@grest-ts/testkit 0.0.6 → 0.0.8
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/LICENSE +21 -21
- package/README.md +413 -413
- package/dist/src/runner/isolated-loader.mjs +91 -91
- package/dist/src/runner/worker-loader.mjs +49 -49
- package/dist/tsconfig.publish.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/src/GGBundleTest.ts +89 -89
- package/src/GGTest.ts +318 -318
- package/src/GGTestContext.ts +74 -74
- package/src/GGTestRunner.ts +308 -308
- package/src/GGTestRuntime.ts +265 -265
- package/src/GGTestRuntimeWorker.ts +159 -159
- package/src/GGTestSharedRef.ts +116 -116
- package/src/GGTestkitExtensionsDiscovery.ts +26 -26
- package/src/IGGLocalDiscoveryServer.ts +16 -16
- package/src/callOn/GGCallOnSelector.ts +61 -61
- package/src/callOn/GGContractClass.implement.ts +43 -43
- package/src/callOn/GGTestActionForLocatorOnCall.ts +134 -134
- package/src/callOn/TestableIPC.ts +81 -81
- package/src/callOn/callOn.ts +224 -224
- package/src/callOn/registerOnCallHandler.ts +123 -123
- package/src/index-node.ts +64 -64
- package/src/mockable/GGMockable.ts +22 -22
- package/src/mockable/GGMockableCall.ts +45 -45
- package/src/mockable/GGMockableIPC.ts +20 -20
- package/src/mockable/GGMockableInterceptor.ts +44 -44
- package/src/mockable/GGMockableInterceptorsServer.ts +69 -69
- package/src/mockable/mockable.ts +71 -71
- package/src/runner/InlineRunner.ts +47 -47
- package/src/runner/IsolatedRunner.ts +179 -179
- package/src/runner/RuntimeRunner.ts +15 -15
- package/src/runner/WorkerRunner.ts +179 -179
- package/src/runner/isolated-loader.mjs +91 -91
- package/src/runner/worker-loader.mjs +49 -49
- package/src/testers/GGCallInterceptor.ts +224 -224
- package/src/testers/GGMockWith.ts +92 -92
- package/src/testers/GGSpyWith.ts +115 -115
- package/src/testers/GGTestAction.ts +332 -332
- package/src/testers/GGTestComponent.ts +16 -16
- package/src/testers/GGTestSelector.ts +223 -223
- package/src/testers/IGGTestInterceptor.ts +10 -10
- package/src/testers/IGGTestWith.ts +15 -15
- package/src/testers/RuntimeSelector.ts +151 -151
- package/src/utils/GGExpectations.ts +78 -78
- package/src/utils/GGTestError.ts +36 -36
- package/src/utils/captureStack.ts +53 -53
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type {GGTestRunner} from "../GGTestRunner";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Interface for test components that can be registered with GGTestRunner.
|
|
5
|
-
* Components must accept GGTestRunner as their constructor argument.
|
|
6
|
-
*/
|
|
7
|
-
export interface GGTestComponent {
|
|
8
|
-
start?(): Promise<void>;
|
|
9
|
-
afterEach?(): Promise<void>;
|
|
10
|
-
teardown?(): Promise<void>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Constructor type for components. All components must accept GGTestRunner as constructor argument.
|
|
15
|
-
*/
|
|
16
|
-
export type GGTestComponentType<T extends GGTestComponent> = new (runner: GGTestRunner) => T;
|
|
1
|
+
import type {GGTestRunner} from "../GGTestRunner";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interface for test components that can be registered with GGTestRunner.
|
|
5
|
+
* Components must accept GGTestRunner as their constructor argument.
|
|
6
|
+
*/
|
|
7
|
+
export interface GGTestComponent {
|
|
8
|
+
start?(): Promise<void>;
|
|
9
|
+
afterEach?(): Promise<void>;
|
|
10
|
+
teardown?(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Constructor type for components. All components must accept GGTestRunner as constructor argument.
|
|
15
|
+
*/
|
|
16
|
+
export type GGTestComponentType<T extends GGTestComponent> = new (runner: GGTestRunner) => T;
|
|
@@ -1,223 +1,223 @@
|
|
|
1
|
-
import {RuntimeConstructor, RuntimeResult, Selector, SelectorExtensions, ObjectResult, StartResult, RuntimeInput} from "./RuntimeSelector";
|
|
2
|
-
import {GGTestRuntime} from "../GGTestRuntime";
|
|
3
|
-
import type {GGTestRunner} from "../GGTestRunner";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Internal implementation class for Selector.
|
|
7
|
-
* Works with GGTestRuntime instances directly.
|
|
8
|
-
*/
|
|
9
|
-
export class GGTestSelector<T extends RuntimeConstructor[]> {
|
|
10
|
-
|
|
11
|
-
private static readonly extensions = new Map<string, typeof GGTestSelectorExtension>();
|
|
12
|
-
|
|
13
|
-
public readonly runtimes: GGTestRuntime[];
|
|
14
|
-
private readonly extensionCache = new Map<string, unknown>();
|
|
15
|
-
|
|
16
|
-
constructor(runtimes: GGTestRuntime[]) {
|
|
17
|
-
this.runtimes = runtimes;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public get length(): number {
|
|
21
|
-
return this.runtimes.length;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public static addExtension(factory: typeof GGTestSelectorExtension & { PROPERTY_NAME: string }): void {
|
|
25
|
-
if (this.extensions.has(factory.PROPERTY_NAME)) {
|
|
26
|
-
throw new Error("Extension with name '" + factory.PROPERTY_NAME + "' is already registered!")
|
|
27
|
-
}
|
|
28
|
-
this.extensions.set(factory.PROPERTY_NAME, factory);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public static hasExtension(name: string): boolean {
|
|
32
|
-
return this.extensions.has(name);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public getExtension<K extends keyof SelectorExtensions<T>>(name: K): SelectorExtensions<T>[K] {
|
|
36
|
-
const cached = this.extensionCache.get(name as string);
|
|
37
|
-
if (cached !== undefined) {
|
|
38
|
-
return cached as SelectorExtensions<T>[K];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const extension = GGTestSelector.extensions.get(name);
|
|
42
|
-
if (!extension) {
|
|
43
|
-
throw new Error(`Extension '${String(name)}' is not registered. ` +
|
|
44
|
-
`Make sure the module providing this extension is imported.`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const extensionInstance = new extension(this.runtimes);
|
|
48
|
-
this.extensionCache.set(name as string, extensionInstance);
|
|
49
|
-
return extensionInstance as SelectorExtensions<T>[K];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Stop all runtimes in this selector.
|
|
54
|
-
*/
|
|
55
|
-
public async stop(): Promise<void> {
|
|
56
|
-
for (const runtime of this.runtimes) {
|
|
57
|
-
await runtime.stop();
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Shutdown all runtimes in this selector.
|
|
63
|
-
*/
|
|
64
|
-
public async shutdown(): Promise<void> {
|
|
65
|
-
for (const runtime of this.runtimes) {
|
|
66
|
-
await runtime.shutdown();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export class GGTestSelectorExtension {
|
|
72
|
-
|
|
73
|
-
protected readonly runner: GGTestRunner
|
|
74
|
-
|
|
75
|
-
constructor(protected readonly runtimes: GGTestRuntime[]) {
|
|
76
|
-
this.runner = this.runtimes[0]?.runner
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
protected async forEachParallel(callback: (runtime: GGTestRuntime) => Promise<void>): Promise<void> {
|
|
80
|
-
const results = await Promise.allSettled(
|
|
81
|
-
this.runtimes.map(runtime => callback(runtime))
|
|
82
|
-
);
|
|
83
|
-
const errors = results
|
|
84
|
-
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
85
|
-
.map(r => r.reason);
|
|
86
|
-
|
|
87
|
-
if (errors.length > 0) {
|
|
88
|
-
throw new AggregateError(errors, `${errors.length} runtime(s) failed`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Create a proxied Selector that supports:
|
|
95
|
-
* - Indexed access: selector[0]
|
|
96
|
-
* - Extension access: selector.config, selector.logs
|
|
97
|
-
* - Lifecycle methods: selector.stop(), selector.shutdown()
|
|
98
|
-
* - Standard properties: selector.runtimes, selector.length
|
|
99
|
-
*/
|
|
100
|
-
export function createSelector<T extends RuntimeConstructor[]>(runtimes: GGTestRuntime[]): Selector<T> {
|
|
101
|
-
const impl = new GGTestSelector<T>(runtimes);
|
|
102
|
-
|
|
103
|
-
return new Proxy(impl as unknown as Selector<T>, {
|
|
104
|
-
get(target, prop) {
|
|
105
|
-
const implTarget = target as unknown as GGTestSelector<T>;
|
|
106
|
-
|
|
107
|
-
// Handle numeric index access: selector[0]
|
|
108
|
-
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
|
|
109
|
-
const index = parseInt(prop, 10);
|
|
110
|
-
if (index >= 0 && index < implTarget.runtimes.length) {
|
|
111
|
-
return createSelector([implTarget.runtimes[index]]);
|
|
112
|
-
}
|
|
113
|
-
return undefined;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Handle extension access: selector.config, selector.logs, etc.
|
|
117
|
-
if (typeof prop === 'string' && GGTestSelector.hasExtension(prop)) {
|
|
118
|
-
return implTarget.getExtension(prop as keyof SelectorExtensions<T>);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Handle methods and properties from impl
|
|
122
|
-
return Reflect.get(implTarget, prop);
|
|
123
|
-
}
|
|
124
|
-
}) as Selector<T>;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ============================================================================
|
|
128
|
-
// Factory functions for different input shapes
|
|
129
|
-
// ============================================================================
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Create result based on input shape.
|
|
133
|
-
* - Single runtime → Selector
|
|
134
|
-
* - Array of runtimes → Selector
|
|
135
|
-
* - Object → ObjectResult with named selectors
|
|
136
|
-
*/
|
|
137
|
-
export function createStartResult<T extends RuntimeInput>(
|
|
138
|
-
input: T,
|
|
139
|
-
runtimes: GGTestRuntime[]
|
|
140
|
-
): StartResult<T> {
|
|
141
|
-
// Object input: { main: MainRuntime, sub: SubRuntime }
|
|
142
|
-
if (isObjectInput(input)) {
|
|
143
|
-
return createObjectResult(input, runtimes) as StartResult<T>;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Array or single runtime → Selector
|
|
147
|
-
return createSelector(runtimes) as StartResult<T>;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Check if input is an object (not a constructor or array).
|
|
152
|
-
*/
|
|
153
|
-
function isObjectInput(input: RuntimeInput): input is Record<string, RuntimeConstructor | RuntimeConstructor[]> {
|
|
154
|
-
return typeof input === 'object' && !Array.isArray(input) && !('NAME' in input);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Create ObjectResult for object input.
|
|
159
|
-
*/
|
|
160
|
-
function createObjectResult<T extends Record<string, RuntimeConstructor | RuntimeConstructor[]>>(
|
|
161
|
-
input: T,
|
|
162
|
-
runtimes: GGTestRuntime[]
|
|
163
|
-
): ObjectResult<T> {
|
|
164
|
-
const result: Record<string, Selector<any>> = {};
|
|
165
|
-
|
|
166
|
-
// Group runtimes by the key they were registered under
|
|
167
|
-
// We need to track which runtimes belong to which key
|
|
168
|
-
for (const [key, value] of Object.entries(input)) {
|
|
169
|
-
const constructors = Array.isArray(value) ? value : [value];
|
|
170
|
-
const names = constructors.map(c => c.NAME);
|
|
171
|
-
const keyRuntimes = runtimes.filter(r => names.includes(r.name));
|
|
172
|
-
result[key] = createSelector(keyRuntimes);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Add stop/shutdown that affects all runtimes
|
|
176
|
-
(result as any).stop = async () => {
|
|
177
|
-
for (const runtime of runtimes) {
|
|
178
|
-
await runtime.stop();
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
(result as any).shutdown = async () => {
|
|
183
|
-
for (const runtime of runtimes) {
|
|
184
|
-
await runtime.shutdown();
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
return result as ObjectResult<T>;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// ============================================================================
|
|
192
|
-
// Legacy factory (for backwards compatibility)
|
|
193
|
-
// ============================================================================
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* @deprecated Use createStartResult instead.
|
|
197
|
-
* Create a RuntimeResult for accessing runtimes via get() method.
|
|
198
|
-
*/
|
|
199
|
-
export function createRuntimeSelector<T extends RuntimeConstructor[]>(runtimes: GGTestRuntime[]): RuntimeResult<T> {
|
|
200
|
-
return {
|
|
201
|
-
get(runtimeConstructor: RuntimeConstructor): Selector<any> {
|
|
202
|
-
const name = runtimeConstructor.NAME;
|
|
203
|
-
const filtered = runtimes.filter(r => r.name === name);
|
|
204
|
-
return createSelector(filtered);
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
all(): Selector<any> {
|
|
208
|
-
return createSelector(runtimes);
|
|
209
|
-
},
|
|
210
|
-
|
|
211
|
-
async stop(): Promise<void> {
|
|
212
|
-
for (const runtime of runtimes) {
|
|
213
|
-
await runtime.stop();
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
|
|
217
|
-
async shutdown(): Promise<void> {
|
|
218
|
-
for (const runtime of runtimes) {
|
|
219
|
-
await runtime.shutdown();
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
} as RuntimeResult<T>;
|
|
223
|
-
}
|
|
1
|
+
import {RuntimeConstructor, RuntimeResult, Selector, SelectorExtensions, ObjectResult, StartResult, RuntimeInput} from "./RuntimeSelector";
|
|
2
|
+
import {GGTestRuntime} from "../GGTestRuntime";
|
|
3
|
+
import type {GGTestRunner} from "../GGTestRunner";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Internal implementation class for Selector.
|
|
7
|
+
* Works with GGTestRuntime instances directly.
|
|
8
|
+
*/
|
|
9
|
+
export class GGTestSelector<T extends RuntimeConstructor[]> {
|
|
10
|
+
|
|
11
|
+
private static readonly extensions = new Map<string, typeof GGTestSelectorExtension>();
|
|
12
|
+
|
|
13
|
+
public readonly runtimes: GGTestRuntime[];
|
|
14
|
+
private readonly extensionCache = new Map<string, unknown>();
|
|
15
|
+
|
|
16
|
+
constructor(runtimes: GGTestRuntime[]) {
|
|
17
|
+
this.runtimes = runtimes;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public get length(): number {
|
|
21
|
+
return this.runtimes.length;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static addExtension(factory: typeof GGTestSelectorExtension & { PROPERTY_NAME: string }): void {
|
|
25
|
+
if (this.extensions.has(factory.PROPERTY_NAME)) {
|
|
26
|
+
throw new Error("Extension with name '" + factory.PROPERTY_NAME + "' is already registered!")
|
|
27
|
+
}
|
|
28
|
+
this.extensions.set(factory.PROPERTY_NAME, factory);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public static hasExtension(name: string): boolean {
|
|
32
|
+
return this.extensions.has(name);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public getExtension<K extends keyof SelectorExtensions<T>>(name: K): SelectorExtensions<T>[K] {
|
|
36
|
+
const cached = this.extensionCache.get(name as string);
|
|
37
|
+
if (cached !== undefined) {
|
|
38
|
+
return cached as SelectorExtensions<T>[K];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const extension = GGTestSelector.extensions.get(name);
|
|
42
|
+
if (!extension) {
|
|
43
|
+
throw new Error(`Extension '${String(name)}' is not registered. ` +
|
|
44
|
+
`Make sure the module providing this extension is imported.`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const extensionInstance = new extension(this.runtimes);
|
|
48
|
+
this.extensionCache.set(name as string, extensionInstance);
|
|
49
|
+
return extensionInstance as SelectorExtensions<T>[K];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Stop all runtimes in this selector.
|
|
54
|
+
*/
|
|
55
|
+
public async stop(): Promise<void> {
|
|
56
|
+
for (const runtime of this.runtimes) {
|
|
57
|
+
await runtime.stop();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Shutdown all runtimes in this selector.
|
|
63
|
+
*/
|
|
64
|
+
public async shutdown(): Promise<void> {
|
|
65
|
+
for (const runtime of this.runtimes) {
|
|
66
|
+
await runtime.shutdown();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class GGTestSelectorExtension {
|
|
72
|
+
|
|
73
|
+
protected readonly runner: GGTestRunner
|
|
74
|
+
|
|
75
|
+
constructor(protected readonly runtimes: GGTestRuntime[]) {
|
|
76
|
+
this.runner = this.runtimes[0]?.runner
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected async forEachParallel(callback: (runtime: GGTestRuntime) => Promise<void>): Promise<void> {
|
|
80
|
+
const results = await Promise.allSettled(
|
|
81
|
+
this.runtimes.map(runtime => callback(runtime))
|
|
82
|
+
);
|
|
83
|
+
const errors = results
|
|
84
|
+
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
85
|
+
.map(r => r.reason);
|
|
86
|
+
|
|
87
|
+
if (errors.length > 0) {
|
|
88
|
+
throw new AggregateError(errors, `${errors.length} runtime(s) failed`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a proxied Selector that supports:
|
|
95
|
+
* - Indexed access: selector[0]
|
|
96
|
+
* - Extension access: selector.config, selector.logs
|
|
97
|
+
* - Lifecycle methods: selector.stop(), selector.shutdown()
|
|
98
|
+
* - Standard properties: selector.runtimes, selector.length
|
|
99
|
+
*/
|
|
100
|
+
export function createSelector<T extends RuntimeConstructor[]>(runtimes: GGTestRuntime[]): Selector<T> {
|
|
101
|
+
const impl = new GGTestSelector<T>(runtimes);
|
|
102
|
+
|
|
103
|
+
return new Proxy(impl as unknown as Selector<T>, {
|
|
104
|
+
get(target, prop) {
|
|
105
|
+
const implTarget = target as unknown as GGTestSelector<T>;
|
|
106
|
+
|
|
107
|
+
// Handle numeric index access: selector[0]
|
|
108
|
+
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
|
|
109
|
+
const index = parseInt(prop, 10);
|
|
110
|
+
if (index >= 0 && index < implTarget.runtimes.length) {
|
|
111
|
+
return createSelector([implTarget.runtimes[index]]);
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Handle extension access: selector.config, selector.logs, etc.
|
|
117
|
+
if (typeof prop === 'string' && GGTestSelector.hasExtension(prop)) {
|
|
118
|
+
return implTarget.getExtension(prop as keyof SelectorExtensions<T>);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Handle methods and properties from impl
|
|
122
|
+
return Reflect.get(implTarget, prop);
|
|
123
|
+
}
|
|
124
|
+
}) as Selector<T>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// Factory functions for different input shapes
|
|
129
|
+
// ============================================================================
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Create result based on input shape.
|
|
133
|
+
* - Single runtime → Selector
|
|
134
|
+
* - Array of runtimes → Selector
|
|
135
|
+
* - Object → ObjectResult with named selectors
|
|
136
|
+
*/
|
|
137
|
+
export function createStartResult<T extends RuntimeInput>(
|
|
138
|
+
input: T,
|
|
139
|
+
runtimes: GGTestRuntime[]
|
|
140
|
+
): StartResult<T> {
|
|
141
|
+
// Object input: { main: MainRuntime, sub: SubRuntime }
|
|
142
|
+
if (isObjectInput(input)) {
|
|
143
|
+
return createObjectResult(input, runtimes) as StartResult<T>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Array or single runtime → Selector
|
|
147
|
+
return createSelector(runtimes) as StartResult<T>;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Check if input is an object (not a constructor or array).
|
|
152
|
+
*/
|
|
153
|
+
function isObjectInput(input: RuntimeInput): input is Record<string, RuntimeConstructor | RuntimeConstructor[]> {
|
|
154
|
+
return typeof input === 'object' && !Array.isArray(input) && !('NAME' in input);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Create ObjectResult for object input.
|
|
159
|
+
*/
|
|
160
|
+
function createObjectResult<T extends Record<string, RuntimeConstructor | RuntimeConstructor[]>>(
|
|
161
|
+
input: T,
|
|
162
|
+
runtimes: GGTestRuntime[]
|
|
163
|
+
): ObjectResult<T> {
|
|
164
|
+
const result: Record<string, Selector<any>> = {};
|
|
165
|
+
|
|
166
|
+
// Group runtimes by the key they were registered under
|
|
167
|
+
// We need to track which runtimes belong to which key
|
|
168
|
+
for (const [key, value] of Object.entries(input)) {
|
|
169
|
+
const constructors = Array.isArray(value) ? value : [value];
|
|
170
|
+
const names = constructors.map(c => c.NAME);
|
|
171
|
+
const keyRuntimes = runtimes.filter(r => names.includes(r.name));
|
|
172
|
+
result[key] = createSelector(keyRuntimes);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Add stop/shutdown that affects all runtimes
|
|
176
|
+
(result as any).stop = async () => {
|
|
177
|
+
for (const runtime of runtimes) {
|
|
178
|
+
await runtime.stop();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
(result as any).shutdown = async () => {
|
|
183
|
+
for (const runtime of runtimes) {
|
|
184
|
+
await runtime.shutdown();
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
return result as ObjectResult<T>;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// Legacy factory (for backwards compatibility)
|
|
193
|
+
// ============================================================================
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @deprecated Use createStartResult instead.
|
|
197
|
+
* Create a RuntimeResult for accessing runtimes via get() method.
|
|
198
|
+
*/
|
|
199
|
+
export function createRuntimeSelector<T extends RuntimeConstructor[]>(runtimes: GGTestRuntime[]): RuntimeResult<T> {
|
|
200
|
+
return {
|
|
201
|
+
get(runtimeConstructor: RuntimeConstructor): Selector<any> {
|
|
202
|
+
const name = runtimeConstructor.NAME;
|
|
203
|
+
const filtered = runtimes.filter(r => r.name === name);
|
|
204
|
+
return createSelector(filtered);
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
all(): Selector<any> {
|
|
208
|
+
return createSelector(runtimes);
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
async stop(): Promise<void> {
|
|
212
|
+
for (const runtime of runtimes) {
|
|
213
|
+
await runtime.stop();
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
async shutdown(): Promise<void> {
|
|
218
|
+
for (const runtime of runtimes) {
|
|
219
|
+
await runtime.shutdown();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} as RuntimeResult<T>;
|
|
223
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export interface IGGTestInterceptor {
|
|
2
|
-
register(): void | Promise<void>;
|
|
3
|
-
|
|
4
|
-
unregister(): void | Promise<void>;
|
|
5
|
-
|
|
6
|
-
validate(): void | Promise<void>;
|
|
7
|
-
|
|
8
|
-
getMockValidationError(): Error | undefined;
|
|
9
|
-
|
|
10
|
-
isCalled(): boolean;
|
|
1
|
+
export interface IGGTestInterceptor {
|
|
2
|
+
register(): void | Promise<void>;
|
|
3
|
+
|
|
4
|
+
unregister(): void | Promise<void>;
|
|
5
|
+
|
|
6
|
+
validate(): void | Promise<void>;
|
|
7
|
+
|
|
8
|
+
getMockValidationError(): Error | undefined;
|
|
9
|
+
|
|
10
|
+
isCalled(): boolean;
|
|
11
11
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {IGGTestInterceptor} from "./IGGTestInterceptor";
|
|
2
|
-
|
|
3
|
-
export interface IGGTestWith {
|
|
4
|
-
createInterceptor(): IGGTestInterceptor;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Returns true if this expectation requires async processing and must be used with `.waitFor()`.
|
|
8
|
-
* When true, using with `.with()` will throw an error guiding the developer to use `.waitFor()`.
|
|
9
|
-
*
|
|
10
|
-
* Example: SQS message processing is async (happens after HTTP response), so SQS
|
|
11
|
-
* interceptors require `.waitFor()`.
|
|
12
|
-
*/
|
|
13
|
-
requiresWaitFor?(): boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
1
|
+
import {IGGTestInterceptor} from "./IGGTestInterceptor";
|
|
2
|
+
|
|
3
|
+
export interface IGGTestWith {
|
|
4
|
+
createInterceptor(): IGGTestInterceptor;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns true if this expectation requires async processing and must be used with `.waitFor()`.
|
|
8
|
+
* When true, using with `.with()` will throw an error guiding the developer to use `.waitFor()`.
|
|
9
|
+
*
|
|
10
|
+
* Example: SQS message processing is async (happens after HTTP response), so SQS
|
|
11
|
+
* interceptors require `.waitFor()`.
|
|
12
|
+
*/
|
|
13
|
+
requiresWaitFor?(): boolean;
|
|
14
|
+
}
|
|
15
|
+
|