@grest-ts/testkit 0.0.5 → 0.0.7
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 +418 -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 +12 -12
- 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,224 +1,224 @@
|
|
|
1
|
-
import type {GGTestRunner} from "../GGTestRunner";
|
|
2
|
-
import {GGExpectations} from "../utils/GGExpectations";
|
|
3
|
-
import {GGTestError} from "../utils/GGTestError";
|
|
4
|
-
import {GGLog} from "@grest-ts/logger";
|
|
5
|
-
|
|
6
|
-
import {IGGTestInterceptor} from "./IGGTestInterceptor";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Configuration for creating an interceptor.
|
|
10
|
-
* Used by both mock and spy modes - passThrough determines behavior.
|
|
11
|
-
*/
|
|
12
|
-
export interface GGCallInterceptorConfig {
|
|
13
|
-
definedInSourceFile: string;
|
|
14
|
-
sleep: number;
|
|
15
|
-
times: number;
|
|
16
|
-
passThrough: boolean;
|
|
17
|
-
inputExpectations?: GGExpectations<any>;
|
|
18
|
-
outputExpectations?: GGExpectations<any>;
|
|
19
|
-
returnData?: any;
|
|
20
|
-
expectError?: any;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Unified base class for mock/spy interceptors.
|
|
25
|
-
*
|
|
26
|
-
* - Mock mode (passThrough=false): validates input, returns fake data
|
|
27
|
-
* - Spy mode (passThrough=true): validates input, calls through, validates output
|
|
28
|
-
*
|
|
29
|
-
* Transport-specific subclasses provide register/unregister/getKey.
|
|
30
|
-
*/
|
|
31
|
-
export abstract class GGCallInterceptor implements IGGTestInterceptor {
|
|
32
|
-
|
|
33
|
-
protected readonly test: GGTestRunner;
|
|
34
|
-
private readonly definedInSourceFile: string;
|
|
35
|
-
private readonly _sleep: number;
|
|
36
|
-
private readonly times: number;
|
|
37
|
-
public readonly passThrough: boolean;
|
|
38
|
-
private readonly inputExpectations?: GGExpectations<any>;
|
|
39
|
-
private readonly outputExpectations?: GGExpectations<any>;
|
|
40
|
-
private readonly returnData?: any;
|
|
41
|
-
|
|
42
|
-
private noOfTimesCalled = 0;
|
|
43
|
-
private isRegistered = false;
|
|
44
|
-
private validationError: Error | undefined;
|
|
45
|
-
|
|
46
|
-
protected constructor(test: GGTestRunner, config: GGCallInterceptorConfig) {
|
|
47
|
-
this.test = test;
|
|
48
|
-
this.definedInSourceFile = config.definedInSourceFile;
|
|
49
|
-
this._sleep = config.sleep;
|
|
50
|
-
this.times = config.times;
|
|
51
|
-
this.passThrough = config.passThrough;
|
|
52
|
-
this.inputExpectations = config.inputExpectations;
|
|
53
|
-
this.outputExpectations = config.outputExpectations;
|
|
54
|
-
this.returnData = config.returnData;
|
|
55
|
-
if (this.passThrough) {
|
|
56
|
-
if (this.returnData !== undefined) {
|
|
57
|
-
throw new Error("Spy can't have returnData! It calls through and returns what ever it receives!")
|
|
58
|
-
}
|
|
59
|
-
} else {
|
|
60
|
-
if (this.outputExpectations) {
|
|
61
|
-
throw new Error("Mocks can't have output expectations, they return the data that is defined in the test!")
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// -------------------------------------------
|
|
67
|
-
// Abstract - transport subclass provides
|
|
68
|
-
// -------------------------------------------
|
|
69
|
-
|
|
70
|
-
public abstract getKey(): string;
|
|
71
|
-
|
|
72
|
-
protected abstract doRegister(): void;
|
|
73
|
-
|
|
74
|
-
protected abstract doUnregister(): void;
|
|
75
|
-
|
|
76
|
-
protected abstract parseResponseData(result: any): any;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Transform request body before checking expectations.
|
|
80
|
-
* Override to extract/transform the input for validation.
|
|
81
|
-
* Default: returns body unchanged.
|
|
82
|
-
*/
|
|
83
|
-
protected transformInput(body: any): any {
|
|
84
|
-
return body;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// -------------------------------------------
|
|
88
|
-
// Registration lifecycle
|
|
89
|
-
// -------------------------------------------
|
|
90
|
-
|
|
91
|
-
public register(): void {
|
|
92
|
-
if (this.isRegistered) {
|
|
93
|
-
throw new Error("Interceptor already registered, this should not happen...");
|
|
94
|
-
}
|
|
95
|
-
if (this.noOfTimesCalled > 0) {
|
|
96
|
-
throw new Error("Should not register interceptor multiple times. Something is wrong...");
|
|
97
|
-
}
|
|
98
|
-
this.isRegistered = true;
|
|
99
|
-
|
|
100
|
-
const mode = this.passThrough ? "spy" : "mock";
|
|
101
|
-
GGLog.debug(this, `Add ${mode} interceptor [${this.getKey()}]`);
|
|
102
|
-
|
|
103
|
-
this.doRegister();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public unregister(): void {
|
|
107
|
-
if (!this.isRegistered) {
|
|
108
|
-
throw new Error("Interceptor is not registered, but trying to unregister. This should not happen...");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const mode = this.passThrough ? "spy" : "mock";
|
|
112
|
-
GGLog.debug(this, `Remove ${mode} interceptor [${this.getKey()}]`);
|
|
113
|
-
|
|
114
|
-
this.doUnregister();
|
|
115
|
-
this.isRegistered = false;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// -------------------------------------------
|
|
119
|
-
// Request/Response handling
|
|
120
|
-
// -------------------------------------------
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Handle incoming request.
|
|
124
|
-
* - Validates input expectations
|
|
125
|
-
* - For mock: returns configured returnData
|
|
126
|
-
* - For spy: returns undefined (signal to pass through)
|
|
127
|
-
*/
|
|
128
|
-
public async onRequest(body: any): Promise<any> {
|
|
129
|
-
try {
|
|
130
|
-
this.checkNoOfTimesCalled();
|
|
131
|
-
const transformed = this.transformInput(body);
|
|
132
|
-
this.inputExpectations?.check(transformed);
|
|
133
|
-
} catch (error: any) {
|
|
134
|
-
const errorType = this.passThrough ? "SPY_REQUEST_VALIDATION_FAILED" : "MOCK_VALIDATION_FAILED";
|
|
135
|
-
this.setMockValidationError(error, errorType);
|
|
136
|
-
throw error;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (!this.passThrough) {
|
|
140
|
-
await this.sleepIfNeeded();
|
|
141
|
-
return this.returnData;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return undefined;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Handle response (spy mode only).
|
|
149
|
-
* Called after pass-through completes with the real response.
|
|
150
|
-
* Parses response via transport-specific method, then validates.
|
|
151
|
-
*/
|
|
152
|
-
public async onResponse(result: any): Promise<void> {
|
|
153
|
-
if (!this.passThrough) {
|
|
154
|
-
throw new Error("onResponse called in mock mode! Mocks don't have responses as they create fake responses! This is a coding error if you reach here!");
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
const data = this.parseResponseData(result);
|
|
158
|
-
this.outputExpectations?.check(data);
|
|
159
|
-
await this.sleepIfNeeded();
|
|
160
|
-
} catch (error: any) {
|
|
161
|
-
this.setMockValidationError(error, "SPY_RESPONSE_VALIDATION_FAILED");
|
|
162
|
-
throw error;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// -------------------------------------------
|
|
167
|
-
// Validation after test completes
|
|
168
|
-
// -------------------------------------------
|
|
169
|
-
|
|
170
|
-
public validate(): void {
|
|
171
|
-
if (this.noOfTimesCalled === 0 && this.times > 0) {
|
|
172
|
-
throw new GGTestError({
|
|
173
|
-
test: "Expected to be called, but was not.",
|
|
174
|
-
expected: "To be called",
|
|
175
|
-
received: "-",
|
|
176
|
-
sourceFile: this.definedInSourceFile
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
public getMockValidationError(): Error | undefined {
|
|
182
|
-
return this.validationError;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
public isCalled(): boolean {
|
|
186
|
-
return this.noOfTimesCalled > 0;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// -------------------------------------------
|
|
190
|
-
// Helpers
|
|
191
|
-
// -------------------------------------------
|
|
192
|
-
|
|
193
|
-
protected async sleepIfNeeded(): Promise<void> {
|
|
194
|
-
if (this._sleep) {
|
|
195
|
-
await new Promise(resolve => setTimeout(resolve, this._sleep));
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
protected checkNoOfTimesCalled(): void {
|
|
200
|
-
this.noOfTimesCalled++;
|
|
201
|
-
if (this.noOfTimesCalled > this.times) {
|
|
202
|
-
throw new GGTestError({
|
|
203
|
-
context: `[${this.getKey()}]`,
|
|
204
|
-
test: "Interceptor called too many times!",
|
|
205
|
-
expected: `Called ${this.times} time(s)`,
|
|
206
|
-
received: `Called ${this.noOfTimesCalled} times(s)`,
|
|
207
|
-
sourceFile: this.definedInSourceFile
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
protected setMockValidationError(originalError: Error, type: string): void {
|
|
213
|
-
const messagePrefix = `[${this.getKey()}] ${type}`;
|
|
214
|
-
GGLog.error(this, messagePrefix, originalError);
|
|
215
|
-
|
|
216
|
-
(originalError as any).isMockValidationError = true;
|
|
217
|
-
|
|
218
|
-
originalError.message = messagePrefix + "\n" + originalError.message;
|
|
219
|
-
const lines = originalError.stack?.split("\n") || [];
|
|
220
|
-
lines.shift();
|
|
221
|
-
originalError.stack = lines.join("\n");
|
|
222
|
-
this.validationError = originalError;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
1
|
+
import type {GGTestRunner} from "../GGTestRunner";
|
|
2
|
+
import {GGExpectations} from "../utils/GGExpectations";
|
|
3
|
+
import {GGTestError} from "../utils/GGTestError";
|
|
4
|
+
import {GGLog} from "@grest-ts/logger";
|
|
5
|
+
|
|
6
|
+
import {IGGTestInterceptor} from "./IGGTestInterceptor";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for creating an interceptor.
|
|
10
|
+
* Used by both mock and spy modes - passThrough determines behavior.
|
|
11
|
+
*/
|
|
12
|
+
export interface GGCallInterceptorConfig {
|
|
13
|
+
definedInSourceFile: string;
|
|
14
|
+
sleep: number;
|
|
15
|
+
times: number;
|
|
16
|
+
passThrough: boolean;
|
|
17
|
+
inputExpectations?: GGExpectations<any>;
|
|
18
|
+
outputExpectations?: GGExpectations<any>;
|
|
19
|
+
returnData?: any;
|
|
20
|
+
expectError?: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Unified base class for mock/spy interceptors.
|
|
25
|
+
*
|
|
26
|
+
* - Mock mode (passThrough=false): validates input, returns fake data
|
|
27
|
+
* - Spy mode (passThrough=true): validates input, calls through, validates output
|
|
28
|
+
*
|
|
29
|
+
* Transport-specific subclasses provide register/unregister/getKey.
|
|
30
|
+
*/
|
|
31
|
+
export abstract class GGCallInterceptor implements IGGTestInterceptor {
|
|
32
|
+
|
|
33
|
+
protected readonly test: GGTestRunner;
|
|
34
|
+
private readonly definedInSourceFile: string;
|
|
35
|
+
private readonly _sleep: number;
|
|
36
|
+
private readonly times: number;
|
|
37
|
+
public readonly passThrough: boolean;
|
|
38
|
+
private readonly inputExpectations?: GGExpectations<any>;
|
|
39
|
+
private readonly outputExpectations?: GGExpectations<any>;
|
|
40
|
+
private readonly returnData?: any;
|
|
41
|
+
|
|
42
|
+
private noOfTimesCalled = 0;
|
|
43
|
+
private isRegistered = false;
|
|
44
|
+
private validationError: Error | undefined;
|
|
45
|
+
|
|
46
|
+
protected constructor(test: GGTestRunner, config: GGCallInterceptorConfig) {
|
|
47
|
+
this.test = test;
|
|
48
|
+
this.definedInSourceFile = config.definedInSourceFile;
|
|
49
|
+
this._sleep = config.sleep;
|
|
50
|
+
this.times = config.times;
|
|
51
|
+
this.passThrough = config.passThrough;
|
|
52
|
+
this.inputExpectations = config.inputExpectations;
|
|
53
|
+
this.outputExpectations = config.outputExpectations;
|
|
54
|
+
this.returnData = config.returnData;
|
|
55
|
+
if (this.passThrough) {
|
|
56
|
+
if (this.returnData !== undefined) {
|
|
57
|
+
throw new Error("Spy can't have returnData! It calls through and returns what ever it receives!")
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
if (this.outputExpectations) {
|
|
61
|
+
throw new Error("Mocks can't have output expectations, they return the data that is defined in the test!")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// -------------------------------------------
|
|
67
|
+
// Abstract - transport subclass provides
|
|
68
|
+
// -------------------------------------------
|
|
69
|
+
|
|
70
|
+
public abstract getKey(): string;
|
|
71
|
+
|
|
72
|
+
protected abstract doRegister(): void;
|
|
73
|
+
|
|
74
|
+
protected abstract doUnregister(): void;
|
|
75
|
+
|
|
76
|
+
protected abstract parseResponseData(result: any): any;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Transform request body before checking expectations.
|
|
80
|
+
* Override to extract/transform the input for validation.
|
|
81
|
+
* Default: returns body unchanged.
|
|
82
|
+
*/
|
|
83
|
+
protected transformInput(body: any): any {
|
|
84
|
+
return body;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// -------------------------------------------
|
|
88
|
+
// Registration lifecycle
|
|
89
|
+
// -------------------------------------------
|
|
90
|
+
|
|
91
|
+
public register(): void {
|
|
92
|
+
if (this.isRegistered) {
|
|
93
|
+
throw new Error("Interceptor already registered, this should not happen...");
|
|
94
|
+
}
|
|
95
|
+
if (this.noOfTimesCalled > 0) {
|
|
96
|
+
throw new Error("Should not register interceptor multiple times. Something is wrong...");
|
|
97
|
+
}
|
|
98
|
+
this.isRegistered = true;
|
|
99
|
+
|
|
100
|
+
const mode = this.passThrough ? "spy" : "mock";
|
|
101
|
+
GGLog.debug(this, `Add ${mode} interceptor [${this.getKey()}]`);
|
|
102
|
+
|
|
103
|
+
this.doRegister();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public unregister(): void {
|
|
107
|
+
if (!this.isRegistered) {
|
|
108
|
+
throw new Error("Interceptor is not registered, but trying to unregister. This should not happen...");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const mode = this.passThrough ? "spy" : "mock";
|
|
112
|
+
GGLog.debug(this, `Remove ${mode} interceptor [${this.getKey()}]`);
|
|
113
|
+
|
|
114
|
+
this.doUnregister();
|
|
115
|
+
this.isRegistered = false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// -------------------------------------------
|
|
119
|
+
// Request/Response handling
|
|
120
|
+
// -------------------------------------------
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Handle incoming request.
|
|
124
|
+
* - Validates input expectations
|
|
125
|
+
* - For mock: returns configured returnData
|
|
126
|
+
* - For spy: returns undefined (signal to pass through)
|
|
127
|
+
*/
|
|
128
|
+
public async onRequest(body: any): Promise<any> {
|
|
129
|
+
try {
|
|
130
|
+
this.checkNoOfTimesCalled();
|
|
131
|
+
const transformed = this.transformInput(body);
|
|
132
|
+
this.inputExpectations?.check(transformed);
|
|
133
|
+
} catch (error: any) {
|
|
134
|
+
const errorType = this.passThrough ? "SPY_REQUEST_VALIDATION_FAILED" : "MOCK_VALIDATION_FAILED";
|
|
135
|
+
this.setMockValidationError(error, errorType);
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!this.passThrough) {
|
|
140
|
+
await this.sleepIfNeeded();
|
|
141
|
+
return this.returnData;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Handle response (spy mode only).
|
|
149
|
+
* Called after pass-through completes with the real response.
|
|
150
|
+
* Parses response via transport-specific method, then validates.
|
|
151
|
+
*/
|
|
152
|
+
public async onResponse(result: any): Promise<void> {
|
|
153
|
+
if (!this.passThrough) {
|
|
154
|
+
throw new Error("onResponse called in mock mode! Mocks don't have responses as they create fake responses! This is a coding error if you reach here!");
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const data = this.parseResponseData(result);
|
|
158
|
+
this.outputExpectations?.check(data);
|
|
159
|
+
await this.sleepIfNeeded();
|
|
160
|
+
} catch (error: any) {
|
|
161
|
+
this.setMockValidationError(error, "SPY_RESPONSE_VALIDATION_FAILED");
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// -------------------------------------------
|
|
167
|
+
// Validation after test completes
|
|
168
|
+
// -------------------------------------------
|
|
169
|
+
|
|
170
|
+
public validate(): void {
|
|
171
|
+
if (this.noOfTimesCalled === 0 && this.times > 0) {
|
|
172
|
+
throw new GGTestError({
|
|
173
|
+
test: "Expected to be called, but was not.",
|
|
174
|
+
expected: "To be called",
|
|
175
|
+
received: "-",
|
|
176
|
+
sourceFile: this.definedInSourceFile
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public getMockValidationError(): Error | undefined {
|
|
182
|
+
return this.validationError;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public isCalled(): boolean {
|
|
186
|
+
return this.noOfTimesCalled > 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// -------------------------------------------
|
|
190
|
+
// Helpers
|
|
191
|
+
// -------------------------------------------
|
|
192
|
+
|
|
193
|
+
protected async sleepIfNeeded(): Promise<void> {
|
|
194
|
+
if (this._sleep) {
|
|
195
|
+
await new Promise(resolve => setTimeout(resolve, this._sleep));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
protected checkNoOfTimesCalled(): void {
|
|
200
|
+
this.noOfTimesCalled++;
|
|
201
|
+
if (this.noOfTimesCalled > this.times) {
|
|
202
|
+
throw new GGTestError({
|
|
203
|
+
context: `[${this.getKey()}]`,
|
|
204
|
+
test: "Interceptor called too many times!",
|
|
205
|
+
expected: `Called ${this.times} time(s)`,
|
|
206
|
+
received: `Called ${this.noOfTimesCalled} times(s)`,
|
|
207
|
+
sourceFile: this.definedInSourceFile
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
protected setMockValidationError(originalError: Error, type: string): void {
|
|
213
|
+
const messagePrefix = `[${this.getKey()}] ${type}`;
|
|
214
|
+
GGLog.error(this, messagePrefix, originalError);
|
|
215
|
+
|
|
216
|
+
(originalError as any).isMockValidationError = true;
|
|
217
|
+
|
|
218
|
+
originalError.message = messagePrefix + "\n" + originalError.message;
|
|
219
|
+
const lines = originalError.stack?.split("\n") || [];
|
|
220
|
+
lines.shift();
|
|
221
|
+
originalError.stack = lines.join("\n");
|
|
222
|
+
this.validationError = originalError;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
import {DeepPartial} from "@grest-ts/common";
|
|
2
|
-
import {captureStackSourceFile} from "../utils/captureStack";
|
|
3
|
-
import {GGExpectations} from "../utils/GGExpectations";
|
|
4
|
-
import {Raw} from "@grest-ts/schema";
|
|
5
|
-
import {GG_TEST_RUNNER, GGTestRunner} from "../GGTestRunner";
|
|
6
|
-
import {IGGTestWith} from "./IGGTestWith";
|
|
7
|
-
import {IGGTestInterceptor} from "./IGGTestInterceptor";
|
|
8
|
-
import {GGCallInterceptor, GGCallInterceptorConfig} from "./GGCallInterceptor";
|
|
9
|
-
|
|
10
|
-
type InterceptorFactory = new (runner: GGTestRunner, config: any) => GGCallInterceptor;
|
|
11
|
-
|
|
12
|
-
export class GGMockWith<RequestBody = any, ResponseData = any, ErrorsUnion = any> implements IGGTestWith {
|
|
13
|
-
|
|
14
|
-
private readonly interceptorFactory: InterceptorFactory;
|
|
15
|
-
private readonly interceptorConfig: Record<string, any>;
|
|
16
|
-
private readonly definedInSourceFile: string;
|
|
17
|
-
private _sleep: number;
|
|
18
|
-
private _times: number = 1;
|
|
19
|
-
|
|
20
|
-
private readonly expectations: GGExpectations<RequestBody> = new GGExpectations();
|
|
21
|
-
private returnData: ResponseData | ErrorsUnion | (() => ResponseData | ErrorsUnion);
|
|
22
|
-
|
|
23
|
-
constructor(interceptorFactory: InterceptorFactory, config: Record<string, any>) {
|
|
24
|
-
this.interceptorFactory = interceptorFactory;
|
|
25
|
-
this.interceptorConfig = config;
|
|
26
|
-
this.definedInSourceFile = captureStackSourceFile();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public createInterceptor(): IGGTestInterceptor {
|
|
30
|
-
const test = GG_TEST_RUNNER.get();
|
|
31
|
-
const config: GGCallInterceptorConfig = {
|
|
32
|
-
...this.interceptorConfig,
|
|
33
|
-
definedInSourceFile: this.definedInSourceFile,
|
|
34
|
-
sleep: this._sleep,
|
|
35
|
-
times: this._times,
|
|
36
|
-
passThrough: false,
|
|
37
|
-
inputExpectations: this.expectations,
|
|
38
|
-
returnData: this.returnData
|
|
39
|
-
};
|
|
40
|
-
return new this.interceptorFactory(test, config);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public sleep(timeMs: number): this {
|
|
44
|
-
this._sleep = timeMs;
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public times(amount: number): this {
|
|
49
|
-
this._times = amount;
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
public toEqual(expectedData: Raw<RequestBody>): this {
|
|
54
|
-
this.expectations.toEqual(expectedData as RequestBody)
|
|
55
|
-
return this;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public toMatchObject(expectedData: DeepPartial<Raw<RequestBody>>): this {
|
|
59
|
-
this.expectations.toMatchObject(expectedData as RequestBody)
|
|
60
|
-
return this;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public toBeUndefined(): this {
|
|
64
|
-
this.expectations.toBeUndefined()
|
|
65
|
-
return this;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
public toHaveLength(length: number): this {
|
|
69
|
-
this.expectations.toHaveLength(length)
|
|
70
|
-
return this;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public arrayToContain<Item extends RequestBody extends Array<infer R> ? R : never>(...items: Partial<Raw<Item>>[]): this {
|
|
74
|
-
this.expectations.arrayToContain(...items)
|
|
75
|
-
return this;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public arrayToContainEqual<Item extends RequestBody extends Array<infer R> ? R : never>(...items: Partial<Raw<Item>>[]): this {
|
|
79
|
-
this.expectations.arrayToContainEqual(...items)
|
|
80
|
-
return this;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public andReturn(data: Raw<ResponseData | ErrorsUnion> | (() => Raw<ResponseData | ErrorsUnion>)): this {
|
|
84
|
-
this.returnData = data as any;
|
|
85
|
-
return this;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public requiresWaitFor(): boolean {
|
|
89
|
-
return this.interceptorConfig.requiresWaitFor === true;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
}
|
|
1
|
+
import {DeepPartial} from "@grest-ts/common";
|
|
2
|
+
import {captureStackSourceFile} from "../utils/captureStack";
|
|
3
|
+
import {GGExpectations} from "../utils/GGExpectations";
|
|
4
|
+
import {Raw} from "@grest-ts/schema";
|
|
5
|
+
import {GG_TEST_RUNNER, GGTestRunner} from "../GGTestRunner";
|
|
6
|
+
import {IGGTestWith} from "./IGGTestWith";
|
|
7
|
+
import {IGGTestInterceptor} from "./IGGTestInterceptor";
|
|
8
|
+
import {GGCallInterceptor, GGCallInterceptorConfig} from "./GGCallInterceptor";
|
|
9
|
+
|
|
10
|
+
type InterceptorFactory = new (runner: GGTestRunner, config: any) => GGCallInterceptor;
|
|
11
|
+
|
|
12
|
+
export class GGMockWith<RequestBody = any, ResponseData = any, ErrorsUnion = any> implements IGGTestWith {
|
|
13
|
+
|
|
14
|
+
private readonly interceptorFactory: InterceptorFactory;
|
|
15
|
+
private readonly interceptorConfig: Record<string, any>;
|
|
16
|
+
private readonly definedInSourceFile: string;
|
|
17
|
+
private _sleep: number;
|
|
18
|
+
private _times: number = 1;
|
|
19
|
+
|
|
20
|
+
private readonly expectations: GGExpectations<RequestBody> = new GGExpectations();
|
|
21
|
+
private returnData: ResponseData | ErrorsUnion | (() => ResponseData | ErrorsUnion);
|
|
22
|
+
|
|
23
|
+
constructor(interceptorFactory: InterceptorFactory, config: Record<string, any>) {
|
|
24
|
+
this.interceptorFactory = interceptorFactory;
|
|
25
|
+
this.interceptorConfig = config;
|
|
26
|
+
this.definedInSourceFile = captureStackSourceFile();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public createInterceptor(): IGGTestInterceptor {
|
|
30
|
+
const test = GG_TEST_RUNNER.get();
|
|
31
|
+
const config: GGCallInterceptorConfig = {
|
|
32
|
+
...this.interceptorConfig,
|
|
33
|
+
definedInSourceFile: this.definedInSourceFile,
|
|
34
|
+
sleep: this._sleep,
|
|
35
|
+
times: this._times,
|
|
36
|
+
passThrough: false,
|
|
37
|
+
inputExpectations: this.expectations,
|
|
38
|
+
returnData: this.returnData
|
|
39
|
+
};
|
|
40
|
+
return new this.interceptorFactory(test, config);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public sleep(timeMs: number): this {
|
|
44
|
+
this._sleep = timeMs;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public times(amount: number): this {
|
|
49
|
+
this._times = amount;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public toEqual(expectedData: Raw<RequestBody>): this {
|
|
54
|
+
this.expectations.toEqual(expectedData as RequestBody)
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public toMatchObject(expectedData: DeepPartial<Raw<RequestBody>>): this {
|
|
59
|
+
this.expectations.toMatchObject(expectedData as RequestBody)
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public toBeUndefined(): this {
|
|
64
|
+
this.expectations.toBeUndefined()
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public toHaveLength(length: number): this {
|
|
69
|
+
this.expectations.toHaveLength(length)
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public arrayToContain<Item extends RequestBody extends Array<infer R> ? R : never>(...items: Partial<Raw<Item>>[]): this {
|
|
74
|
+
this.expectations.arrayToContain(...items)
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public arrayToContainEqual<Item extends RequestBody extends Array<infer R> ? R : never>(...items: Partial<Raw<Item>>[]): this {
|
|
79
|
+
this.expectations.arrayToContainEqual(...items)
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public andReturn(data: Raw<ResponseData | ErrorsUnion> | (() => Raw<ResponseData | ErrorsUnion>)): this {
|
|
84
|
+
this.returnData = data as any;
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public requiresWaitFor(): boolean {
|
|
89
|
+
return this.interceptorConfig.requiresWaitFor === true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|