import { type Sentinel } from '@logto/schemas'; import { TtlCache } from '@logto/shared'; import { createMockPool, createMockQueryResult } from 'slonik'; import { WellKnownCache } from '#src/caches/well-known.js'; import type { CloudConnectionLibrary } from '#src/libraries/cloud-connection.js'; import { createCloudConnectionLibrary } from '#src/libraries/cloud-connection.js'; import type { ConnectorLibrary } from '#src/libraries/connector.js'; import { createConnectorLibrary } from '#src/libraries/connector.js'; import { createLogtoConfigLibrary } from '#src/libraries/logto-config.js'; import { type LogtoConfigLibrary } from '#src/libraries/logto-config.js'; import Libraries from '#src/tenants/Libraries.js'; import Queries from '#src/tenants/Queries.js'; import type TenantContext from '#src/tenants/TenantContext.js'; import { mockEnvSet } from './env-set.js'; import type { GrantMock } from './oidc-provider.js'; import { createMockProvider } from './oidc-provider.js'; import { MockSentinel } from './sentinel.js'; export class MockWellKnownCache extends WellKnownCache { constructor(public ttlCache = new TtlCache(60_000)) { super('mock_id', ttlCache); } } export class MockQueries extends Queries { constructor(queriesOverride?: Partial2) { super( createMockPool({ query: async (sql, values) => { return createMockQueryResult([]); }, }), new MockWellKnownCache() ); if (!queriesOverride) { return; } const overrideKey = (key: Key) => { this[key] = { ...this[key], ...queriesOverride[key] }; }; // eslint-disable-next-line no-restricted-syntax for (const key of Object.keys(queriesOverride) as Array) { overrideKey(key); } } } // eslint-disable-next-line @typescript-eslint/ban-types export type DeepPartial = T extends object ? { [P in keyof T]?: DeepPartial; } : T; export type Partial2 = { [key in keyof T]?: Partial }; export class MockTenant implements TenantContext { public id = 'mock_id'; public envSet = mockEnvSet; public queries: Queries; public logtoConfigs: LogtoConfigLibrary; public cloudConnection: CloudConnectionLibrary; public connectors: ConnectorLibrary; public libraries: Libraries; public sentinel: Sentinel; constructor( public provider = createMockProvider(), queriesOverride?: Partial2, connectorsOverride?: Partial, librariesOverride?: Partial2 ) { this.queries = new MockQueries(queriesOverride); this.logtoConfigs = createLogtoConfigLibrary(this.queries); this.cloudConnection = createCloudConnectionLibrary(this.logtoConfigs); this.connectors = { ...createConnectorLibrary(this.queries, this.cloudConnection), ...connectorsOverride, }; this.libraries = new Libraries(this.id, this.queries, this.connectors, this.cloudConnection); this.setPartial('libraries', librariesOverride); this.sentinel = new MockSentinel(); } setPartialKey( type: Type, key: Key, value: Partial ) { this[type][key] = { ...this[type][key], ...value }; } setPartial(type: Type, value?: Partial2) { if (!value) { return; } // eslint-disable-next-line no-restricted-syntax for (const key of Object.keys(value) as Array) { this.setPartialKey(type, key, { ...this[type][key], ...value[key] }); } } } export const createMockTenantWithInteraction = ( interactionDetails?: jest.Mock, Grant?: typeof GrantMock ) => new MockTenant(createMockProvider(interactionDetails, Grant));