@justscale/testing 0.1.0

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.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Adapter conformance suite - cluster primitives.
3
+ *
4
+ * Every cluster-capable adapter (Postgres, Redis, future) must pass this
5
+ * suite to claim conformance. Shape follows the well-trod JDBC/ODBC
6
+ * pattern: one abstract spec, multiple concrete runners.
7
+ *
8
+ * ## How to use
9
+ *
10
+ * ```typescript
11
+ * import { describeClusterConformance } from '@justscale/testing/conformance';
12
+ * import { PostgresFeature, PostgresChannelFeature, PostgresLockFeature,
13
+ * PostgresProcessFeature } from '@justscale/postgres';
14
+ *
15
+ * describeClusterConformance('postgres (real docker pg)', {
16
+ * makeInstance: () => JustScale()
17
+ * .add(env)
18
+ * .add(PostgresFeature)
19
+ * .add(PostgresChannelFeature)
20
+ * .add(PostgresLockFeature)
21
+ * .add(PostgresProcessFeature),
22
+ * skipIfUnavailable: async () => !(await hasDockerPg()),
23
+ * });
24
+ * ```
25
+ *
26
+ * ## What it asserts
27
+ *
28
+ * 1. Channel pub/sub cross-instance - publish on A, subscribe on B, B receives within 500ms.
29
+ * 2. Channel isolation - channels keyed differently don't cross-talk.
30
+ * 3. Lock mutex - two instances racing for the same advisory lock, only one wins; release lets the other acquire.
31
+ * 4. Lock hand-off - kill lock-holder, another instance picks it up.
32
+ * 5. Process signal resume - process suspended at race(), signal fires, process wakes and advances pc.
33
+ * 6. Process cross-instance signal - process running on A, emit from B, A resumes.
34
+ * 7. Process advisory lock - spawn same process path on two instances, only one runs.
35
+ *
36
+ * Each scenario is scoped tight enough to pinpoint the failing primitive.
37
+ */
38
+ /**
39
+ * Run the cluster conformance suite against an adapter.
40
+ *
41
+ * @param adapterName - Shows up in test output: "cluster-conformance/postgres"
42
+ * @param opts - How to spin up instances + setup/teardown hooks
43
+ */
44
+ export function describeClusterConformance(adapterName, opts) {
45
+ void adapterName;
46
+ void opts;
47
+ throw new Error(`describeClusterConformance('${adapterName}', ...) is not yet implemented. ` +
48
+ 'Scenarios are listed in the header comment.');
49
+ }
50
+ //# sourceMappingURL=cluster-primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-primitives.js","sourceRoot":"","sources":["../../src/conformance/cluster-primitives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAqCH;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CACxC,WAAmB,EACnB,IAA+B;IAE/B,KAAK,WAAW,CAAC;IACjB,KAAK,IAAI,CAAC;IACV,MAAM,IAAI,KAAK,CACb,+BAA+B,WAAW,kCAAkC;QAC5E,6CAA6C,CAC9C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Test Container
3
+ *
4
+ * Extended container with support for mocking and overriding services.
5
+ */
6
+ import { Container, type ServiceToken, type InstanceOf } from '@justscale/core';
7
+ /**
8
+ * A container designed for testing with mock support.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const container = new TestContainer();
13
+ *
14
+ * // Register real services
15
+ * container.register(UserRepository);
16
+ * container.register(UserService);
17
+ *
18
+ * // Override with a mock
19
+ * container.mock(UserRepository, {
20
+ * findById: mockFn().returns(Promise.resolve({ id: '1', name: 'Test' })),
21
+ * });
22
+ *
23
+ * // Resolve - will use the mock for UserRepository
24
+ * const userService = container.resolve(UserService);
25
+ * ```
26
+ */
27
+ export declare class TestContainer extends Container {
28
+ private mocks;
29
+ /**
30
+ * Override a service with a mock implementation.
31
+ * The mock will be used instead of the real service when resolving.
32
+ */
33
+ mock<T>(token: ServiceToken<T>, mockInstance: Partial<T>): this;
34
+ /**
35
+ * Override a service with a complete replacement instance.
36
+ */
37
+ override<T>(token: ServiceToken<T>, instance: T): this;
38
+ /**
39
+ * Clear all mocks, restoring original service resolution.
40
+ */
41
+ clearMocks(): this;
42
+ /**
43
+ * Clear a specific mock.
44
+ */
45
+ clearMock<T>(token: ServiceToken<T>): this;
46
+ /**
47
+ * Get the mock for a service if one exists.
48
+ */
49
+ getMock<T>(token: ServiceToken<T>): T | undefined;
50
+ /**
51
+ * Check if a service has been mocked.
52
+ */
53
+ isMocked<T>(token: ServiceToken<T>): boolean;
54
+ /**
55
+ * Resolve a service - returns mock if available, otherwise resolves normally.
56
+ */
57
+ resolve<T>(token: ServiceToken<T>): Promise<T>;
58
+ /**
59
+ * Get typed access to a resolved service.
60
+ * Useful for accessing services in tests.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const userService = await container.get(UserService);
65
+ * // userService is typed as InstanceOf<typeof UserService>
66
+ * ```
67
+ */
68
+ get<T extends ServiceToken>(token: T): Promise<InstanceOf<T>>;
69
+ }
70
+ //# sourceMappingURL=container.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAc,SAAQ,SAAS;IAC1C,OAAO,CAAC,KAAK,CAAoC;IAEjD;;;OAGG;IACH,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAK/D;;OAEG;IACH,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAKtD;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;OAEG;IACH,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IAK1C;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS;IAIjD;;OAEG;IACH,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO;IAI5C;;OAEG;IACY,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAU7D;;;;;;;;;OASG;IACG,GAAG,CAAC,CAAC,SAAS,YAAY,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;CAGpE"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Test Container
3
+ *
4
+ * Extended container with support for mocking and overriding services.
5
+ */
6
+ import { Container, } from '@justscale/core';
7
+ /**
8
+ * A container designed for testing with mock support.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const container = new TestContainer();
13
+ *
14
+ * // Register real services
15
+ * container.register(UserRepository);
16
+ * container.register(UserService);
17
+ *
18
+ * // Override with a mock
19
+ * container.mock(UserRepository, {
20
+ * findById: mockFn().returns(Promise.resolve({ id: '1', name: 'Test' })),
21
+ * });
22
+ *
23
+ * // Resolve - will use the mock for UserRepository
24
+ * const userService = container.resolve(UserService);
25
+ * ```
26
+ */
27
+ export class TestContainer extends Container {
28
+ mocks = new Map();
29
+ /**
30
+ * Override a service with a mock implementation.
31
+ * The mock will be used instead of the real service when resolving.
32
+ */
33
+ mock(token, mockInstance) {
34
+ this.mocks.set(token, mockInstance);
35
+ return this;
36
+ }
37
+ /**
38
+ * Override a service with a complete replacement instance.
39
+ */
40
+ override(token, instance) {
41
+ this.mocks.set(token, instance);
42
+ return this;
43
+ }
44
+ /**
45
+ * Clear all mocks, restoring original service resolution.
46
+ */
47
+ clearMocks() {
48
+ this.mocks.clear();
49
+ return this;
50
+ }
51
+ /**
52
+ * Clear a specific mock.
53
+ */
54
+ clearMock(token) {
55
+ this.mocks.delete(token);
56
+ return this;
57
+ }
58
+ /**
59
+ * Get the mock for a service if one exists.
60
+ */
61
+ getMock(token) {
62
+ return this.mocks.get(token);
63
+ }
64
+ /**
65
+ * Check if a service has been mocked.
66
+ */
67
+ isMocked(token) {
68
+ return this.mocks.has(token);
69
+ }
70
+ /**
71
+ * Resolve a service - returns mock if available, otherwise resolves normally.
72
+ */
73
+ async resolve(token) {
74
+ // Check for mock first
75
+ if (this.mocks.has(token)) {
76
+ return this.mocks.get(token);
77
+ }
78
+ // Fall back to normal resolution
79
+ return super.resolve(token);
80
+ }
81
+ /**
82
+ * Get typed access to a resolved service.
83
+ * Useful for accessing services in tests.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const userService = await container.get(UserService);
88
+ * // userService is typed as InstanceOf<typeof UserService>
89
+ * ```
90
+ */
91
+ async get(token) {
92
+ return this.resolve(token);
93
+ }
94
+ }
95
+ //# sourceMappingURL=container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,SAAS,GAGV,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,aAAc,SAAQ,SAAS;IAClC,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEjD;;;OAGG;IACH,IAAI,CAAI,KAAsB,EAAE,YAAwB;QACtD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,QAAQ,CAAI,KAAsB,EAAE,QAAW;QAC7C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,SAAS,CAAI,KAAsB;QACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,OAAO,CAAI,KAAsB;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAkB,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,QAAQ,CAAI,KAAsB;QAChC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACM,KAAK,CAAC,OAAO,CAAI,KAAsB;QAC9C,uBAAuB;QACvB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;QACpC,CAAC;QAED,iCAAiC;QACjC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,GAAG,CAAyB,KAAQ;QACxC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAA2B,CAAC;IACvD,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * JustScale Testing Utilities
3
+ *
4
+ * Provides helpers for testing JustScale applications:
5
+ * - TestContainer: Container with mock support
6
+ * - createTestApp: Create an app instance for testing
7
+ * - Test client with pluggable transports
8
+ */
9
+ export { TestContainer } from './container.js';
10
+ export { createTestApp, type TestApp } from './app.js';
11
+ export { createTestClient, teardownApp, type TestClient, type TestClientWithTransports, type TestClientOptions, type TestTransport, type TransportState, type TransportClient, type TransportOptions, type TestResponse, type BuildControllerAPI, } from './client.js';
12
+ export { createTestKit, type TestKit, type CreateTestKitOptions, type KitBuilderFn, type SpawnHttpOptions, type SpawnHttpResult, } from './kit.js';
13
+ export { mock, mockFn, mockService, spyOn, spyService, mockResolves, mockRejects, mockThrows, assertCalledWith, assertCallCount, assertNotCalled, enableDebuggerFormatters, type MockedService, type SpyWrapper, } from './mock.js';
14
+ export { InMemoryLockProvider } from '@justscale/core/memory';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,KAAK,UAAU,EACf,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,aAAa,EACb,KAAK,OAAO,EACZ,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAEL,IAAI,EAEJ,MAAM,EACN,WAAW,EACX,KAAK,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EAEV,gBAAgB,EAChB,eAAe,EACf,eAAe,EAEf,wBAAwB,EAExB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * JustScale Testing Utilities
3
+ *
4
+ * Provides helpers for testing JustScale applications:
5
+ * - TestContainer: Container with mock support
6
+ * - createTestApp: Create an app instance for testing
7
+ * - Test client with pluggable transports
8
+ */
9
+ if (process.env.NODE_ENV === 'production') {
10
+ throw new Error('@justscale/core/testing must not be imported in production code. ' +
11
+ 'This package contains test-only utilities (mocks, spies, TestContainer).');
12
+ }
13
+ export { TestContainer } from './container.js';
14
+ export { createTestApp } from './app.js';
15
+ export { createTestClient, teardownApp, } from './client.js';
16
+ export { createTestKit, } from './kit.js';
17
+ export {
18
+ // Re-exported from node:test
19
+ mock,
20
+ // Mock helpers
21
+ mockFn, mockService, spyOn, spyService, mockResolves, mockRejects, mockThrows,
22
+ // Assertions
23
+ assertCalledWith, assertCallCount, assertNotCalled,
24
+ // Debugger support
25
+ enableDebuggerFormatters, } from './mock.js';
26
+ // Lock testing utilities
27
+ export { InMemoryLockProvider } from '@justscale/core/memory';
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;IAC1C,MAAM,IAAI,KAAK,CACb,mEAAmE;QACnE,0EAA0E,CAC3E,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAgB,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,gBAAgB,EAChB,WAAW,GAUZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,aAAa,GAMd,MAAM,UAAU,CAAC;AAClB,OAAO;AACL,6BAA6B;AAC7B,IAAI;AACJ,eAAe;AACf,MAAM,EACN,WAAW,EACX,KAAK,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,UAAU;AACV,aAAa;AACb,gBAAgB,EAChB,eAAe,EACf,eAAe;AACf,mBAAmB;AACnB,wBAAwB,GAIzB,MAAM,WAAW,CAAC;AAEnB,yBAAyB;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/kit.d.ts ADDED
@@ -0,0 +1,82 @@
1
+ import JustScale from '@justscale/core';
2
+ import type { App, ControllerDef } from '@justscale/core';
3
+ type JustScaleBuilder = ReturnType<typeof JustScale>;
4
+ import { type TestClientOptions, type TestClientWithTransports, type TestTransport, type BuildControllerAPI } from './client.js';
5
+ /**
6
+ * Builder factory: receives a fresh JustScale() builder (with the usual
7
+ * built-ins already provided — Logger, Lifecycle), returns it decorated
8
+ * with whatever the test wants. The returned Builder must have its
9
+ * requires satisfied; we call `.build().compile()` on it.
10
+ */
11
+ export type KitBuilderFn = (b: JustScaleBuilder) => {
12
+ build: () => {
13
+ compile: () => App;
14
+ };
15
+ };
16
+ export interface SpawnHttpOptions<TTransports extends Record<string, TestTransport<unknown, unknown>>, TControllers extends Record<string, ControllerDef<any, any, any>>> extends TestClientOptions<TTransports> {
17
+ /** Map of controller defs to surface as a typed `controllers` API. */
18
+ controllers?: TControllers;
19
+ }
20
+ export interface SpawnHttpResult<TTransports extends Record<string, TestTransport<unknown, unknown>>, TControllers extends Record<string, ControllerDef<any, any, any>>> {
21
+ app: App;
22
+ client: TestClientWithTransports<App, TTransports>;
23
+ controllers: BuildControllerAPI<TControllers>;
24
+ }
25
+ /**
26
+ * Multi-instance test harness. Owns N apps, drains them on dispose.
27
+ *
28
+ * Auto-registers `afterEach` from node:test when available so tests
29
+ * never have to remember cleanup; `using` / explicit `dispose()` are
30
+ * supported as fallbacks (or for tests outside node:test).
31
+ *
32
+ * The framework's story is many-instance coordination — this kit
33
+ * makes 1 the trivial case of N. `spawnCluster(N, builder)` is the
34
+ * primitive for distributed-invariant tests (cross-instance lock,
35
+ * cross-instance channel) that previously required ad-hoc worker
36
+ * spawning.
37
+ */
38
+ export interface TestKit {
39
+ /** Build + compile one app. Adds it to the kit's owned set. */
40
+ spawn(builderFn: KitBuilderFn): Promise<App>;
41
+ /**
42
+ * Build + compile one app AND attach test transport(s) for HTTP-style
43
+ * testing. Returns a flat result: `{ app, client, controllers }`.
44
+ * `controllers` is the typed surface for the controller defs you pass.
45
+ */
46
+ spawnHttp<TTransports extends Record<string, TestTransport<unknown, unknown>> = Record<string, never>, TControllers extends Record<string, ControllerDef<any, any, any>> = Record<string, never>>(builderFn: KitBuilderFn, options?: SpawnHttpOptions<TTransports, TControllers>): Promise<SpawnHttpResult<TTransports, TControllers>>;
47
+ /**
48
+ * N identical instances. Use for distributed-invariant tests:
49
+ * the apps share infrastructure (same Postgres, same Redis) so
50
+ * coordination primitives (locks, channels) operate cross-instance.
51
+ */
52
+ spawnCluster(n: number, builderFn: KitBuilderFn): Promise<App[]>;
53
+ /** Drain everything. Idempotent. */
54
+ dispose(): Promise<void>;
55
+ /** Apps owned by this kit (live + already-disposed are pruned). */
56
+ readonly apps: readonly App[];
57
+ readonly [Symbol.asyncDispose]: () => Promise<void>;
58
+ }
59
+ export interface CreateTestKitOptions {
60
+ /**
61
+ * Whether to auto-register `afterEach` from node:test. Defaults to
62
+ * true. Set to false for tests that manage their own lifecycle.
63
+ */
64
+ autoCleanup?: boolean;
65
+ }
66
+ /**
67
+ * Create a multi-instance test harness. Call at module level (top of
68
+ * a test file) so its `afterEach` runs after every test in the file.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const kit = createTestKit()
73
+ *
74
+ * test('lock cross-instance', async () => {
75
+ * const [a, b] = await kit.spawnCluster(2, builder)
76
+ * // ... a holds lock, b times out, etc.
77
+ * })
78
+ * ```
79
+ */
80
+ export declare function createTestKit(options?: CreateTestKitOptions): TestKit;
81
+ export {};
82
+ //# sourceMappingURL=kit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,EAAE,GAAG,EAAW,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEnE,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AACrD,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAErB;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,CAAC,EAAE,gBAAgB,KAChB;IAAE,KAAK,EAAE,MAAM;QAAE,OAAO,EAAE,MAAM,GAAG,CAAA;KAAE,CAAA;CAAE,CAAC;AAE7C,MAAM,WAAW,gBAAgB,CAC/B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EACnE,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CACjE,SAAQ,iBAAiB,CAAC,WAAW,CAAC;IACtC,sEAAsE;IACtE,WAAW,CAAC,EAAE,YAAY,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe,CAC9B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EACnE,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAEjE,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,wBAAwB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACnD,WAAW,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,OAAO;IACtB,+DAA+D;IAC/D,KAAK,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE7C;;;;OAIG;IACH,SAAS,CACP,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC3F,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEzF,SAAS,EAAE,YAAY,EACvB,OAAO,CAAC,EAAE,gBAAgB,CAAC,WAAW,EAAE,YAAY,CAAC,GACpD,OAAO,CAAC,eAAe,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;IAEvD;;;;OAIG;IACH,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAEjE,oCAAoC;IACpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,EAAE,CAAC;IAE9B,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CA2GrE"}
package/dist/kit.js ADDED
@@ -0,0 +1,114 @@
1
+ import JustScale from '@justscale/core';
2
+ import { createTestClient, teardownApp, } from './client.js';
3
+ /**
4
+ * Create a multi-instance test harness. Call at module level (top of
5
+ * a test file) so its `afterEach` runs after every test in the file.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const kit = createTestKit()
10
+ *
11
+ * test('lock cross-instance', async () => {
12
+ * const [a, b] = await kit.spawnCluster(2, builder)
13
+ * // ... a holds lock, b times out, etc.
14
+ * })
15
+ * ```
16
+ */
17
+ export function createTestKit(options) {
18
+ const owned = [];
19
+ let disposed = false;
20
+ async function disposeAll() {
21
+ if (disposed)
22
+ return;
23
+ disposed = true;
24
+ const errors = [];
25
+ while (owned.length) {
26
+ const entry = owned.pop();
27
+ try {
28
+ await entry.close();
29
+ }
30
+ catch (err) {
31
+ errors.push(err);
32
+ }
33
+ }
34
+ disposed = false; // allow re-spawn after manual dispose mid-test
35
+ if (errors.length) {
36
+ const first = errors[0];
37
+ throw first instanceof Error ? first : new Error(String(first));
38
+ }
39
+ }
40
+ if (options?.autoCleanup ?? true) {
41
+ // node:test exposes `afterEach` as a top-level export; if we're
42
+ // running outside node:test (e.g. a script), this import fails
43
+ // silently and callers must dispose manually.
44
+ void (async () => {
45
+ try {
46
+ const { afterEach } = await import('node:test');
47
+ afterEach(async () => {
48
+ await disposeAll();
49
+ });
50
+ }
51
+ catch {
52
+ // not in node:test context
53
+ }
54
+ })();
55
+ }
56
+ async function buildAndCompile(builderFn) {
57
+ const builder = builderFn(JustScale());
58
+ const app = builder.build().compile();
59
+ await app.ready;
60
+ return app;
61
+ }
62
+ const kit = {
63
+ async spawn(builderFn) {
64
+ const app = await buildAndCompile(builderFn);
65
+ owned.push({ app, close: () => teardownApp(app) });
66
+ return app;
67
+ },
68
+ async spawnHttp(builderFn, opts) {
69
+ const app = await buildAndCompile(builderFn);
70
+ const transports = opts?.transports ?? {};
71
+ const transportOptions = opts?.transportOptions;
72
+ const client = await createTestClient(app, {
73
+ transports,
74
+ transportOptions,
75
+ });
76
+ // client.close() already calls teardownApp
77
+ owned.push({ app, close: () => client.close() });
78
+ const controllerDefs = (opts?.controllers ?? {});
79
+ // useControllers lives on the http transport client; only available if the
80
+ // caller wired the http transport.
81
+ const httpClient = client['http'];
82
+ const controllers = httpClient && typeof httpClient.useControllers === 'function' && Object.keys(controllerDefs).length
83
+ ? httpClient.useControllers(controllerDefs)
84
+ : {};
85
+ return {
86
+ app,
87
+ client: client,
88
+ controllers: controllers,
89
+ };
90
+ },
91
+ async spawnCluster(n, builderFn) {
92
+ if (n < 1)
93
+ return [];
94
+ const results = [];
95
+ // Sequential: deterministic ordering for distributed tests, and the
96
+ // build phase is fast (DI graph, not network). Parallel build was
97
+ // an option but it makes timing-sensitive tests harder to reason
98
+ // about for trivial speedup.
99
+ for (let i = 0; i < n; i++) {
100
+ const app = await buildAndCompile(builderFn);
101
+ owned.push({ app, close: () => teardownApp(app) });
102
+ results.push(app);
103
+ }
104
+ return results;
105
+ },
106
+ dispose: disposeAll,
107
+ get apps() {
108
+ return owned.map((e) => e.app);
109
+ },
110
+ [Symbol.asyncDispose]: () => disposeAll(),
111
+ };
112
+ return kit;
113
+ }
114
+ //# sourceMappingURL=kit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kit.js","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"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"}
package/dist/mock.d.ts ADDED
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Mocking utilities for JustScale testing
3
+ *
4
+ * Integrates with Node.js test runner's mock API while providing
5
+ * type-safe helpers for mocking services and controllers.
6
+ *
7
+ * Supports `using` keyword for automatic cleanup:
8
+ * ```typescript
9
+ * using spied = spyOn(service);
10
+ * // ... test code ...
11
+ * // automatically restored when block exits
12
+ * ```
13
+ */
14
+ import { mock, type Mock as NodeMock } from 'node:test';
15
+ import type { ServiceDef, ServiceToken } from '@justscale/core';
16
+ export { mock };
17
+ /**
18
+ * Manually enable custom formatters after debugger connects.
19
+ * This is opt-in — it is not called automatically on import.
20
+ * Call it early in your test setup if you want CDP-based formatting in the debugger.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * import { enableDebuggerFormatters } from '@justscale/testing';
25
+ * enableDebuggerFormatters(); // Call early in your test
26
+ * ```
27
+ */
28
+ export declare function enableDebuggerFormatters(): void;
29
+ /**
30
+ * Extract the instance type from a ServiceDef or ServiceToken
31
+ */
32
+ type ServiceInstance<T> = T extends ServiceDef<infer S, any> ? S : T extends ServiceToken<infer S> ? S : never;
33
+ /**
34
+ * A mocked version of a service where all methods are mock functions
35
+ */
36
+ export type MockedService<T> = {
37
+ [K in keyof T]: T[K] extends (...args: infer A) => infer R ? NodeMock<(...args: A) => R> : T[K];
38
+ };
39
+ /**
40
+ * A spy wrapper that can be disposed to restore original methods
41
+ */
42
+ export interface SpyWrapper<T> extends Disposable {
43
+ /** The spied object with mock functions */
44
+ readonly spied: MockedService<T>;
45
+ /** The original object */
46
+ readonly original: T;
47
+ /** Reset all mock call tracking */
48
+ reset(): void;
49
+ /** Restore original methods (also called on dispose) */
50
+ restore(): void;
51
+ }
52
+ /**
53
+ * Create a mock implementation of a service.
54
+ * Uses node:test mock functions for tracking calls and assertions.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const mockRepo = mockService<typeof PlayerRepository>({
59
+ * get: mock.fn(() => Promise.resolve({ id: '1', name: 'Mock' })),
60
+ * find: mock.fn(() => Promise.resolve([])),
61
+ * });
62
+ * ```
63
+ */
64
+ export declare function mockService<T extends ServiceToken>(impl: Partial<MockedService<ServiceInstance<T>>>, name?: string): MockedService<ServiceInstance<T>>;
65
+ /**
66
+ * Create a spy wrapper around an existing service instance.
67
+ * All method calls are tracked while still calling the real implementation.
68
+ *
69
+ * Supports `using` for automatic cleanup:
70
+ * ```typescript
71
+ * using spy = spyOn(playerRepo);
72
+ * await spy.spied.get(Player.ref('123'));
73
+ * assertCallCount(spy.spied.get, 1);
74
+ * // Original methods restored when block exits
75
+ * ```
76
+ *
77
+ * @example Manual cleanup
78
+ * ```typescript
79
+ * const spy = spyOn(playerRepo);
80
+ * try {
81
+ * await spy.spied.get(Player.ref('123'));
82
+ * assertCallCount(spy.spied.get, 1);
83
+ * } finally {
84
+ * spy.restore();
85
+ * }
86
+ * ```
87
+ */
88
+ export declare function spyOn<T extends object>(instance: T): SpyWrapper<T>;
89
+ /**
90
+ * Create a spy that wraps an existing service instance.
91
+ * Returns just the spied object (simpler API, no auto-cleanup).
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const spiedRepo = spyService(playerRepo);
96
+ * await spiedRepo.get(Player.ref('123'));
97
+ * assertCallCount(spiedRepo.get, 1);
98
+ * ```
99
+ */
100
+ export declare function spyService<T extends object>(instance: T): MockedService<T>;
101
+ /**
102
+ * Create a mock function with a specific implementation.
103
+ * @param implementation Optional function to call when the mock is invoked
104
+ * @param name Optional name for debugging (shown in console.log)
105
+ */
106
+ export declare function mockFn<TArgs extends unknown[], TReturn>(implementation?: (...args: TArgs) => TReturn, name?: string): NodeMock<(...args: TArgs) => TReturn>;
107
+ /**
108
+ * Create a mock function that returns a resolved promise.
109
+ * @param value The value to resolve with
110
+ * @param name Optional name for debugging (shown in console.log)
111
+ */
112
+ export declare function mockResolves<T>(value: T, name?: string): NodeMock<(...args: unknown[]) => Promise<T>>;
113
+ /**
114
+ * Create a mock function that returns a rejected promise.
115
+ * @param error The error to reject with
116
+ * @param name Optional name for debugging (shown in console.log)
117
+ */
118
+ export declare function mockRejects(error: Error, name?: string): NodeMock<(...args: unknown[]) => Promise<never>>;
119
+ /**
120
+ * Create a mock function that throws an error.
121
+ * @param error The error to throw
122
+ * @param name Optional name for debugging (shown in console.log)
123
+ */
124
+ export declare function mockThrows(error: Error, name?: string): NodeMock<(...args: unknown[]) => never>;
125
+ /**
126
+ * Assert that a mock was called with specific arguments.
127
+ */
128
+ export declare function assertCalledWith<TArgs extends unknown[], TReturn>(mockFn: NodeMock<(...args: TArgs) => TReturn>, ...expectedArgs: TArgs): void;
129
+ /**
130
+ * Assert that a mock was called exactly n times.
131
+ */
132
+ export declare function assertCallCount<TArgs extends unknown[], TReturn>(mockFn: NodeMock<(...args: TArgs) => TReturn>, expected: number): void;
133
+ /**
134
+ * Assert that a mock was never called.
135
+ */
136
+ export declare function assertNotCalled<TArgs extends unknown[], TReturn>(mockFn: NodeMock<(...args: TArgs) => TReturn>): void;
137
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"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"}