From 6e5b48bdcbdb6e69b4df020d56bf5d367e7d5ff8 Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Fri, 28 Apr 2023 15:42:43 +0800 Subject: [PATCH] chore(schemas,test,core): add IT to ensure mock connectors are installed (#3762) --- packages/core/src/routes/connector/index.ts | 29 +++++++++++----- .../integration-tests/src/api/connector.ts | 13 +++++++- .../src/tests/api/connector.test.ts | 33 ++++++++++++++++--- packages/schemas/src/types/connector.ts | 17 ++++++---- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/packages/core/src/routes/connector/index.ts b/packages/core/src/routes/connector/index.ts index 6d73fd96c..0ec6b65c1 100644 --- a/packages/core/src/routes/connector/index.ts +++ b/packages/core/src/routes/connector/index.ts @@ -1,6 +1,6 @@ import { buildRawConnector } from '@logto/cli/lib/connector/index.js'; import { demoConnectorIds, validateConfig } from '@logto/connector-kit'; -import { Connectors, ConnectorType } from '@logto/schemas'; +import { connectorFactoryResponseGuard, Connectors, ConnectorType } from '@logto/schemas'; import { buildIdGenerator } from '@logto/shared'; import cleanDeep from 'clean-deep'; import { string, object } from 'zod'; @@ -200,18 +200,29 @@ export default function connectorRoutes( } ); - router.get('/connector-factories', async (ctx, next) => { - const connectorFactories = await loadConnectorFactories(); - ctx.body = connectorFactories.map((connectorFactory) => - transpileConnectorFactory(connectorFactory) - ); + router.get( + '/connector-factories', + koaGuard({ + response: connectorFactoryResponseGuard.array(), + status: [200], + }), + async (ctx, next) => { + const connectorFactories = await loadConnectorFactories(); + ctx.body = connectorFactories.map((connectorFactory) => + transpileConnectorFactory(connectorFactory) + ); - return next(); - }); + return next(); + } + ); router.get( '/connector-factories/:id', - koaGuard({ params: object({ id: string().min(1) }) }), + koaGuard({ + params: object({ id: string().min(1) }), + response: connectorFactoryResponseGuard, + status: [200], + }), async (ctx, next) => { const { params: { id }, diff --git a/packages/integration-tests/src/api/connector.ts b/packages/integration-tests/src/api/connector.ts index 7ce8eea86..b0362af1d 100644 --- a/packages/integration-tests/src/api/connector.ts +++ b/packages/integration-tests/src/api/connector.ts @@ -1,4 +1,9 @@ -import type { Connector, ConnectorResponse, CreateConnector } from '@logto/schemas'; +import type { + Connector, + ConnectorFactoryResponse, + ConnectorResponse, + CreateConnector, +} from '@logto/schemas'; import { authedAdminApi } from './api.js'; @@ -8,6 +13,12 @@ export const listConnectors = async () => export const getConnector = async (connectorId: string) => authedAdminApi.get(`connectors/${connectorId}`).json(); +export const listConnectorFactories = async () => + authedAdminApi.get('connector-factories').json(); + +export const getConnectorFactory = async (connectorId: string) => + authedAdminApi.get(`connector-factories/${connectorId}`).json(); + // FIXME @Darcy: correct use of `id` and `connectorId`. export const postConnector = async ( payload: Pick diff --git a/packages/integration-tests/src/tests/api/connector.test.ts b/packages/integration-tests/src/tests/api/connector.test.ts index eabd71f5a..646ac105c 100644 --- a/packages/integration-tests/src/tests/api/connector.test.ts +++ b/packages/integration-tests/src/tests/api/connector.test.ts @@ -18,16 +18,43 @@ import { sendEmailTestMessage, sendSmsTestMessage, updateConnectorConfig, + listConnectorFactories, + getConnectorFactory, } from '#src/api/connector.js'; const connectorIdMap = new Map(); +const mockConnectorSetups = [ + { connectorId: mockSmsConnectorId, config: mockSmsConnectorConfig }, + { connectorId: mockEmailConnectorId, config: mockEmailConnectorConfig }, + { connectorId: mockSocialConnectorId, config: mockSocialConnectorConfig }, +]; + /* * We'd better only use mock connectors in integration tests. * Since we will refactor connectors soon, keep using some real connectors * for testing updating configs and enabling/disabling for now. */ test('connector set-up flow', async () => { + /** + * Check whether mock connector factories are properly installed using + * both connector factory APIs: + * 1. GET /connector-factories (listConnectorFactories()). + * 2. GET /connector-factories/:connectorId (getConnectorFactory()). + */ + const connectorFactories = await listConnectorFactories(); + await Promise.all( + mockConnectorSetups.map(async ({ connectorId }) => { + expect(connectorFactories.find(({ id }) => id === connectorId)).toBeDefined(); + + const connectorFactory = await getConnectorFactory(connectorId); + expect(connectorFactory).toBeDefined(); + }) + ); + + /** + * Clean up `connector` table + */ const connectors = await listConnectors(); await Promise.all( connectors.map(async ({ id }) => { @@ -40,11 +67,7 @@ test('connector set-up flow', async () => { * Set up social/SMS/email connectors */ await Promise.all( - [ - { connectorId: mockSmsConnectorId, config: mockSmsConnectorConfig }, - { connectorId: mockEmailConnectorId, config: mockEmailConnectorConfig }, - { connectorId: mockSocialConnectorId, config: mockSocialConnectorConfig }, - ].map(async ({ connectorId, config }) => { + mockConnectorSetups.map(async ({ connectorId, config }) => { // @darcy FIXME: should call post method directly const { id } = await postConnector({ connectorId }); connectorIdMap.set(connectorId, id); diff --git a/packages/schemas/src/types/connector.ts b/packages/schemas/src/types/connector.ts index 56665547d..aa4b6624d 100644 --- a/packages/schemas/src/types/connector.ts +++ b/packages/schemas/src/types/connector.ts @@ -1,4 +1,6 @@ -import type { BaseConnector, ConnectorMetadata, ConnectorType } from '@logto/connector-kit'; +import type { BaseConnector, ConnectorMetadata } from '@logto/connector-kit'; +import { ConnectorType, connectorMetadataGuard } from '@logto/connector-kit'; +import { z } from 'zod'; import type { Connector } from '../db-entries/index.js'; @@ -12,8 +14,11 @@ export type ConnectorResponse = Pick< Omit, 'configGuard' | 'metadata'> & ConnectorMetadata & { isDemo?: boolean }; -export type ConnectorFactoryResponse = Omit< - BaseConnector, - 'configGuard' | 'metadata' -> & - ConnectorMetadata & { isDemo?: boolean }; +export const connectorFactoryResponseGuard = z + .object({ + type: z.nativeEnum(ConnectorType), // Omit, 'configGuard' | 'metadata'> + isDemo: z.boolean().optional(), + }) + .merge(connectorMetadataGuard); + +export type ConnectorFactoryResponse = z.infer;