@jaypie/testkit 1.0.20 → 1.0.21
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 +20 -7
- package/package.json +3 -1
- package/src/index.js +5 -0
- package/src/jaypie.mock.js +206 -0
package/README.md
CHANGED
|
@@ -12,21 +12,33 @@ npm install --save-dev @jaypie/testkit
|
|
|
12
12
|
|
|
13
13
|
### Example
|
|
14
14
|
|
|
15
|
+
#### Mocking Jaypie
|
|
16
|
+
|
|
17
|
+
The testkit provides a complete mock for Jaypie including:
|
|
18
|
+
|
|
19
|
+
* Log spying (`expect(log.warn).toHaveBeenCalled()`)
|
|
20
|
+
* Default responses for runtime-only functions (`connect`, `sendMessage`, `submitMetric`)
|
|
21
|
+
* No automatic error handling for handlers (which is good in production but obfuscates tests)
|
|
22
|
+
* Most non-utility functions are mocked to allow simple testing
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
vi.mock("jaypie", vi.importActual("@jaypie/testkit"));
|
|
26
|
+
```
|
|
27
|
+
|
|
15
28
|
#### Log Spying
|
|
16
29
|
|
|
17
30
|
```javascript
|
|
18
|
-
import {
|
|
19
|
-
|
|
31
|
+
import { log } from "jaypie";
|
|
32
|
+
|
|
33
|
+
vi.mock("jaypie", vi.importActual("@jaypie/testkit"));
|
|
20
34
|
|
|
21
|
-
beforeEach(() => {
|
|
22
|
-
spyLog(log);
|
|
23
|
-
});
|
|
24
35
|
afterEach(() => {
|
|
25
|
-
restoreLog(log);
|
|
26
36
|
vi.clearAllMocks();
|
|
27
37
|
});
|
|
28
38
|
|
|
29
39
|
test("log", () => {
|
|
40
|
+
expect(vi.isMockFunction(log.warn)).toBe(true);
|
|
41
|
+
expect(log.warn).not.toHaveBeenCalled();
|
|
30
42
|
log.warn("Danger");
|
|
31
43
|
expect(log.warn).toHaveBeenCalled();
|
|
32
44
|
expect(log.error).not.toHaveBeenCalled();
|
|
@@ -256,7 +268,7 @@ Restores the `log` provided by `@jaypie/core`, commonly performed `afterEach` wi
|
|
|
256
268
|
|
|
257
269
|
### `spyLog(log)`
|
|
258
270
|
|
|
259
|
-
Spies on the `log` provided by `@jaypie/core`, commonly performed `beforeEach` with `restoreLog` in `afterEach`.
|
|
271
|
+
Spies on the `log` provided by `@jaypie/core`, commonly performed `beforeEach` with `restoreLog` in `afterEach`. Not necessary when mocking the entire Jaypie module.
|
|
260
272
|
|
|
261
273
|
```javascript
|
|
262
274
|
import { restoreLog, spyLog } from "@jaypie/testkit";
|
|
@@ -303,6 +315,7 @@ const event = sqsTestRecords(
|
|
|
303
315
|
|
|
304
316
|
| Date | Version | Summary |
|
|
305
317
|
| ---------- | ------- | -------------- |
|
|
318
|
+
| 7/16/2024 | 1.0.21 | Export Jaypie mock as default |
|
|
306
319
|
| 3/20/2024 | 1.0.2 | Export `LOG` |
|
|
307
320
|
| 3/16/2024 | 1.0.0 | Artists ship |
|
|
308
321
|
| 3/15/2024 | 0.1.0 | Initial deploy |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaypie/testkit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"author": "Finlayson Studio",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"test": "vitest",
|
|
22
22
|
"test:spec:constants": "vitest run ./src/__tests__/constants.spec.js",
|
|
23
23
|
"test:spec:index": "vitest run ./src/__tests__/index.spec.js",
|
|
24
|
+
"test:spec:jaypie.mock": "vitest run ./src/__tests__/jaypie.mock.spec.js",
|
|
24
25
|
"test:spec:jsonApiSchema.module": "vitest run ./src/__tests__/jsonApiSchema.module.spec.js",
|
|
25
26
|
"test:spec:matchers.module": "vitest run ./src/__tests__/matchers.module.spec.js",
|
|
26
27
|
"test:spec:mockLog.module": "vitest run ./src/__tests__/mockLog.module.spec.js",
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@jaypie/core": "^1.0.33",
|
|
37
|
+
"jaypie": "^1.0.44",
|
|
36
38
|
"jest-json-schema": "^6.1.0",
|
|
37
39
|
"lodash.isequal": "^4.5.0",
|
|
38
40
|
"uuid": "^9.0.1"
|
package/src/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import * as mockingJay from "./jaypie.mock.js";
|
|
2
|
+
|
|
1
3
|
//
|
|
2
4
|
//
|
|
3
5
|
// Constants
|
|
4
6
|
//
|
|
5
7
|
|
|
6
8
|
export { LOG } from "./constants.js";
|
|
9
|
+
|
|
7
10
|
//
|
|
8
11
|
//
|
|
9
12
|
// Export
|
|
@@ -13,3 +16,5 @@ export { jsonApiErrorSchema, jsonApiSchema } from "./jsonApiSchema.module.js";
|
|
|
13
16
|
export { default as matchers } from "./matchers.module.js";
|
|
14
17
|
export { mockLogFactory, restoreLog, spyLog } from "./mockLog.module.js";
|
|
15
18
|
export { default as sqsTestRecords } from "./sqsTestRecords.function.js";
|
|
19
|
+
|
|
20
|
+
export default mockingJay;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { getMessages as originalGetMessages } from "@jaypie/aws";
|
|
2
|
+
import { force, uuid as originalUuid } from "@jaypie/core";
|
|
3
|
+
import { BadRequestError, JAYPIE, log, UnavailableError } from "@jaypie/core";
|
|
4
|
+
import { beforeAll, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
import { spyLog } from "./mockLog.module.js";
|
|
7
|
+
|
|
8
|
+
//
|
|
9
|
+
//
|
|
10
|
+
// Setup
|
|
11
|
+
//
|
|
12
|
+
|
|
13
|
+
const TAG = JAYPIE.LIB.TESTKIT;
|
|
14
|
+
|
|
15
|
+
// Export all the modules from Jaypie packages:
|
|
16
|
+
|
|
17
|
+
export * from "@jaypie/aws";
|
|
18
|
+
export * from "@jaypie/core";
|
|
19
|
+
export * from "@jaypie/express";
|
|
20
|
+
export * from "@jaypie/datadog";
|
|
21
|
+
export * from "@jaypie/lambda";
|
|
22
|
+
export * from "@jaypie/mongoose";
|
|
23
|
+
|
|
24
|
+
// Spy on log:
|
|
25
|
+
|
|
26
|
+
beforeAll(() => {
|
|
27
|
+
spyLog(log);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// afterEach(() => {
|
|
31
|
+
// This is not necessary because the log isn't being used outside tests:
|
|
32
|
+
// restoreLog(log);
|
|
33
|
+
// The is the client's responsibility:
|
|
34
|
+
// vi.clearAllMocks();
|
|
35
|
+
// });
|
|
36
|
+
|
|
37
|
+
//
|
|
38
|
+
//
|
|
39
|
+
// Mock Functions
|
|
40
|
+
//
|
|
41
|
+
|
|
42
|
+
// @jaypie/aws
|
|
43
|
+
|
|
44
|
+
export const getMessages = vi.fn((...params) => originalGetMessages(...params));
|
|
45
|
+
|
|
46
|
+
export const getSecret = vi.fn(() => {
|
|
47
|
+
return `_MOCK_SECRET_[${TAG}]`;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const sendBatchMessages = vi.fn(() => {
|
|
51
|
+
// TODO: better default value
|
|
52
|
+
return { value: `_MOCK_BATCH_MESSAGES_[${TAG}]` };
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const sendMessage = vi.fn(() => {
|
|
56
|
+
// TODO: better default value
|
|
57
|
+
return { value: `_MOCK_MESSAGE_[${TAG}]` };
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// @jaypie/core Functions
|
|
61
|
+
|
|
62
|
+
export const envBoolean = vi.fn(() => {
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export const jaypieHandler = vi.fn(
|
|
67
|
+
(
|
|
68
|
+
handler,
|
|
69
|
+
{
|
|
70
|
+
setup = [],
|
|
71
|
+
teardown = [],
|
|
72
|
+
unavailable = force.boolean(process.env.PROJECT_UNAVAILABLE),
|
|
73
|
+
validate = [],
|
|
74
|
+
} = {},
|
|
75
|
+
) => {
|
|
76
|
+
return async (...args) => {
|
|
77
|
+
let result;
|
|
78
|
+
let thrownError;
|
|
79
|
+
if (unavailable) throw new UnavailableError();
|
|
80
|
+
for (const validator of validate) {
|
|
81
|
+
if (typeof validator === "function") {
|
|
82
|
+
const valid = await validator(...args);
|
|
83
|
+
if (valid === false) {
|
|
84
|
+
throw new BadRequestError();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
for (const setupFunction of setup) {
|
|
90
|
+
if (typeof setupFunction === "function") {
|
|
91
|
+
await setupFunction(...args);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
result = handler(...args);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
thrownError = error;
|
|
97
|
+
}
|
|
98
|
+
for (const teardownFunction of teardown) {
|
|
99
|
+
if (typeof teardownFunction === "function") {
|
|
100
|
+
try {
|
|
101
|
+
await teardownFunction(...args);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
// eslint-disable-next-line no-console
|
|
104
|
+
console.error(error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (thrownError) {
|
|
109
|
+
throw thrownError;
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
export const sleep = vi.fn(() => {
|
|
117
|
+
return true;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export const uuid = vi.fn(originalUuid);
|
|
121
|
+
|
|
122
|
+
// @jaypie/datadog
|
|
123
|
+
|
|
124
|
+
export const submitMetric = vi.fn(() => {
|
|
125
|
+
return true;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
export const submitMetricSet = vi.fn(() => {
|
|
129
|
+
return true;
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// @jaypie/express
|
|
133
|
+
|
|
134
|
+
export const expressHandler = vi.fn((handler, props = {}) => {
|
|
135
|
+
if (typeof handler !== "function") {
|
|
136
|
+
throw new BadRequestError("handler must be a function");
|
|
137
|
+
}
|
|
138
|
+
if (!props) {
|
|
139
|
+
props = {};
|
|
140
|
+
}
|
|
141
|
+
props.setup = force.array(props.setup); // allows a single item
|
|
142
|
+
props.teardown = force.array(props.teardown); // allows a single item
|
|
143
|
+
if (!Array.isArray(props.setup)) {
|
|
144
|
+
props.setup = [];
|
|
145
|
+
}
|
|
146
|
+
if (props.locals === null) {
|
|
147
|
+
throw new BadRequestError("locals cannot be null");
|
|
148
|
+
}
|
|
149
|
+
if (props.locals) {
|
|
150
|
+
if (typeof props.locals !== "object" || Array.isArray(props.locals)) {
|
|
151
|
+
throw new BadRequestError("locals must be an object");
|
|
152
|
+
}
|
|
153
|
+
// Locals
|
|
154
|
+
const keys = Object.keys(props.locals);
|
|
155
|
+
if (keys.length > 0) {
|
|
156
|
+
props.setup.push((req = {}) => {
|
|
157
|
+
if (typeof req !== "object") {
|
|
158
|
+
throw new BadRequestError("req must be an object");
|
|
159
|
+
}
|
|
160
|
+
// Set req.locals if it doesn't exist
|
|
161
|
+
if (!req.locals) req.locals = {};
|
|
162
|
+
if (typeof req.locals !== "object" || Array.isArray(req.locals)) {
|
|
163
|
+
throw new BadRequestError("req.locals must be an object");
|
|
164
|
+
}
|
|
165
|
+
if (!req.locals._jaypie) req.locals._jaypie = {};
|
|
166
|
+
});
|
|
167
|
+
const localsSetup = async (localsReq, localsRes) => {
|
|
168
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
169
|
+
const key = keys[i];
|
|
170
|
+
if (typeof props.locals[key] === "function") {
|
|
171
|
+
// eslint-disable-next-line no-await-in-loop
|
|
172
|
+
localsReq.locals[key] = await props.locals[key](
|
|
173
|
+
localsReq,
|
|
174
|
+
localsRes,
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
localsReq.locals[key] = props.locals[key];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
props.setup.push(localsSetup);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return jaypieHandler(handler, props);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// @jaypie/lambda
|
|
188
|
+
|
|
189
|
+
// For testing, this is the same as the jaypieHandler
|
|
190
|
+
export const lambdaHandler = vi.fn((handler, props = {}) => {
|
|
191
|
+
return jaypieHandler(handler, props);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// @jaypie/mongoose
|
|
195
|
+
|
|
196
|
+
export const connect = vi.fn(() => {
|
|
197
|
+
return true;
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
export const connectFromSecretEnv = vi.fn(() => {
|
|
201
|
+
return true;
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
export const disconnect = vi.fn(() => {
|
|
205
|
+
return true;
|
|
206
|
+
});
|