diff --git a/packages/core/src/libraries/connector.test.ts b/packages/core/src/libraries/connector.test.ts index bb37982e9..4914630d3 100644 --- a/packages/core/src/libraries/connector.test.ts +++ b/packages/core/src/libraries/connector.test.ts @@ -1,10 +1,7 @@ import type { Connector } from '@logto/schemas'; -import { createMockUtils } from '@logto/shared/esm'; import RequestError from '#src/errors/RequestError/index.js'; - -const { jest } = import.meta; -const { mockEsmWithActual } = createMockUtils(jest); +import { MockQueries } from '#src/test-utils/tenant.js'; const connectors: Connector[] = [ { @@ -17,11 +14,10 @@ const connectors: Connector[] = [ }, ]; -await mockEsmWithActual('#src/queries/connector.js', () => ({ - findAllConnectors: jest.fn(async () => connectors), -})); - -const { getConnectorConfig } = await import('./connector.js'); +const { createConnectorLibrary } = await import('./connector.js'); +const { getConnectorConfig } = createConnectorLibrary( + new MockQueries({ connectors: { findAllConnectors: async () => connectors } }) +); it('getConnectorConfig() should return right config', async () => { const config = await getConnectorConfig('id'); diff --git a/packages/core/src/libraries/connector.ts b/packages/core/src/libraries/connector.ts index 0737967c9..e775cfd74 100644 --- a/packages/core/src/libraries/connector.ts +++ b/packages/core/src/libraries/connector.ts @@ -2,85 +2,102 @@ import type { AllConnector } from '@logto/connector-kit'; import { validateConfig } from '@logto/connector-kit'; import RequestError from '#src/errors/RequestError/index.js'; -import { findAllConnectors } from '#src/queries/connector.js'; +import type Queries from '#src/tenants/Queries.js'; import assertThat from '#src/utils/assert-that.js'; import { defaultConnectorMethods } from '#src/utils/connectors/consts.js'; import { loadConnectorFactories } from '#src/utils/connectors/factories.js'; import { validateConnectorModule, parseMetadata } from '#src/utils/connectors/index.js'; import type { LogtoConnector } from '#src/utils/connectors/types.js'; -export const getConnectorConfig = async (id: string): Promise => { - const connectors = await findAllConnectors(); - const connector = connectors.find((connector) => connector.id === id); +import { defaultQueries } from './shared.js'; - assertThat(connector, new RequestError({ code: 'entity.not_found', id, status: 404 })); +export type ConnectorLibrary = ReturnType; - return connector.config; +export const createConnectorLibrary = (queries: Queries) => { + const { findAllConnectors } = queries.connectors; + + const getConnectorConfig = async (id: string): Promise => { + const connectors = await findAllConnectors(); + const connector = connectors.find((connector) => connector.id === id); + + assertThat(connector, new RequestError({ code: 'entity.not_found', id, status: 404 })); + + return connector.config; + }; + + const getLogtoConnectors = async (): Promise => { + const databaseConnectors = await findAllConnectors(); + + const logtoConnectors = await Promise.all( + databaseConnectors.map(async (databaseConnector) => { + const { id, metadata, connectorId } = databaseConnector; + + const connectorFactories = await loadConnectorFactories(); + const connectorFactory = connectorFactories.find( + ({ metadata }) => metadata.id === connectorId + ); + + if (!connectorFactory) { + return; + } + + const { createConnector, path: packagePath } = connectorFactory; + + try { + const rawConnector = await createConnector({ + getConfig: async () => { + return getConnectorConfig(id); + }, + }); + validateConnectorModule(rawConnector); + const rawMetadata = await parseMetadata(rawConnector.metadata, packagePath); + + const connector: AllConnector = { + ...defaultConnectorMethods, + ...rawConnector, + metadata: { + ...rawMetadata, + ...metadata, + }, + }; + + return { + ...connector, + validateConfig: (config: unknown) => { + validateConfig(config, rawConnector.configGuard); + }, + dbEntry: databaseConnector, + }; + } catch {} + }) + ); + + return logtoConnectors.filter( + (logtoConnector): logtoConnector is LogtoConnector => logtoConnector !== undefined + ); + }; + + const getLogtoConnectorById = async (id: string): Promise => { + const connectors = await getLogtoConnectors(); + const pickedConnector = connectors.find(({ dbEntry }) => dbEntry.id === id); + + if (!pickedConnector) { + throw new RequestError({ + code: 'entity.not_found', + id, + status: 404, + }); + } + + return pickedConnector; + }; + + return { getConnectorConfig, getLogtoConnectors, getLogtoConnectorById }; }; -export const getLogtoConnectors = async (): Promise => { - const databaseConnectors = await findAllConnectors(); +/** @deprecated Don't use. This is for transition only and will be removed soon. */ +export const defaultConnectorLibrary = createConnectorLibrary(defaultQueries); - const logtoConnectors = await Promise.all( - databaseConnectors.map(async (databaseConnector) => { - const { id, metadata, connectorId } = databaseConnector; - - const connectorFactories = await loadConnectorFactories(); - const connectorFactory = connectorFactories.find( - ({ metadata }) => metadata.id === connectorId - ); - - if (!connectorFactory) { - return; - } - - const { createConnector, path: packagePath } = connectorFactory; - - try { - const rawConnector = await createConnector({ - getConfig: async () => { - return getConnectorConfig(id); - }, - }); - validateConnectorModule(rawConnector); - const rawMetadata = await parseMetadata(rawConnector.metadata, packagePath); - - const connector: AllConnector = { - ...defaultConnectorMethods, - ...rawConnector, - metadata: { - ...rawMetadata, - ...metadata, - }, - }; - - return { - ...connector, - validateConfig: (config: unknown) => { - validateConfig(config, rawConnector.configGuard); - }, - dbEntry: databaseConnector, - }; - } catch {} - }) - ); - - return logtoConnectors.filter( - (logtoConnector): logtoConnector is LogtoConnector => logtoConnector !== undefined - ); -}; - -export const getLogtoConnectorById = async (id: string): Promise => { - const connectors = await getLogtoConnectors(); - const pickedConnector = connectors.find(({ dbEntry }) => dbEntry.id === id); - - if (!pickedConnector) { - throw new RequestError({ - code: 'entity.not_found', - id, - status: 404, - }); - } - - return pickedConnector; -}; +/** @deprecated Don't use. This is for transition only and will be removed soon. */ +export const { getConnectorConfig, getLogtoConnectors, getLogtoConnectorById } = + defaultConnectorLibrary; diff --git a/packages/core/src/libraries/sign-in-experience/index.test.ts b/packages/core/src/libraries/sign-in-experience/index.test.ts index e29c12df5..8aaa39be9 100644 --- a/packages/core/src/libraries/sign-in-experience/index.test.ts +++ b/packages/core/src/libraries/sign-in-experience/index.test.ts @@ -2,7 +2,6 @@ import type { LanguageTag } from '@logto/language-kit'; import { builtInLanguages } from '@logto/phrases-ui'; import type { CreateSignInExperience, SignInExperience } from '@logto/schemas'; import { BrandingStyle } from '@logto/schemas'; -import { createMockUtils } from '@logto/shared/esm'; import { socialTarget01, @@ -13,8 +12,9 @@ import { } from '#src/__mocks__/index.js'; import RequestError from '#src/errors/RequestError/index.js'; +import { createConnectorLibrary } from '../connector.js'; + const { jest } = import.meta; -const { mockEsm } = createMockUtils(jest); const allCustomLanguageTags: LanguageTag[] = []; @@ -23,10 +23,6 @@ const customPhrases = { }; const { findAllCustomLanguageTags } = customPhrases; -const { getLogtoConnectors } = mockEsm('#src/libraries/connector.js', () => ({ - getLogtoConnectors: jest.fn(), -})); - const signInExperiences = { findDefaultSignInExperience: jest.fn(), updateDefaultSignInExperience: jest.fn( @@ -43,10 +39,12 @@ const queries = new MockQueries({ customPhrases, signInExperiences, }); +const connectorLibrary = createConnectorLibrary(queries); +const getLogtoConnectors = jest.spyOn(connectorLibrary, 'getLogtoConnectors'); const { validateBranding, createSignInExperienceLibrary } = await import('./index.js'); const { validateLanguageInfo, removeUnavailableSocialConnectorTargets } = - createSignInExperienceLibrary(queries); + createSignInExperienceLibrary(queries, connectorLibrary); beforeEach(() => { jest.clearAllMocks(); diff --git a/packages/core/src/libraries/sign-in-experience/index.ts b/packages/core/src/libraries/sign-in-experience/index.ts index d1cc95ddd..52804ef18 100644 --- a/packages/core/src/libraries/sign-in-experience/index.ts +++ b/packages/core/src/libraries/sign-in-experience/index.ts @@ -12,7 +12,8 @@ import { deduplicate } from '@silverhand/essentials'; import i18next from 'i18next'; import RequestError from '#src/errors/RequestError/index.js'; -import { getLogtoConnectors } from '#src/libraries/connector.js'; +import type { ConnectorLibrary } from '#src/libraries/connector.js'; +import { defaultConnectorLibrary } from '#src/libraries/connector.js'; import type Queries from '#src/tenants/Queries.js'; import assertThat from '#src/utils/assert-that.js'; @@ -29,7 +30,10 @@ export const validateBranding = (branding: Branding) => { assertThat(branding.logoUrl.trim(), 'sign_in_experiences.empty_logo'); }; -export const createSignInExperienceLibrary = (queries: Queries) => { +export const createSignInExperienceLibrary = ( + queries: Queries, + connectorLibrary: ConnectorLibrary +) => { const { customPhrases: { findAllCustomLanguageTags }, signInExperiences: { findDefaultSignInExperience, updateDefaultSignInExperience }, @@ -49,7 +53,7 @@ export const createSignInExperienceLibrary = (queries: Queries) => { }; const removeUnavailableSocialConnectorTargets = async () => { - const connectors = await getLogtoConnectors(); + const connectors = await connectorLibrary.getLogtoConnectors(); const availableSocialConnectorTargets = deduplicate( connectors .filter(({ type }) => type === ConnectorType.Social) @@ -113,4 +117,4 @@ export const { validateLanguageInfo, removeUnavailableSocialConnectorTargets, getSignInExperienceForApplication, -} = createSignInExperienceLibrary(defaultQueries); +} = createSignInExperienceLibrary(defaultQueries, defaultConnectorLibrary); diff --git a/packages/core/src/libraries/user.test.ts b/packages/core/src/libraries/user.test.ts index be9e9293d..943d995a2 100644 --- a/packages/core/src/libraries/user.test.ts +++ b/packages/core/src/libraries/user.test.ts @@ -1,7 +1,7 @@ import { UsersPasswordEncryptionMethod } from '@logto/schemas'; import { createMockPool } from 'slonik'; -import Queries from '#src/tenants/Queries.js'; +import { MockQueries } from '#src/test-utils/tenant.js'; const { jest } = import.meta; @@ -11,9 +11,8 @@ const pool = createMockPool({ const { encryptUserPassword, createUserLibrary } = await import('./user.js'); -const queries = new Queries(pool); - -const hasUserWithId = jest.spyOn(queries.users, 'hasUserWithId'); +const hasUserWithId = jest.fn(); +const queries = new MockQueries({ users: { hasUserWithId } }); describe('generateUserId()', () => { const { generateUserId } = createUserLibrary(queries); diff --git a/packages/core/src/routes/connector.test.ts b/packages/core/src/routes/connector.test.ts index f74c64e64..677f5296d 100644 --- a/packages/core/src/routes/connector.test.ts +++ b/packages/core/src/routes/connector.test.ts @@ -1,6 +1,7 @@ /* eslint-disable max-lines */ import type { EmailConnector, SmsConnector } from '@logto/connector-kit'; import { ConnectorPlatform, VerificationCodeType } from '@logto/connector-kit'; +import type { Connector } from '@logto/schemas'; import { ConnectorType } from '@logto/schemas'; import { pickDefault, createMockUtils } from '@logto/shared/esm'; import { any } from 'zod'; @@ -17,6 +18,8 @@ import { mockLogtoConnector, } from '#src/__mocks__/index.js'; import RequestError from '#src/errors/RequestError/index.js'; +import Queries from '#src/tenants/Queries.js'; +import { MockTenant } from '#src/test-utils/tenant.js'; import assertThat from '#src/utils/assert-that.js'; import { defaultConnectorMethods } from '#src/utils/connectors/consts.js'; import type { LogtoConnector } from '#src/utils/connectors/types.js'; @@ -29,26 +32,22 @@ mockEsm('#src/utils/connectors/platform.js', () => ({ checkSocialConnectorTargetAndPlatformUniqueness: jest.fn(), })); -const { removeUnavailableSocialConnectorTargets } = mockEsm( - '#src/libraries/sign-in-experience/index.js', - () => ({ - removeUnavailableSocialConnectorTargets: jest.fn(), - }) -); +const removeUnavailableSocialConnectorTargets = jest.fn(); +const connectorQueries = { + findConnectorById: jest.fn(), + countConnectorByConnectorId: jest.fn(), + deleteConnectorById: jest.fn(), + deleteConnectorByIds: jest.fn(), + insertConnector: jest.fn(async (body) => body as Connector), +} satisfies Partial; const { findConnectorById, countConnectorByConnectorId, deleteConnectorById, deleteConnectorByIds, insertConnector, -} = await mockEsmWithActual('#src/queries/connector.js', () => ({ - findConnectorById: jest.fn(), - countConnectorByConnectorId: jest.fn(), - deleteConnectorById: jest.fn(), - deleteConnectorByIds: jest.fn(), - insertConnector: jest.fn(async (body: unknown) => body), -})); +} = connectorQueries; // eslint-disable-next-line @typescript-eslint/ban-types const getLogtoConnectors = jest.fn, []>(); @@ -57,27 +56,35 @@ const { loadConnectorFactories } = mockEsm('#src/utils/connectors/factories.js', loadConnectorFactories: jest.fn(), })); -mockEsm('#src/libraries/connector.js', () => ({ - getLogtoConnectors, - getLogtoConnectorById: async (connectorId: string) => { - const connectors = await getLogtoConnectors(); - const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId); - assertThat( - connector, - new RequestError({ - code: 'entity.not_found', - connectorId, - status: 404, - }) - ); +const tenantContext = new MockTenant( + undefined, + { connectors: connectorQueries }, + { + signInExperiences: { removeUnavailableSocialConnectorTargets }, + connectors: { + getLogtoConnectors, + getLogtoConnectorById: async (connectorId: string) => { + const connectors = await getLogtoConnectors(); + const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId); + assertThat( + connector, + new RequestError({ + code: 'entity.not_found', + connectorId, + status: 404, + }) + ); + + return connector; + }, + }, + } +); - return connector; - }, -})); const connectorRoutes = await pickDefault(import('./connector.js')); describe('connector route', () => { - const connectorRequest = createRequester({ authedRoutes: connectorRoutes }); + const connectorRequest = createRequester({ authedRoutes: connectorRoutes, tenantContext }); describe('GET /connectors', () => { afterEach(() => { diff --git a/packages/core/src/routes/connector.ts b/packages/core/src/routes/connector.ts index 3f690a3ca..4ad949ca8 100644 --- a/packages/core/src/routes/connector.ts +++ b/packages/core/src/routes/connector.ts @@ -6,17 +6,7 @@ import cleanDeep from 'clean-deep'; import { object, string } from 'zod'; import RequestError from '#src/errors/RequestError/index.js'; -import { getLogtoConnectorById, getLogtoConnectors } from '#src/libraries/connector.js'; -import { removeUnavailableSocialConnectorTargets } from '#src/libraries/sign-in-experience/index.js'; import koaGuard from '#src/middleware/koa-guard.js'; -import { - findConnectorById, - countConnectorByConnectorId, - deleteConnectorById, - deleteConnectorByIds, - insertConnector, - updateConnector, -} from '#src/queries/connector.js'; import assertThat from '#src/utils/assert-that.js'; import { loadConnectorFactories } from '#src/utils/connectors/factories.js'; import { checkSocialConnectorTargetAndPlatformUniqueness } from '#src/utils/connectors/platform.js'; @@ -36,7 +26,22 @@ const transpileLogtoConnector = ({ const generateConnectorId = buildIdGenerator(12); -export default function connectorRoutes(...[router]: RouterInitArgs) { +export default function connectorRoutes( + ...[router, { queries, libraries }]: RouterInitArgs +) { + const { + findConnectorById, + countConnectorByConnectorId, + deleteConnectorById, + deleteConnectorByIds, + insertConnector, + updateConnector, + } = queries.connectors; + const { + connectors: { getLogtoConnectorById, getLogtoConnectors }, + signInExperiences: { removeUnavailableSocialConnectorTargets }, + } = libraries; + router.get( '/connectors', koaGuard({ diff --git a/packages/core/src/routes/connector.update.test.ts b/packages/core/src/routes/connector.update.test.ts index 65b5ae612..c87c1b375 100644 --- a/packages/core/src/routes/connector.update.test.ts +++ b/packages/core/src/routes/connector.update.test.ts @@ -1,6 +1,6 @@ import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit'; import { ConnectorType } from '@logto/schemas'; -import { pickDefault, createMockUtils } from '@logto/shared/esm'; +import { pickDefault } from '@logto/shared/esm'; import { mockMetadata, @@ -9,53 +9,56 @@ import { mockLogtoConnector, } from '#src/__mocks__/index.js'; import RequestError from '#src/errors/RequestError/index.js'; +import { MockTenant } from '#src/test-utils/tenant.js'; import assertThat from '#src/utils/assert-that.js'; import type { LogtoConnector } from '#src/utils/connectors/types.js'; import { createRequester } from '#src/utils/test-utils.js'; const { jest } = import.meta; -const { mockEsm, mockEsmWithActual } = createMockUtils(jest); -const getLogtoConnectors = jest.fn() as jest.MockedFunction<() => Promise>; -const getLogtoConnectorById = jest.fn(async (connectorId: string) => { - const connectors = await getLogtoConnectors(); - const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId); +const getLogtoConnectors: jest.MockedFunction<() => Promise> = jest.fn(); +const getLogtoConnectorById: jest.MockedFunction<(connectorId: string) => Promise> = + jest.fn(async (connectorId: string) => { + const connectors = await getLogtoConnectors(); + const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId); - assertThat( - connector, - new RequestError({ - code: 'entity.not_found', - connectorId, - status: 404, - }) - ); + assertThat( + connector, + new RequestError({ + code: 'entity.not_found', + connectorId, + status: 404, + }) + ); - return { - ...connector, - sendMessage: sendMessagePlaceHolder, - }; -}) as jest.MockedFunction<(connectorId: string) => Promise>; + return { + ...connector, + sendMessage: sendMessagePlaceHolder, + }; + }); const sendMessagePlaceHolder = jest.fn(); +const updateConnector = jest.fn(); -const { updateConnector } = await mockEsmWithActual('#src/queries/connector.js', () => ({ - updateConnector: jest.fn(), -})); - -await mockEsmWithActual('#src/libraries/connector.js', () => ({ - getLogtoConnectors, - getLogtoConnectorById, -})); - -mockEsm('#src/libraries/sign-in-experience.js', () => ({ - // eslint-disable-next-line @typescript-eslint/no-empty-function - removeUnavailableSocialConnectorTargets: async () => {}, -})); +const tenantContext = new MockTenant( + undefined, + { connectors: { updateConnector } }, + { + connectors: { + getLogtoConnectors, + getLogtoConnectorById, + }, + signInExperiences: { + // eslint-disable-next-line @typescript-eslint/no-empty-function + removeUnavailableSocialConnectorTargets: async () => {}, + }, + } +); const connectorRoutes = await pickDefault(import('./connector.js')); describe('connector PATCH routes', () => { - const connectorRequest = createRequester({ authedRoutes: connectorRoutes }); + const connectorRequest = createRequester({ authedRoutes: connectorRoutes, tenantContext }); describe('PATCH /connectors/:id', () => { afterEach(() => { diff --git a/packages/core/src/routes/session/social.test.ts b/packages/core/src/routes/session/social.test.ts index 362a654ae..7a6cf5c73 100644 --- a/packages/core/src/routes/session/social.test.ts +++ b/packages/core/src/routes/session/social.test.ts @@ -3,7 +3,7 @@ import type { SocialUserInfo } from '@logto/connector-kit'; import type { User } from '@logto/schemas'; import Provider from 'oidc-provider'; -import { mockLogtoConnectorList, mockSignInExperience, mockUser } from '#src/__mocks__/index.js'; +import { mockSignInExperience, mockUser } from '#src/__mocks__/index.js'; import RequestError from '#src/errors/RequestError/index.js'; import { getLogtoConnectorById } from '#src/libraries/connector.js'; import { createRequester } from '#src/utils/test-utils.js'; @@ -91,7 +91,6 @@ const getLogtoConnectorByIdHelper = jest.fn(async (connectorId: string) => { }); jest.mock('#src/libraries/connector.js', () => ({ - getLogtoConnectors: jest.fn(async () => mockLogtoConnectorList), getLogtoConnectorById: jest.fn(async (connectorId: string) => { const connector = await getLogtoConnectorByIdHelper(connectorId); diff --git a/packages/core/src/routes/sign-in-experience/guard.branding.test.ts b/packages/core/src/routes/sign-in-experience/guard.branding.test.ts index 2e006f136..5eab88136 100644 --- a/packages/core/src/routes/sign-in-experience/guard.branding.test.ts +++ b/packages/core/src/routes/sign-in-experience/guard.branding.test.ts @@ -1,17 +1,11 @@ import type { CreateSignInExperience, SignInExperience } from '@logto/schemas'; import { BrandingStyle } from '@logto/schemas'; -import { pickDefault, createMockUtils } from '@logto/shared/esm'; +import { pickDefault } from '@logto/shared/esm'; import { mockBranding, mockSignInExperience } from '#src/__mocks__/index.js'; import { MockTenant } from '#src/test-utils/tenant.js'; import { createRequester } from '#src/utils/test-utils.js'; -const { mockEsm } = createMockUtils(import.meta.jest); - -mockEsm('#src/libraries/connector.js', () => ({ - getLogtoConnectors: async () => [], -})); - const tenantContext = new MockTenant(undefined, { signInExperiences: { updateDefaultSignInExperience: async ( diff --git a/packages/core/src/routes/sign-in-experience/guard.color.test.ts b/packages/core/src/routes/sign-in-experience/guard.color.test.ts index 658662121..374dbd49b 100644 --- a/packages/core/src/routes/sign-in-experience/guard.color.test.ts +++ b/packages/core/src/routes/sign-in-experience/guard.color.test.ts @@ -7,10 +7,6 @@ import { createRequester } from '#src/utils/test-utils.js'; const { mockEsm } = createMockUtils(import.meta.jest); -mockEsm('#src/libraries/connector.js', () => ({ - getLogtoConnectors: async () => [], -})); - const signInExperiencesRoutes = await pickDefault(import('./index.js')); const signInExperienceRequester = createRequester({ authedRoutes: signInExperiencesRoutes, diff --git a/packages/core/src/routes/sign-in-experience/guard.test.ts b/packages/core/src/routes/sign-in-experience/guard.test.ts index 62e58ad4d..56e4ffc3b 100644 --- a/packages/core/src/routes/sign-in-experience/guard.test.ts +++ b/packages/core/src/routes/sign-in-experience/guard.test.ts @@ -1,29 +1,10 @@ import type { CreateSignInExperience, SignInExperience } from '@logto/schemas'; -import { pickDefault, createMockUtils } from '@logto/shared/esm'; +import { pickDefault } from '@logto/shared/esm'; -import { - mockAliyunDmConnector, - mockAliyunSmsConnector, - mockFacebookConnector, - mockGithubConnector, - mockGoogleConnector, - mockLanguageInfo, - mockSignInExperience, -} from '#src/__mocks__/index.js'; +import { mockLanguageInfo, mockSignInExperience } from '#src/__mocks__/index.js'; import { MockTenant } from '#src/test-utils/tenant.js'; const { jest } = import.meta; -const { mockEsm } = createMockUtils(jest); - -mockEsm('#src/libraries/connector.js', () => ({ - getLogtoConnectors: jest.fn(async () => [ - mockAliyunDmConnector, - mockAliyunSmsConnector, - mockFacebookConnector, - mockGithubConnector, - mockGoogleConnector, - ]), -})); const validateLanguageInfo = jest.fn(); diff --git a/packages/core/src/routes/sign-in-experience/index.test.ts b/packages/core/src/routes/sign-in-experience/index.test.ts index c7fe0875c..2c6b02eaf 100644 --- a/packages/core/src/routes/sign-in-experience/index.test.ts +++ b/packages/core/src/routes/sign-in-experience/index.test.ts @@ -29,10 +29,6 @@ const logtoConnectors = [ mockAliyunSmsConnector, ]; -await mockEsmWithActual('#src/libraries/connector.js', () => ({ - getLogtoConnectors: async () => logtoConnectors, -})); - const { validateBranding, validateSignIn, validateSignUp } = await mockEsmWithActual( '#src/libraries/sign-in-experience/index.js', () => ({ @@ -58,7 +54,10 @@ const validateLanguageInfo = jest.fn(); const tenantContext = new MockTenant( undefined, { signInExperiences, customPhrases: { findAllCustomLanguageTags: async () => [] } }, - { signInExperiences: { validateLanguageInfo } } + { + signInExperiences: { validateLanguageInfo }, + connectors: { getLogtoConnectors: async () => logtoConnectors }, + } ); const signInExperiencesRoutes = await pickDefault(import('./index.js')); diff --git a/packages/core/src/routes/sign-in-experience/index.ts b/packages/core/src/routes/sign-in-experience/index.ts index 217f33032..840639e30 100644 --- a/packages/core/src/routes/sign-in-experience/index.ts +++ b/packages/core/src/routes/sign-in-experience/index.ts @@ -1,7 +1,6 @@ import { ConnectorType, SignInExperiences } from '@logto/schemas'; import { literal, object, string } from 'zod'; -import { getLogtoConnectors } from '#src/libraries/connector.js'; import { validateBranding, validateSignUp, @@ -15,7 +14,10 @@ export default function signInExperiencesRoutes( ...[router, { queries, libraries }]: RouterInitArgs ) { const { findDefaultSignInExperience, updateDefaultSignInExperience } = queries.signInExperiences; - const { validateLanguageInfo } = libraries.signInExperiences; + const { + signInExperiences: { validateLanguageInfo }, + connectors: { getLogtoConnectors }, + } = libraries; /** * As we only support single signInExperience settings for V1 diff --git a/packages/core/src/routes/well-known.test.ts b/packages/core/src/routes/well-known.test.ts index 2069a8882..525c4570d 100644 --- a/packages/core/src/routes/well-known.test.ts +++ b/packages/core/src/routes/well-known.test.ts @@ -17,7 +17,7 @@ import { } from '#src/__mocks__/index.js'; const { jest } = import.meta; -const { mockEsm, mockEsmWithActual } = createMockUtils(jest); +const { mockEsmWithActual } = createMockUtils(jest); await mockEsmWithActual('i18next', () => ({ default: { @@ -31,18 +31,6 @@ const sieQueries = { }; const { findDefaultSignInExperience } = sieQueries; -mockEsm('#src/libraries/connector.js', () => ({ - getLogtoConnectors: jest.fn(async () => [ - mockAliyunDmConnector, - mockAliyunSmsConnector, - mockFacebookConnector, - mockGithubConnector, - mockGoogleConnector, - mockWechatConnector, - mockWechatNativeConnector, - ]), -})); - const wellKnownRoutes = await pickDefault(import('#src/routes/well-known.js')); const { createMockProvider } = await import('#src/test-utils/oidc-provider.js'); const { MockTenant } = await import('#src/test-utils/tenant.js'); @@ -56,10 +44,26 @@ describe('GET /.well-known/sign-in-exp', () => { const provider = createMockProvider(); const sessionRequest = createRequester({ anonymousRoutes: wellKnownRoutes, - tenantContext: new MockTenant(provider, { - signInExperiences: sieQueries, - users: { hasActiveUsers: jest.fn().mockResolvedValue(true) }, - }), + tenantContext: new MockTenant( + provider, + { + signInExperiences: sieQueries, + users: { hasActiveUsers: jest.fn().mockResolvedValue(true) }, + }, + { + connectors: { + getLogtoConnectors: jest.fn(async () => [ + mockAliyunDmConnector, + mockAliyunSmsConnector, + mockFacebookConnector, + mockGithubConnector, + mockGoogleConnector, + mockWechatConnector, + mockWechatNativeConnector, + ]), + }, + } + ), middlewares: [ async (ctx, next) => { ctx.addLogContext = jest.fn(); diff --git a/packages/core/src/routes/well-known.ts b/packages/core/src/routes/well-known.ts index bf68becdf..3266580ec 100644 --- a/packages/core/src/routes/well-known.ts +++ b/packages/core/src/routes/well-known.ts @@ -3,7 +3,6 @@ import { ConnectorType } from '@logto/connector-kit'; import { adminConsoleApplicationId } from '@logto/schemas'; import etag from 'etag'; -import { getLogtoConnectors } from '#src/libraries/connector.js'; import { getApplicationIdFromInteraction } from '#src/libraries/session.js'; import type { AnonymousRouter, RouterInitArgs } from './types.js'; @@ -11,7 +10,10 @@ import type { AnonymousRouter, RouterInitArgs } from './types.js'; export default function wellKnownRoutes( ...[router, { provider, libraries }]: RouterInitArgs ) { - const { getSignInExperienceForApplication } = libraries.signInExperiences; + const { + signInExperiences: { getSignInExperienceForApplication }, + connectors: { getLogtoConnectors }, + } = libraries; router.get( '/.well-known/sign-in-exp', diff --git a/packages/core/src/tenants/Libraries.ts b/packages/core/src/tenants/Libraries.ts index d6d056b1c..4e8c9ee40 100644 --- a/packages/core/src/tenants/Libraries.ts +++ b/packages/core/src/tenants/Libraries.ts @@ -1,11 +1,13 @@ +import { createConnectorLibrary } from '#src/libraries/connector.js'; import { createSignInExperienceLibrary } from '#src/libraries/sign-in-experience/index.js'; import { createUserLibrary } from '#src/libraries/user.js'; import type Queries from './Queries.js'; export default class Libraries { + connectors = createConnectorLibrary(this.queries); users = createUserLibrary(this.queries); - signInExperiences = createSignInExperienceLibrary(this.queries); + signInExperiences = createSignInExperienceLibrary(this.queries, this.connectors); constructor(public readonly queries: Queries) {} } diff --git a/packages/core/src/test-utils/tenant.ts b/packages/core/src/test-utils/tenant.ts index a895edf7e..72c421928 100644 --- a/packages/core/src/test-utils/tenant.ts +++ b/packages/core/src/test-utils/tenant.ts @@ -6,15 +6,6 @@ import type TenantContext from '#src/tenants/TenantContext.js'; import { createMockProvider } from './oidc-provider.js'; -export const createQueriesWithMockPool = () => - new Queries( - createMockPool({ - query: async (sql, values) => { - return createMockQueryResult([]); - }, - }) - ); - export class MockQueries extends Queries { constructor(queriesOverride?: Partial2) { super(