@webpieces/core-mock 0.4.449
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 +30 -0
- package/package.json +30 -0
- package/src/MockHandler.d.ts +75 -0
- package/src/MockHandler.js +137 -0
- package/src/MockHandler.js.map +1 -0
- package/src/createMock.d.ts +41 -0
- package/src/createMock.js +47 -0
- package/src/createMock.js.map +1 -0
- package/src/index.d.ts +11 -0
- package/src/index.js +19 -0
- package/src/index.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @webpieces/core-mock
|
|
2
|
+
|
|
3
|
+
Typed mock framework for webpieces feature tests — the TypeScript port of Java
|
|
4
|
+
webpieces' `core-mock` (`MockSuperclass`).
|
|
5
|
+
|
|
6
|
+
Where Java requires a hand-written mock subclass per api, `createMock<T>()`
|
|
7
|
+
returns a `Proxy` implementing the api with the identical prime/assert
|
|
8
|
+
vocabulary:
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
const mockRemote = createMock<RemoteApi>('RemoteApi');
|
|
12
|
+
|
|
13
|
+
// prime
|
|
14
|
+
mockRemote.mock.addValueToReturn('fetchValue', { value: 'primed' });
|
|
15
|
+
mockRemote.mock.addExceptionToThrow('fetchValue', () => new Error('boom'));
|
|
16
|
+
mockRemote.mock.setDefaultReturnValue('fetchValue', { value: 'default' });
|
|
17
|
+
|
|
18
|
+
// rebind in the test container
|
|
19
|
+
rebind(TYPES.RemoteApi).toConstantValue(mockRemote);
|
|
20
|
+
|
|
21
|
+
// assert
|
|
22
|
+
const requests = mockRemote.mock.getSingleRequestList<FetchValueRequest>('fetchValue');
|
|
23
|
+
expect(requests[0].name).toBe('two-hop');
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Semantics (matching Java `MockSuperclass`):
|
|
27
|
+
- Primed values form a queue per method; each call dequeues one.
|
|
28
|
+
- Empty queue falls back to the default value; no default → throws
|
|
29
|
+
"test did not add enough return values".
|
|
30
|
+
- `getCalledMethodList`/`getSingleRequestList` DRAIN the recorded calls.
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@webpieces/core-mock",
|
|
3
|
+
"version": "0.4.449",
|
|
4
|
+
"description": "Typed mock framework for webpieces feature tests (port of Java core-mock MockSuperclass)",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"types": "./src/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.d.ts",
|
|
11
|
+
"default": "./src/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"author": "Dean Hiller",
|
|
15
|
+
"license": "Apache-2.0",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/deanhiller/webpieces-ts.git",
|
|
19
|
+
"directory": "packages/core/core-mock"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"webpieces",
|
|
23
|
+
"mock",
|
|
24
|
+
"testing"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {}
|
|
30
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ParametersPassedIn - The arguments captured from one mock invocation.
|
|
3
|
+
* Per CLAUDE.md: data-only structure = class.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ParametersPassedIn {
|
|
6
|
+
readonly args: unknown[];
|
|
7
|
+
constructor(args: unknown[]);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* ValueToReturn - One primed response: either a value supplier or an error
|
|
11
|
+
* supplier (port of Java ValueToReturn).
|
|
12
|
+
*/
|
|
13
|
+
export declare class ValueToReturn {
|
|
14
|
+
private readonly valueSupplier?;
|
|
15
|
+
private readonly errorSupplier?;
|
|
16
|
+
constructor(valueSupplier?: (() => unknown) | undefined, errorSupplier?: (() => Error) | undefined);
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the primed entry: throws if primed as an exception, else returns.
|
|
19
|
+
*/
|
|
20
|
+
returnOrThrowValue(): unknown;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* MockHandler - The mock engine (port of Java MockSuperclass), keyed by
|
|
24
|
+
* method name.
|
|
25
|
+
*
|
|
26
|
+
* Semantics identical to Java:
|
|
27
|
+
* - Primed values form a QUEUE per method; each call dequeues one.
|
|
28
|
+
* - Empty queue falls back to the method's default value.
|
|
29
|
+
* - No queue entry and no default -> throws "test did not add enough return values".
|
|
30
|
+
* - getCalledMethodList/getSingleRequestList DRAIN the recorded calls.
|
|
31
|
+
*
|
|
32
|
+
* Usually consumed through createMock<T>() which wraps this in a typed Proxy;
|
|
33
|
+
* use directly only when hand-writing a mock class.
|
|
34
|
+
*/
|
|
35
|
+
export declare class MockHandler {
|
|
36
|
+
private returnValues;
|
|
37
|
+
private defaultReturnValues;
|
|
38
|
+
private calledMethods;
|
|
39
|
+
/**
|
|
40
|
+
* Queue a value to return on the next call to method.
|
|
41
|
+
*/
|
|
42
|
+
addValueToReturn(method: string, value: unknown): void;
|
|
43
|
+
/**
|
|
44
|
+
* Queue a computed value (supplier runs at call time).
|
|
45
|
+
*/
|
|
46
|
+
addCalculateRetValue(method: string, supplier: () => unknown): void;
|
|
47
|
+
/**
|
|
48
|
+
* Queue an exception to throw on the next call to method.
|
|
49
|
+
*/
|
|
50
|
+
addExceptionToThrow(method: string, errorSupplier: () => Error): void;
|
|
51
|
+
/**
|
|
52
|
+
* Fallback value returned when the queue for method is empty.
|
|
53
|
+
*/
|
|
54
|
+
setDefaultReturnValue(method: string, value: unknown): void;
|
|
55
|
+
/**
|
|
56
|
+
* Record a call and resolve its response (queue -> default -> throw).
|
|
57
|
+
* Called by the createMock proxy for every api-method invocation.
|
|
58
|
+
*/
|
|
59
|
+
calledMethod(method: string, args: unknown[]): unknown;
|
|
60
|
+
/**
|
|
61
|
+
* DRAIN and return all recorded invocations of method (Java parity: the
|
|
62
|
+
* list resets so a second assertion sees only new calls).
|
|
63
|
+
*/
|
|
64
|
+
getCalledMethodList(method: string): ParametersPassedIn[];
|
|
65
|
+
/**
|
|
66
|
+
* DRAIN and return the FIRST argument of each recorded invocation - the
|
|
67
|
+
* common single-request-DTO shape.
|
|
68
|
+
*/
|
|
69
|
+
getSingleRequestList<R>(method: string): R[];
|
|
70
|
+
/**
|
|
71
|
+
* Reset all primed values, defaults, and recorded calls.
|
|
72
|
+
*/
|
|
73
|
+
clear(): void;
|
|
74
|
+
private queueFor;
|
|
75
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MockHandler = exports.ValueToReturn = exports.ParametersPassedIn = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* ParametersPassedIn - The arguments captured from one mock invocation.
|
|
6
|
+
* Per CLAUDE.md: data-only structure = class.
|
|
7
|
+
*/
|
|
8
|
+
class ParametersPassedIn {
|
|
9
|
+
args;
|
|
10
|
+
// webpieces-disable no-any-unknown -- mock captures arbitrary api arguments
|
|
11
|
+
constructor(args) {
|
|
12
|
+
this.args = args;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.ParametersPassedIn = ParametersPassedIn;
|
|
16
|
+
/**
|
|
17
|
+
* ValueToReturn - One primed response: either a value supplier or an error
|
|
18
|
+
* supplier (port of Java ValueToReturn).
|
|
19
|
+
*/
|
|
20
|
+
class ValueToReturn {
|
|
21
|
+
valueSupplier;
|
|
22
|
+
errorSupplier;
|
|
23
|
+
constructor(
|
|
24
|
+
// webpieces-disable no-any-unknown -- primed values are api-specific, erased here
|
|
25
|
+
valueSupplier, errorSupplier) {
|
|
26
|
+
this.valueSupplier = valueSupplier;
|
|
27
|
+
this.errorSupplier = errorSupplier;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the primed entry: throws if primed as an exception, else returns.
|
|
31
|
+
*/
|
|
32
|
+
// webpieces-disable no-any-unknown -- primed values are api-specific, erased here
|
|
33
|
+
returnOrThrowValue() {
|
|
34
|
+
if (this.errorSupplier) {
|
|
35
|
+
throw this.errorSupplier();
|
|
36
|
+
}
|
|
37
|
+
return this.valueSupplier ? this.valueSupplier() : undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.ValueToReturn = ValueToReturn;
|
|
41
|
+
/**
|
|
42
|
+
* MockHandler - The mock engine (port of Java MockSuperclass), keyed by
|
|
43
|
+
* method name.
|
|
44
|
+
*
|
|
45
|
+
* Semantics identical to Java:
|
|
46
|
+
* - Primed values form a QUEUE per method; each call dequeues one.
|
|
47
|
+
* - Empty queue falls back to the method's default value.
|
|
48
|
+
* - No queue entry and no default -> throws "test did not add enough return values".
|
|
49
|
+
* - getCalledMethodList/getSingleRequestList DRAIN the recorded calls.
|
|
50
|
+
*
|
|
51
|
+
* Usually consumed through createMock<T>() which wraps this in a typed Proxy;
|
|
52
|
+
* use directly only when hand-writing a mock class.
|
|
53
|
+
*/
|
|
54
|
+
class MockHandler {
|
|
55
|
+
returnValues = new Map();
|
|
56
|
+
defaultReturnValues = new Map();
|
|
57
|
+
calledMethods = new Map();
|
|
58
|
+
/**
|
|
59
|
+
* Queue a value to return on the next call to method.
|
|
60
|
+
*/
|
|
61
|
+
// webpieces-disable no-any-unknown -- primed values are api-specific, erased here
|
|
62
|
+
addValueToReturn(method, value) {
|
|
63
|
+
this.queueFor(method).push(new ValueToReturn(() => value));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Queue a computed value (supplier runs at call time).
|
|
67
|
+
*/
|
|
68
|
+
// webpieces-disable no-any-unknown -- primed values are api-specific, erased here
|
|
69
|
+
addCalculateRetValue(method, supplier) {
|
|
70
|
+
this.queueFor(method).push(new ValueToReturn(supplier));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Queue an exception to throw on the next call to method.
|
|
74
|
+
*/
|
|
75
|
+
addExceptionToThrow(method, errorSupplier) {
|
|
76
|
+
this.queueFor(method).push(new ValueToReturn(undefined, errorSupplier));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Fallback value returned when the queue for method is empty.
|
|
80
|
+
*/
|
|
81
|
+
// webpieces-disable no-any-unknown -- primed values are api-specific, erased here
|
|
82
|
+
setDefaultReturnValue(method, value) {
|
|
83
|
+
this.defaultReturnValues.set(method, new ValueToReturn(() => value));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Record a call and resolve its response (queue -> default -> throw).
|
|
87
|
+
* Called by the createMock proxy for every api-method invocation.
|
|
88
|
+
*/
|
|
89
|
+
// webpieces-disable no-any-unknown -- mock engine handles type-erased calls; createMock adds typing
|
|
90
|
+
calledMethod(method, args) {
|
|
91
|
+
const calls = this.calledMethods.get(method) ?? [];
|
|
92
|
+
calls.push(new ParametersPassedIn(args));
|
|
93
|
+
this.calledMethods.set(method, calls);
|
|
94
|
+
const queue = this.returnValues.get(method);
|
|
95
|
+
if (queue && queue.length > 0) {
|
|
96
|
+
const next = queue.shift();
|
|
97
|
+
return next.returnOrThrowValue();
|
|
98
|
+
}
|
|
99
|
+
const defaultValue = this.defaultReturnValues.get(method);
|
|
100
|
+
if (defaultValue) {
|
|
101
|
+
return defaultValue.returnOrThrowValue();
|
|
102
|
+
}
|
|
103
|
+
throw new Error(`The test did not add enough return values to mocked method '${method}'. ` +
|
|
104
|
+
`Prime it with addValueToReturn('${method}', ...) or setDefaultReturnValue('${method}', ...).`);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* DRAIN and return all recorded invocations of method (Java parity: the
|
|
108
|
+
* list resets so a second assertion sees only new calls).
|
|
109
|
+
*/
|
|
110
|
+
getCalledMethodList(method) {
|
|
111
|
+
const calls = this.calledMethods.get(method) ?? [];
|
|
112
|
+
this.calledMethods.delete(method);
|
|
113
|
+
return calls;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* DRAIN and return the FIRST argument of each recorded invocation - the
|
|
117
|
+
* common single-request-DTO shape.
|
|
118
|
+
*/
|
|
119
|
+
getSingleRequestList(method) {
|
|
120
|
+
return this.getCalledMethodList(method).map((p) => p.args[0]);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Reset all primed values, defaults, and recorded calls.
|
|
124
|
+
*/
|
|
125
|
+
clear() {
|
|
126
|
+
this.returnValues.clear();
|
|
127
|
+
this.defaultReturnValues.clear();
|
|
128
|
+
this.calledMethods.clear();
|
|
129
|
+
}
|
|
130
|
+
queueFor(method) {
|
|
131
|
+
const queue = this.returnValues.get(method) ?? [];
|
|
132
|
+
this.returnValues.set(method, queue);
|
|
133
|
+
return queue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.MockHandler = MockHandler;
|
|
137
|
+
//# sourceMappingURL=MockHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockHandler.js","sourceRoot":"","sources":["../../../../../packages/core/core-mock/src/MockHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ParametersPassedIn - The arguments captured from one mock invocation.\n * Per CLAUDE.md: data-only structure = class.\n */\nexport class ParametersPassedIn {\n // webpieces-disable no-any-unknown -- mock captures arbitrary api arguments\n constructor(public readonly args: unknown[]) {}\n}\n\n/**\n * ValueToReturn - One primed response: either a value supplier or an error\n * supplier (port of Java ValueToReturn).\n */\nexport class ValueToReturn {\n constructor(\n // webpieces-disable no-any-unknown -- primed values are api-specific, erased here\n private readonly valueSupplier?: () => unknown,\n private readonly errorSupplier?: () => Error,\n ) {}\n\n /**\n * Resolve the primed entry: throws if primed as an exception, else returns.\n */\n // webpieces-disable no-any-unknown -- primed values are api-specific, erased here\n returnOrThrowValue(): unknown {\n if (this.errorSupplier) {\n throw this.errorSupplier();\n }\n return this.valueSupplier ? this.valueSupplier() : undefined;\n }\n}\n\n/**\n * MockHandler - The mock engine (port of Java MockSuperclass), keyed by\n * method name.\n *\n * Semantics identical to Java:\n * - Primed values form a QUEUE per method; each call dequeues one.\n * - Empty queue falls back to the method's default value.\n * - No queue entry and no default -> throws \"test did not add enough return values\".\n * - getCalledMethodList/getSingleRequestList DRAIN the recorded calls.\n *\n * Usually consumed through createMock<T>() which wraps this in a typed Proxy;\n * use directly only when hand-writing a mock class.\n */\nexport class MockHandler {\n private returnValues: Map<string, ValueToReturn[]> = new Map();\n private defaultReturnValues: Map<string, ValueToReturn> = new Map();\n private calledMethods: Map<string, ParametersPassedIn[]> = new Map();\n\n /**\n * Queue a value to return on the next call to method.\n */\n // webpieces-disable no-any-unknown -- primed values are api-specific, erased here\n addValueToReturn(method: string, value: unknown): void {\n this.queueFor(method).push(new ValueToReturn(() => value));\n }\n\n /**\n * Queue a computed value (supplier runs at call time).\n */\n // webpieces-disable no-any-unknown -- primed values are api-specific, erased here\n addCalculateRetValue(method: string, supplier: () => unknown): void {\n this.queueFor(method).push(new ValueToReturn(supplier));\n }\n\n /**\n * Queue an exception to throw on the next call to method.\n */\n addExceptionToThrow(method: string, errorSupplier: () => Error): void {\n this.queueFor(method).push(new ValueToReturn(undefined, errorSupplier));\n }\n\n /**\n * Fallback value returned when the queue for method is empty.\n */\n // webpieces-disable no-any-unknown -- primed values are api-specific, erased here\n setDefaultReturnValue(method: string, value: unknown): void {\n this.defaultReturnValues.set(method, new ValueToReturn(() => value));\n }\n\n /**\n * Record a call and resolve its response (queue -> default -> throw).\n * Called by the createMock proxy for every api-method invocation.\n */\n // webpieces-disable no-any-unknown -- mock engine handles type-erased calls; createMock adds typing\n calledMethod(method: string, args: unknown[]): unknown {\n const calls = this.calledMethods.get(method) ?? [];\n calls.push(new ParametersPassedIn(args));\n this.calledMethods.set(method, calls);\n\n const queue = this.returnValues.get(method);\n if (queue && queue.length > 0) {\n const next = queue.shift()!;\n return next.returnOrThrowValue();\n }\n\n const defaultValue = this.defaultReturnValues.get(method);\n if (defaultValue) {\n return defaultValue.returnOrThrowValue();\n }\n\n throw new Error(\n `The test did not add enough return values to mocked method '${method}'. ` +\n `Prime it with addValueToReturn('${method}', ...) or setDefaultReturnValue('${method}', ...).`,\n );\n }\n\n /**\n * DRAIN and return all recorded invocations of method (Java parity: the\n * list resets so a second assertion sees only new calls).\n */\n getCalledMethodList(method: string): ParametersPassedIn[] {\n const calls = this.calledMethods.get(method) ?? [];\n this.calledMethods.delete(method);\n return calls;\n }\n\n /**\n * DRAIN and return the FIRST argument of each recorded invocation - the\n * common single-request-DTO shape.\n */\n getSingleRequestList<R>(method: string): R[] {\n return this.getCalledMethodList(method).map((p: ParametersPassedIn) => p.args[0] as R);\n }\n\n /**\n * Reset all primed values, defaults, and recorded calls.\n */\n clear(): void {\n this.returnValues.clear();\n this.defaultReturnValues.clear();\n this.calledMethods.clear();\n }\n\n private queueFor(method: string): ValueToReturn[] {\n const queue = this.returnValues.get(method) ?? [];\n this.returnValues.set(method, queue);\n return queue;\n }\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ParametersPassedIn } from './MockHandler';
|
|
2
|
+
/**
|
|
3
|
+
* TypedMockControls - The typed prime/assert facade exposed on mock.mock.
|
|
4
|
+
* Method names are constrained to keyof T; primed values to the method's
|
|
5
|
+
* awaited return type.
|
|
6
|
+
*/
|
|
7
|
+
export interface TypedMockControls<T> {
|
|
8
|
+
addValueToReturn<K extends keyof T & string>(method: K, value: T[K] extends (...args: never[]) => unknown ? Awaited<ReturnType<T[K]>> : never): void;
|
|
9
|
+
addCalculateRetValue<K extends keyof T & string>(method: K, supplier: () => unknown): void;
|
|
10
|
+
addExceptionToThrow<K extends keyof T & string>(method: K, errorSupplier: () => Error): void;
|
|
11
|
+
setDefaultReturnValue<K extends keyof T & string>(method: K, value: T[K] extends (...args: never[]) => unknown ? Awaited<ReturnType<T[K]>> : never): void;
|
|
12
|
+
getCalledMethodList<K extends keyof T & string>(method: K): ParametersPassedIn[];
|
|
13
|
+
getSingleRequestList<R, K extends keyof T & string = keyof T & string>(method: K): R[];
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* MockedApi - The mock: implements T (every method resolves via MockHandler)
|
|
18
|
+
* plus a typed `mock` control facade.
|
|
19
|
+
*/
|
|
20
|
+
export type MockedApi<T> = T & {
|
|
21
|
+
mock: TypedMockControls<T>;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* createMock - Build a typed mock for an api interface/abstract class.
|
|
25
|
+
*
|
|
26
|
+
* Port of Java core-mock, minus the boilerplate: where Java requires a
|
|
27
|
+
* hand-written `MockRemoteService extends MockSuperclass implements RemoteApi`
|
|
28
|
+
* per api, a JS Proxy implements every method generically while keeping the
|
|
29
|
+
* identical prime/assert vocabulary.
|
|
30
|
+
*
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const mockRemote = createMock<RemoteApi>('RemoteApi');
|
|
33
|
+
* mockRemote.mock.addValueToReturn('fetchValue', { value: 'primed' });
|
|
34
|
+
* rebind(TYPES.RemoteApi).toConstantValue(mockRemote);
|
|
35
|
+
* // ... run the test ...
|
|
36
|
+
* const reqs = mockRemote.mock.getSingleRequestList<FetchValueRequest>('fetchValue');
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* Every api method returns a Promise (webpieces apis are async by convention).
|
|
40
|
+
*/
|
|
41
|
+
export declare function createMock<T extends object>(apiName: string): MockedApi<T>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMock = createMock;
|
|
4
|
+
const MockHandler_1 = require("./MockHandler");
|
|
5
|
+
/**
|
|
6
|
+
* createMock - Build a typed mock for an api interface/abstract class.
|
|
7
|
+
*
|
|
8
|
+
* Port of Java core-mock, minus the boilerplate: where Java requires a
|
|
9
|
+
* hand-written `MockRemoteService extends MockSuperclass implements RemoteApi`
|
|
10
|
+
* per api, a JS Proxy implements every method generically while keeping the
|
|
11
|
+
* identical prime/assert vocabulary.
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const mockRemote = createMock<RemoteApi>('RemoteApi');
|
|
15
|
+
* mockRemote.mock.addValueToReturn('fetchValue', { value: 'primed' });
|
|
16
|
+
* rebind(TYPES.RemoteApi).toConstantValue(mockRemote);
|
|
17
|
+
* // ... run the test ...
|
|
18
|
+
* const reqs = mockRemote.mock.getSingleRequestList<FetchValueRequest>('fetchValue');
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Every api method returns a Promise (webpieces apis are async by convention).
|
|
22
|
+
*/
|
|
23
|
+
function createMock(apiName) {
|
|
24
|
+
const handler = new MockHandler_1.MockHandler();
|
|
25
|
+
// Properties that must NOT become mocked api methods
|
|
26
|
+
const passthrough = new Set(['mock', 'then', 'catch', 'finally', 'constructor', 'toJSON']);
|
|
27
|
+
return new Proxy({}, {
|
|
28
|
+
// webpieces-disable no-any-unknown -- Proxy get trap returns heterogeneous members
|
|
29
|
+
get(target, prop) {
|
|
30
|
+
if (typeof prop !== 'string') {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
if (prop === 'mock') {
|
|
34
|
+
return handler;
|
|
35
|
+
}
|
|
36
|
+
if (passthrough.has(prop)) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
// Any other property access is treated as an api method
|
|
40
|
+
// webpieces-disable no-any-unknown -- api method args/returns are type-erased in the proxy
|
|
41
|
+
return async (...args) => {
|
|
42
|
+
return handler.calledMethod(prop, args);
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=createMock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createMock.js","sourceRoot":"","sources":["../../../../../packages/core/core-mock/src/createMock.ts"],"names":[],"mappings":";;AAoDA,gCAyBC;AA7ED,+CAAgE;AAkChE;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,UAAU,CAAmB,OAAe;IACxD,MAAM,OAAO,GAAG,IAAI,yBAAW,EAAE,CAAC;IAElC,qDAAqD;IACrD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE3F,OAAO,IAAI,KAAK,CAAC,EAAkB,EAAE;QACjC,mFAAmF;QACnF,GAAG,CAAC,MAAoB,EAAE,IAAqB;YAC3C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC3B,OAAO,SAAS,CAAC;YACrB,CAAC;YACD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBAClB,OAAO,OAAO,CAAC;YACnB,CAAC;YACD,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,OAAO,SAAS,CAAC;YACrB,CAAC;YACD,wDAAwD;YACxD,2FAA2F;YAC3F,OAAO,KAAK,EAAE,GAAG,IAAe,EAAoB,EAAE;gBAClD,OAAO,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5C,CAAC,CAAC;QACN,CAAC;KACJ,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { MockHandler, ParametersPassedIn } from './MockHandler';\n\n/**\n * TypedMockControls - The typed prime/assert facade exposed on mock.mock.\n * Method names are constrained to keyof T; primed values to the method's\n * awaited return type.\n */\nexport interface TypedMockControls<T> {\n // webpieces-disable no-any-unknown -- conditional type extracts the method's awaited return type\n addValueToReturn<K extends keyof T & string>(\n method: K,\n // webpieces-disable no-any-unknown -- conditional type extracts the method's awaited return type\n value: T[K] extends (...args: never[]) => unknown ? Awaited<ReturnType<T[K]>> : never,\n ): void;\n // webpieces-disable no-any-unknown -- supplier computes api-specific values at call time\n addCalculateRetValue<K extends keyof T & string>(method: K, supplier: () => unknown): void;\n addExceptionToThrow<K extends keyof T & string>(method: K, errorSupplier: () => Error): void;\n // webpieces-disable no-any-unknown -- conditional type extracts the method's awaited return type\n setDefaultReturnValue<K extends keyof T & string>(\n method: K,\n // webpieces-disable no-any-unknown -- conditional type extracts the method's awaited return type\n value: T[K] extends (...args: never[]) => unknown ? Awaited<ReturnType<T[K]>> : never,\n ): void;\n getCalledMethodList<K extends keyof T & string>(method: K): ParametersPassedIn[];\n getSingleRequestList<R, K extends keyof T & string = keyof T & string>(method: K): R[];\n clear(): void;\n}\n\n/**\n * MockedApi - The mock: implements T (every method resolves via MockHandler)\n * plus a typed `mock` control facade.\n */\nexport type MockedApi<T> = T & { mock: TypedMockControls<T> };\n\n/**\n * createMock - Build a typed mock for an api interface/abstract class.\n *\n * Port of Java core-mock, minus the boilerplate: where Java requires a\n * hand-written `MockRemoteService extends MockSuperclass implements RemoteApi`\n * per api, a JS Proxy implements every method generically while keeping the\n * identical prime/assert vocabulary.\n *\n * ```typescript\n * const mockRemote = createMock<RemoteApi>('RemoteApi');\n * mockRemote.mock.addValueToReturn('fetchValue', { value: 'primed' });\n * rebind(TYPES.RemoteApi).toConstantValue(mockRemote);\n * // ... run the test ...\n * const reqs = mockRemote.mock.getSingleRequestList<FetchValueRequest>('fetchValue');\n * ```\n *\n * Every api method returns a Promise (webpieces apis are async by convention).\n */\nexport function createMock<T extends object>(apiName: string): MockedApi<T> {\n const handler = new MockHandler();\n\n // Properties that must NOT become mocked api methods\n const passthrough = new Set(['mock', 'then', 'catch', 'finally', 'constructor', 'toJSON']);\n\n return new Proxy({} as MockedApi<T>, {\n // webpieces-disable no-any-unknown -- Proxy get trap returns heterogeneous members\n get(target: MockedApi<T>, prop: string | symbol): unknown {\n if (typeof prop !== 'string') {\n return undefined;\n }\n if (prop === 'mock') {\n return handler;\n }\n if (passthrough.has(prop)) {\n return undefined;\n }\n // Any other property access is treated as an api method\n // webpieces-disable no-any-unknown -- api method args/returns are type-erased in the proxy\n return async (...args: unknown[]): Promise<unknown> => {\n return handler.calledMethod(prop, args);\n };\n },\n });\n}\n"]}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @webpieces/core-mock
|
|
3
|
+
*
|
|
4
|
+
* Typed mock framework for feature tests - the TypeScript port of Java
|
|
5
|
+
* webpieces core-mock (MockSuperclass).
|
|
6
|
+
*
|
|
7
|
+
* - createMock<T>(name): Proxy-based mock implementing T + typed .mock controls
|
|
8
|
+
* - MockHandler: the queue/default/drain engine, for hand-written mock classes
|
|
9
|
+
*/
|
|
10
|
+
export { createMock, MockedApi, TypedMockControls } from './createMock';
|
|
11
|
+
export { MockHandler, ValueToReturn, ParametersPassedIn } from './MockHandler';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ParametersPassedIn = exports.ValueToReturn = exports.MockHandler = exports.createMock = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @webpieces/core-mock
|
|
6
|
+
*
|
|
7
|
+
* Typed mock framework for feature tests - the TypeScript port of Java
|
|
8
|
+
* webpieces core-mock (MockSuperclass).
|
|
9
|
+
*
|
|
10
|
+
* - createMock<T>(name): Proxy-based mock implementing T + typed .mock controls
|
|
11
|
+
* - MockHandler: the queue/default/drain engine, for hand-written mock classes
|
|
12
|
+
*/
|
|
13
|
+
var createMock_1 = require("./createMock");
|
|
14
|
+
Object.defineProperty(exports, "createMock", { enumerable: true, get: function () { return createMock_1.createMock; } });
|
|
15
|
+
var MockHandler_1 = require("./MockHandler");
|
|
16
|
+
Object.defineProperty(exports, "MockHandler", { enumerable: true, get: function () { return MockHandler_1.MockHandler; } });
|
|
17
|
+
Object.defineProperty(exports, "ValueToReturn", { enumerable: true, get: function () { return MockHandler_1.ValueToReturn; } });
|
|
18
|
+
Object.defineProperty(exports, "ParametersPassedIn", { enumerable: true, get: function () { return MockHandler_1.ParametersPassedIn; } });
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/core/core-mock/src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;GAQG;AACH,2CAAwE;AAA/D,wGAAA,UAAU,OAAA;AACnB,6CAA+E;AAAtE,0GAAA,WAAW,OAAA;AAAE,4GAAA,aAAa,OAAA;AAAE,iHAAA,kBAAkB,OAAA","sourcesContent":["/**\n * @webpieces/core-mock\n *\n * Typed mock framework for feature tests - the TypeScript port of Java\n * webpieces core-mock (MockSuperclass).\n *\n * - createMock<T>(name): Proxy-based mock implementing T + typed .mock controls\n * - MockHandler: the queue/default/drain engine, for hand-written mock classes\n */\nexport { createMock, MockedApi, TypedMockControls } from './createMock';\nexport { MockHandler, ValueToReturn, ParametersPassedIn } from './MockHandler';\n"]}
|