Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions packages/testing/src/__tests__/kyc.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
registerAndMaterializePlayer,
asAdmin,
seedMinimal,
type BootTestAppConfig,
type TestDb,
type TestApp,
} from '../index.js';
Expand All @@ -30,7 +31,10 @@ import {
* test with a mocked DB cannot: real routing, real authz, real DB state, and the
* real (fire-and-forget) event -> audit pipeline.
*
* Two app instances share one database:
* Two app instances, each on its own database: an app's outbox relay publishes every
* pending event in its database into its own broker, so on a shared database an event
* written through `appGated` could be handled only by `appDefault`, which has no re-KYC
* thresholds.
* - `appDefault` boots the stock stack (MockKycAdapter, no PLATFORM_CONFIG bound - the
* withdrawal gate is therefore off) to prove the default submit/admin-read path.
* - `appGated` adds a test-only overlay (fixtures/test-kyc-config-plugin.ts) binding
Expand All @@ -44,7 +48,8 @@ import {

const KYC_WEBHOOK_SECRET = 'e2e-kyc-webhook-secret';

let db: TestDb;
let dbDefault: TestDb;
let dbGated: TestDb;
let appDefault: TestApp;
let appGated: TestApp;

Expand Down Expand Up @@ -90,35 +95,42 @@ async function seedLegacyVerifiedStatus(container: Container<CoreTokenCatalog>,
.where(eq(player.userId, userId));
}

async function bootSeededApp(
plugins: BootTestAppConfig['plugins'],
databaseUrl: string,
): Promise<TestApp> {
const app = await bootTestApp({ plugins, databaseUrl });
await seedMinimal(app.container, { playerCount: 0 });
return app;
}

beforeAll(async () => {
process.env['KYC_WEBHOOK_SECRET'] = KYC_WEBHOOK_SECRET;
process.env['BETTER_AUTH_SECRET'] ??= 'e2e-test-better-auth-secret-please-change-000000';
process.env['AUTH_SECRET'] ??= process.env['BETTER_AUTH_SECRET'];
process.env['WITHDRAWAL_PIN_HMAC_SECRET'] ??= 'e2e-test-withdrawal-pin-hmac-secret-000000';
process.env['NODE_ENV'] ??= 'test';

db = await setupTestDb();
const basePlugins = await loadExtensions();

appDefault = await bootTestApp({ plugins: basePlugins, databaseUrl: db.url });
dbDefault = await setupTestDb();
appDefault = await bootSeededApp(basePlugins, dbDefault.url);

const fixturePath = fileURLToPath(
new URL('./fixtures/test-kyc-config-plugin.ts', import.meta.url),
);
appGated = await bootTestApp({
plugins: [...basePlugins, { id: 'test-kyc-config', path: fixturePath }],
databaseUrl: db.url,
});

// Both apps share one database - seed the admin fixture once via appDefault's
// container; appGated's asAdmin() logs into the same underlying `user` row.
await seedMinimal(appDefault.container, { playerCount: 0 });
dbGated = await setupTestDb();
appGated = await bootSeededApp(
[...basePlugins, { id: 'test-kyc-config', path: fixturePath }],
dbGated.url,
);
}, 60_000);

afterAll(async () => {
await appDefault?.close();
await appGated?.close();
await db?.dispose();
await dbDefault?.dispose();
await dbGated?.dispose();
});

describe('KYC submit (default MockKycAdapter) + admin read + authz', () => {
Expand Down
8 changes: 6 additions & 2 deletions packages/testing/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ export type BootTestAppConfig = Pick<CreateAppConfig, 'plugins' | 'igaming'> & {
* BullMQ, Redis cache, Redis rate limiter and Redis Pub/Sub - so event fan-out, job
* retries, throttling and realtime push are exercised for real rather than through
* an in-process stand-in. Each booted app claims its own Redis logical database, so
* several apps in one test file cannot compete for each other's events, jobs, cache
* entries or channels.
* several apps in one test file cannot compete for each other's jobs, cache entries or
* channels. Outbox events (`emitInTransaction`) are the exception when two apps share a
* database: every app's relay publishes the pending events of its database into its own
* broker, so such an event reaches the handlers of whichever app claimed it first, not
* of the app that wrote it. Boot each app on its own `setupTestDb()` when their handlers
* behave differently.
*
* The broker reads from `startId: '0'` here, unlike production's `$`: a test acts
* within milliseconds of boot, and a group created lazily at `$` would silently drop
Expand Down