@geekmidas/constructs 10.0.0-alpha.32 → 10.0.0-alpha.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -6
- package/dist/adaptors/testing.cjs +103 -25
- package/dist/adaptors/testing.cjs.map +1 -1
- package/dist/adaptors/testing.d.cts +91 -18
- package/dist/adaptors/testing.d.cts.map +1 -1
- package/dist/adaptors/testing.d.mts +91 -18
- package/dist/adaptors/testing.d.mts.map +1 -1
- package/dist/adaptors/testing.mjs +101 -26
- package/dist/adaptors/testing.mjs.map +1 -1
- package/package.json +31 -31
|
@@ -237,7 +237,9 @@ export declare class NoTestManifest extends Error {
|
|
|
237
237
|
}
|
|
238
238
|
//#endregion
|
|
239
239
|
//#region src/testing/featureTest.d.ts
|
|
240
|
-
|
|
240
|
+
/** How each database's test factory is built, keyed by its service name. */
|
|
241
|
+
type FactoryBuilders = Record<string, (db: Kysely<any>) => unknown>;
|
|
242
|
+
interface FeatureTestOptions<TBrowser extends Browser, TFactories extends FactoryBuilders = {}> {
|
|
241
243
|
/**
|
|
242
244
|
* What the app declares and the environment its test stage resolved.
|
|
243
245
|
* Defaults to the manifest `gkm test` names in `GKM_TEST_MANIFEST`.
|
|
@@ -253,16 +255,50 @@ interface FeatureTestOptions<TBrowser extends Browser> {
|
|
|
253
255
|
/** The browser each test gets — the generated one, with the app's clients. */
|
|
254
256
|
browser?: new () => TBrowser;
|
|
255
257
|
/**
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
+
* Each database's test factory — `createFactory` from
|
|
259
|
+
* `test/factories/<construct>.ts`, which the generated harness imports —
|
|
260
|
+
* keyed by the database's service name. Each is called once per test with
|
|
261
|
+
* that database's transaction, so what a test inserts through it is rolled
|
|
262
|
+
* back with everything else, and seen by the endpoints it calls.
|
|
258
263
|
*/
|
|
259
|
-
|
|
264
|
+
factories?: TFactories;
|
|
260
265
|
}
|
|
261
|
-
|
|
266
|
+
/** Each database's schema, keyed by its service name. */
|
|
267
|
+
type DatabaseSchemas = Record<string, unknown>;
|
|
268
|
+
/**
|
|
269
|
+
* The app's databases for this test, by service name — `db.get('database')`.
|
|
270
|
+
*
|
|
271
|
+
* Each is this test's transaction on that database: opened by whatever reaches
|
|
272
|
+
* it first — the test, a factory, an endpoint — and the same one for all of
|
|
273
|
+
* them, rolled back after the test.
|
|
274
|
+
*/
|
|
275
|
+
interface TestDatabases<TDatabases extends DatabaseSchemas> {
|
|
276
|
+
get<K extends keyof TDatabases & string>(name: K): Promise<Kysely<TDatabases[K]>>;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Each of the app's databases' test factory, by service name —
|
|
280
|
+
* `await factories.get('database')`. Built on first use, on that database's
|
|
281
|
+
* transaction for this test — the one `db.get` returns — and the same factory
|
|
282
|
+
* for the rest of the test.
|
|
283
|
+
*/
|
|
284
|
+
interface TestFactories<TFactories extends FactoryBuilders> {
|
|
285
|
+
get<K extends keyof TFactories & string>(name: K): Promise<ReturnType<TFactories[K]>>;
|
|
286
|
+
}
|
|
287
|
+
interface FeatureContext<TBrowser extends Browser, TDatabases extends DatabaseSchemas = {}, TFactories extends FactoryBuilders = {}> {
|
|
262
288
|
/** This test's browser, already the global `fetch`. */
|
|
263
289
|
browser: TBrowser;
|
|
264
|
-
/**
|
|
265
|
-
|
|
290
|
+
/**
|
|
291
|
+
* The app's own databases — not a tenant an auth server owns, not a
|
|
292
|
+
* reader — by service name: `await db.get('database')`. The same
|
|
293
|
+
* transaction the test's endpoints and factories use.
|
|
294
|
+
*/
|
|
295
|
+
db: TestDatabases<TDatabases>;
|
|
296
|
+
/**
|
|
297
|
+
* Each of the app's databases' test factory, by service name —
|
|
298
|
+
* `await factories.get('database')` — on the same transaction `db.get`
|
|
299
|
+
* returns.
|
|
300
|
+
*/
|
|
301
|
+
factories: TestFactories<TFactories>;
|
|
266
302
|
/** The mail sent to an address during this test, read from Mailpit. */
|
|
267
303
|
mailbox: (address: string) => Mailbox;
|
|
268
304
|
/**
|
|
@@ -291,13 +327,44 @@ interface PublishedMessage {
|
|
|
291
327
|
type: string;
|
|
292
328
|
payload: unknown;
|
|
293
329
|
}
|
|
294
|
-
type FeatureFn<TBrowser extends Browser,
|
|
295
|
-
interface FeatureIt<TBrowser extends Browser,
|
|
296
|
-
(name: string, fn: FeatureFn<TBrowser,
|
|
297
|
-
only(name: string, fn: FeatureFn<TBrowser,
|
|
298
|
-
skip(name: string, fn: FeatureFn<TBrowser,
|
|
330
|
+
type FeatureFn<TBrowser extends Browser, TDatabases extends DatabaseSchemas, TFactories extends FactoryBuilders> = (context: FeatureContext<TBrowser, TDatabases, TFactories>) => unknown;
|
|
331
|
+
interface FeatureIt<TBrowser extends Browser, TDatabases extends DatabaseSchemas = {}, TFactories extends FactoryBuilders = {}> {
|
|
332
|
+
(name: string, fn: FeatureFn<TBrowser, TDatabases, TFactories>, timeout?: number): void;
|
|
333
|
+
only(name: string, fn: FeatureFn<TBrowser, TDatabases, TFactories>, timeout?: number): void;
|
|
334
|
+
skip(name: string, fn: FeatureFn<TBrowser, TDatabases, TFactories>, timeout?: number): void;
|
|
335
|
+
}
|
|
336
|
+
export declare function featureTest<TBrowser extends Browser = Browser, TDatabases extends DatabaseSchemas = {}, TFactories extends FactoryBuilders = {}>(options?: FeatureTestOptions<TBrowser, TFactories>): FeatureIt<TBrowser, TDatabases, TFactories>;
|
|
337
|
+
/** What `signInWithMagicLink` uses of a better-auth client. */
|
|
338
|
+
interface MagicLinkAuthClient<TSession> {
|
|
339
|
+
signIn: {
|
|
340
|
+
magicLink(input: {
|
|
341
|
+
email: string;
|
|
342
|
+
}): Promise<{
|
|
343
|
+
error?: {
|
|
344
|
+
message?: string;
|
|
345
|
+
} | null;
|
|
346
|
+
}>;
|
|
347
|
+
};
|
|
348
|
+
getSession(): Promise<{
|
|
349
|
+
data: TSession | null;
|
|
350
|
+
}>;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Sign a test's browser in the way a person does: ask the auth server for a
|
|
354
|
+
* magic link, open the email it sent, follow the link.
|
|
355
|
+
*
|
|
356
|
+
* What the generated `browser.signIn(email)` calls. The address's mail is
|
|
357
|
+
* cleared first — so the link is this request's, not one an earlier test left
|
|
358
|
+
* — and cleared again after the test, like any address a test reads. Returns
|
|
359
|
+
* the session the auth server then reports, as better-auth hands it back.
|
|
360
|
+
*/
|
|
361
|
+
export declare function signInWithMagicLink<TSession>(browser: Browser, auth: MagicLinkAuthClient<TSession>, email: string): Promise<TSession>;
|
|
362
|
+
/** `browser.signIn` finished without a session. */
|
|
363
|
+
export declare class SignInFailed extends Error {
|
|
364
|
+
readonly email: string;
|
|
365
|
+
readonly reason: string;
|
|
366
|
+
constructor(email: string, reason: string);
|
|
299
367
|
}
|
|
300
|
-
export declare function featureTest<TBrowser extends Browser = Browser, DB = unknown>(options?: FeatureTestOptions<TBrowser>): FeatureIt<TBrowser, DB>;
|
|
301
368
|
/** A request reached an in-process server without a test to belong to. */
|
|
302
369
|
export declare class UnknownTestContext extends Error {
|
|
303
370
|
readonly url: string;
|
|
@@ -308,12 +375,18 @@ export declare class UnknownTestContext extends Error {
|
|
|
308
375
|
export declare class NoInbox extends Error {
|
|
309
376
|
constructor();
|
|
310
377
|
}
|
|
311
|
-
/** `
|
|
378
|
+
/** `db.get(name)` named no database the test is handed. */
|
|
312
379
|
export declare class UnknownDatabase extends Error {
|
|
313
|
-
readonly
|
|
314
|
-
readonly
|
|
315
|
-
constructor(
|
|
380
|
+
readonly database: string;
|
|
381
|
+
readonly known: readonly string[];
|
|
382
|
+
constructor(database: string, known: readonly string[]);
|
|
383
|
+
}
|
|
384
|
+
/** A factory keyed by a service name no database the app declares has. */
|
|
385
|
+
export declare class UnknownFactory extends Error {
|
|
386
|
+
readonly factory: string;
|
|
387
|
+
readonly known: readonly string[];
|
|
388
|
+
constructor(factory: string, known: readonly string[]);
|
|
316
389
|
}
|
|
317
390
|
//#endregion
|
|
318
|
-
export { type CreateMswHandlersOptions, type CreateMswHandlersResult, type DatabaseOf, type FeatureContext, type FeatureIt, type FeatureTestOptions, type RegisterContextOptions, TEST_CONTEXT_HEADER, type TestManifest, type TestManifestSource };
|
|
391
|
+
export { type CreateMswHandlersOptions, type CreateMswHandlersResult, type DatabaseOf, type DatabaseSchemas, type FactoryBuilders, type FeatureContext, type FeatureIt, type FeatureTestOptions, type MagicLinkAuthClient, type RegisterContextOptions, TEST_CONTEXT_HEADER, type TestDatabases, type TestFactories, type TestManifest, type TestManifestSource };
|
|
319
392
|
//# sourceMappingURL=testing.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.mts","names":["TestBrowser"],"sources":["../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts","../../src/testing/manifest.ts","../../src/testing/featureTest.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"testing.d.mts","names":["TestBrowser"],"sources":["../../src/endpoints/MswEndpointAdaptor.ts","../../src/endpoints/TestEndpointAdaptor.ts","../../src/functions/TestFunctionAdaptor.ts","../../src/queue/TestQueueAdaptor.ts","../../src/subscribers/TestSubscriberAdaptor.ts","../../src/testing/manifest.ts","../../src/testing/featureTest.ts"],"mappings":"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"}
|
|
@@ -503,10 +503,14 @@ function featureTest(options = {}) {
|
|
|
503
503
|
const manifest = options.manifest ?? loadTestManifest();
|
|
504
504
|
const BrowserClass = options.browser ?? Browser;
|
|
505
505
|
let app;
|
|
506
|
+
let factoryDatabases = [];
|
|
507
|
+
let owned = [];
|
|
506
508
|
let network;
|
|
507
509
|
let restoreFetch = () => {};
|
|
508
510
|
beforeAll(async () => {
|
|
509
|
-
app = await load(manifest, options.
|
|
511
|
+
app = await load(manifest, options.modules ?? {});
|
|
512
|
+
owned = ownDatabases(app, manifest);
|
|
513
|
+
factoryDatabases = databasesFor(options.factories ?? {}, owned);
|
|
510
514
|
for (const database of app.databases) bindToTests(database);
|
|
511
515
|
network = setupServer(...surfaceHandlers(app.endpoints, manifest.env), ...app.auths.map((auth) => authHandler(auth, manifest.env, app.envParser)));
|
|
512
516
|
network.listen({ onUnhandledRequest(request, print) {
|
|
@@ -529,6 +533,11 @@ function featureTest(options = {}) {
|
|
|
529
533
|
addresses: /* @__PURE__ */ new Set(),
|
|
530
534
|
published: /* @__PURE__ */ new Map()
|
|
531
535
|
};
|
|
536
|
+
const readMail = app.readMail;
|
|
537
|
+
if (readMail) state.mailbox = (address) => {
|
|
538
|
+
state.addresses.add(address);
|
|
539
|
+
return readMail(address);
|
|
540
|
+
};
|
|
532
541
|
contexts.set(id, state);
|
|
533
542
|
await state.discovery.register(recorders(app.channels, state));
|
|
534
543
|
try {
|
|
@@ -536,13 +545,29 @@ function featureTest(options = {}) {
|
|
|
536
545
|
const browser = new BrowserClass();
|
|
537
546
|
const restore = browser.install();
|
|
538
547
|
try {
|
|
548
|
+
const transaction = (database) => state.transactions.get(database.id, urlOf(database, app.envParser), database.clientConfig);
|
|
549
|
+
const db = { get: (name) => {
|
|
550
|
+
const database = owned.find((candidate) => candidate.service.serviceName === name);
|
|
551
|
+
if (!database) throw new UnknownDatabase(name, owned.map((candidate) => candidate.service.serviceName));
|
|
552
|
+
return transaction(database);
|
|
553
|
+
} };
|
|
554
|
+
const built = /* @__PURE__ */ new Map();
|
|
539
555
|
await fn({
|
|
540
556
|
browser,
|
|
541
|
-
db
|
|
557
|
+
db,
|
|
558
|
+
factories: { get: (name) => {
|
|
559
|
+
const database = factoryDatabases.find(([candidate]) => candidate === name)?.[1];
|
|
560
|
+
if (!database) throw new UnknownFactory(name, factoryDatabases.map(([candidate]) => candidate));
|
|
561
|
+
let factory = built.get(name);
|
|
562
|
+
if (!factory) {
|
|
563
|
+
factory = transaction(database).then(options.factories[name]);
|
|
564
|
+
built.set(name, factory);
|
|
565
|
+
}
|
|
566
|
+
return factory;
|
|
567
|
+
} },
|
|
542
568
|
mailbox: (address) => {
|
|
543
|
-
if (!
|
|
544
|
-
state.
|
|
545
|
-
return app.readMail(address);
|
|
569
|
+
if (!state.mailbox) throw new NoInbox();
|
|
570
|
+
return state.mailbox(address);
|
|
546
571
|
},
|
|
547
572
|
published: (channel) => [...state.published.get(channel.id) ?? []],
|
|
548
573
|
subscriber: (subscriber) => new TestSubscriberAdaptor(subscriber, state.discovery),
|
|
@@ -568,7 +593,7 @@ function featureTest(options = {}) {
|
|
|
568
593
|
* The same modules the app runs, so a construct here *is* the app's construct —
|
|
569
594
|
* the one its endpoints were built from — never a copy declared again.
|
|
570
595
|
*/
|
|
571
|
-
async function load(manifest,
|
|
596
|
+
async function load(manifest, modules) {
|
|
572
597
|
const envParser = new EnvironmentParser({ ...manifest.env });
|
|
573
598
|
const imported = async ({ file, export: name }) => (modules[file] ?? await import(file))[name];
|
|
574
599
|
const constructs = await Promise.all(Object.values(manifest.constructs).map(({ source }) => imported(source)));
|
|
@@ -586,7 +611,6 @@ async function load(manifest, database, modules) {
|
|
|
586
611
|
auths,
|
|
587
612
|
emails,
|
|
588
613
|
channels,
|
|
589
|
-
database: databaseOf(databases, endpoints, database),
|
|
590
614
|
...inbox ? { readMail: createMailbox({ inbox }) } : {}
|
|
591
615
|
};
|
|
592
616
|
}
|
|
@@ -609,18 +633,22 @@ function recorders(channels, state) {
|
|
|
609
633
|
});
|
|
610
634
|
}
|
|
611
635
|
/**
|
|
612
|
-
* The
|
|
613
|
-
*
|
|
614
|
-
*
|
|
636
|
+
* The databases a test is handed: the app's own. A schema tenant an auth server
|
|
637
|
+
* owns is reached through that server, as the app reaches it, and a reader is
|
|
638
|
+
* the same database through a read-only role — neither is another database to
|
|
639
|
+
* test against.
|
|
615
640
|
*/
|
|
616
|
-
function
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
641
|
+
function ownDatabases(app, manifest) {
|
|
642
|
+
const owners = new Set(app.auths.map((auth) => auth.databaseId));
|
|
643
|
+
return app.databases.filter((database) => !owners.has(database.id) && manifest.constructs[database.id]?.kind !== "database-reader");
|
|
644
|
+
}
|
|
645
|
+
/** Each factory's database, found by the service name it is keyed by. */
|
|
646
|
+
function databasesFor(factories, databases) {
|
|
647
|
+
return Object.keys(factories).map((name) => {
|
|
648
|
+
const database = databases.find((candidate) => candidate.service.serviceName === name);
|
|
649
|
+
if (!database) throw new UnknownFactory(name, databases.map((candidate) => candidate.service.serviceName));
|
|
650
|
+
return [name, database];
|
|
651
|
+
});
|
|
624
652
|
}
|
|
625
653
|
/**
|
|
626
654
|
* Make a database resolve, inside a test, to that test's transaction.
|
|
@@ -698,6 +726,42 @@ function trim(url) {
|
|
|
698
726
|
function isLocal(url) {
|
|
699
727
|
return url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname.endsWith(".localhost");
|
|
700
728
|
}
|
|
729
|
+
/**
|
|
730
|
+
* Sign a test's browser in the way a person does: ask the auth server for a
|
|
731
|
+
* magic link, open the email it sent, follow the link.
|
|
732
|
+
*
|
|
733
|
+
* What the generated `browser.signIn(email)` calls. The address's mail is
|
|
734
|
+
* cleared first — so the link is this request's, not one an earlier test left
|
|
735
|
+
* — and cleared again after the test, like any address a test reads. Returns
|
|
736
|
+
* the session the auth server then reports, as better-auth hands it back.
|
|
737
|
+
*/
|
|
738
|
+
async function signInWithMagicLink(browser, auth, email) {
|
|
739
|
+
const context = currentTestContext();
|
|
740
|
+
const state = context && contexts.get(context.id);
|
|
741
|
+
if (!state) throw new UnknownTestContext("signIn", context?.id);
|
|
742
|
+
if (!state.mailbox) throw new NoInbox();
|
|
743
|
+
const inbox = state.mailbox(email);
|
|
744
|
+
await inbox.clear();
|
|
745
|
+
const requested = await auth.signIn.magicLink({ email });
|
|
746
|
+
if (requested.error) throw new SignInFailed(email, `the auth server refused the magic link: ${requested.error.message ?? "no reason given"}`);
|
|
747
|
+
const mail = await inbox.last();
|
|
748
|
+
if (!mail.link) throw new SignInFailed(email, "its email held no link");
|
|
749
|
+
await browser.visit(mail.link);
|
|
750
|
+
const { data } = await auth.getSession();
|
|
751
|
+
if (!data) throw new SignInFailed(email, "the auth server reported no session after the link was opened");
|
|
752
|
+
return data;
|
|
753
|
+
}
|
|
754
|
+
/** `browser.signIn` finished without a session. */
|
|
755
|
+
var SignInFailed = class extends Error {
|
|
756
|
+
email;
|
|
757
|
+
reason;
|
|
758
|
+
constructor(email, reason) {
|
|
759
|
+
super(`Signing ${email} in failed: ${reason}.`);
|
|
760
|
+
this.email = email;
|
|
761
|
+
this.reason = reason;
|
|
762
|
+
this.name = "SignInFailed";
|
|
763
|
+
}
|
|
764
|
+
};
|
|
701
765
|
/** A request reached an in-process server without a test to belong to. */
|
|
702
766
|
var UnknownTestContext = class extends Error {
|
|
703
767
|
url;
|
|
@@ -716,18 +780,29 @@ var NoInbox = class extends Error {
|
|
|
716
780
|
this.name = "NoInbox";
|
|
717
781
|
}
|
|
718
782
|
};
|
|
719
|
-
/** `
|
|
783
|
+
/** `db.get(name)` named no database the test is handed. */
|
|
720
784
|
var UnknownDatabase = class extends Error {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
constructor(
|
|
724
|
-
super(`
|
|
725
|
-
this.
|
|
726
|
-
this.
|
|
785
|
+
database;
|
|
786
|
+
known;
|
|
787
|
+
constructor(database, known) {
|
|
788
|
+
super(`db.get('${database}') names no database of this app's. ` + (known.length > 0 ? `Its databases: ${known.join(", ")}. ` : "It declares no database of its own. ") + "A tenant an auth server owns is reached through that server, and a reader through the database it reads.");
|
|
789
|
+
this.database = database;
|
|
790
|
+
this.known = known;
|
|
727
791
|
this.name = "UnknownDatabase";
|
|
728
792
|
}
|
|
729
793
|
};
|
|
794
|
+
/** A factory keyed by a service name no database the app declares has. */
|
|
795
|
+
var UnknownFactory = class extends Error {
|
|
796
|
+
factory;
|
|
797
|
+
known;
|
|
798
|
+
constructor(factory, known) {
|
|
799
|
+
super(`There is a test factory for '${factory}', and no database this app declares is called that. ` + (known.length > 0 ? `Its databases: ${known.join(", ")}. ` : "It declares no database. ") + `Name the file after the database construct: test/factories/<construct>.ts.`);
|
|
800
|
+
this.factory = factory;
|
|
801
|
+
this.known = known;
|
|
802
|
+
this.name = "UnknownFactory";
|
|
803
|
+
}
|
|
804
|
+
};
|
|
730
805
|
//#endregion
|
|
731
|
-
export { NoInbox, NoTestManifest, TEST_CONTEXT_HEADER, TEST_MANIFEST_ENV, TestEndpointAdaptor, TestFunctionAdaptor, TestQueueAdaptor, TestSubscriberAdaptor, UnknownDatabase, UnknownTestContext, createMswHandlers, featureTest, loadTestManifest };
|
|
806
|
+
export { NoInbox, NoTestManifest, SignInFailed, TEST_CONTEXT_HEADER, TEST_MANIFEST_ENV, TestEndpointAdaptor, TestFunctionAdaptor, TestQueueAdaptor, TestSubscriberAdaptor, UnknownDatabase, UnknownFactory, UnknownTestContext, createMswHandlers, featureTest, loadTestManifest, signInWithMagicLink };
|
|
732
807
|
|
|
733
808
|
//# sourceMappingURL=testing.mjs.map
|