@jaypie/testkit 1.0.25 → 1.0.27
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
CHANGED
|
@@ -22,7 +22,7 @@ The testkit provides a complete mock for Jaypie including:
|
|
|
22
22
|
* Most non-utility functions are mocked to allow simple testing
|
|
23
23
|
|
|
24
24
|
```javascript
|
|
25
|
-
vi.mock("jaypie", vi.importActual("@jaypie/testkit"));
|
|
25
|
+
vi.mock("jaypie", async () => vi.importActual("@jaypie/testkit/mock"));
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
#### Log Spying
|
|
@@ -30,7 +30,7 @@ vi.mock("jaypie", vi.importActual("@jaypie/testkit"));
|
|
|
30
30
|
```javascript
|
|
31
31
|
import { log } from "jaypie";
|
|
32
32
|
|
|
33
|
-
vi.mock("jaypie", vi.importActual("@jaypie/testkit"));
|
|
33
|
+
vi.mock("jaypie", async () => vi.importActual("@jaypie/testkit/mock"));
|
|
34
34
|
|
|
35
35
|
afterEach(() => {
|
|
36
36
|
vi.clearAllMocks();
|
|
@@ -59,6 +59,8 @@ describe("Observability", () => {
|
|
|
59
59
|
// Act
|
|
60
60
|
await myNewFunction(); // TODO: add any "happy path" parameters
|
|
61
61
|
// Assert
|
|
62
|
+
expect(log).not.toBeCalledAboveTrace();
|
|
63
|
+
// or individually:
|
|
62
64
|
expect(log.debug).not.toHaveBeenCalled();
|
|
63
65
|
expect(log.info).not.toHaveBeenCalled();
|
|
64
66
|
expect(log.warn).not.toHaveBeenCalled();
|
|
@@ -131,6 +133,7 @@ A [JSON Schema](https://json-schema.org/) validator for the [JSON:API](https://j
|
|
|
131
133
|
|
|
132
134
|
```javascript
|
|
133
135
|
export default {
|
|
136
|
+
toBeCalledAboveTrace,
|
|
134
137
|
toBeCalledWithInitialParams,
|
|
135
138
|
toBeClass,
|
|
136
139
|
toBeJaypieError,
|
|
@@ -164,6 +167,18 @@ expect.extend(extendedMatchers);
|
|
|
164
167
|
expect.extend(jaypieMatchers);
|
|
165
168
|
```
|
|
166
169
|
|
|
170
|
+
#### `expect(subject).toBeCalledAboveTrace()`
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
import { log } from "@jaypie/core";
|
|
174
|
+
|
|
175
|
+
log.trace("Hello, World!");
|
|
176
|
+
expect(log).not.toBeCalledAboveTrace();
|
|
177
|
+
|
|
178
|
+
log.warn("Look out, World!");
|
|
179
|
+
expect(log).toBeCalledAboveTrace();
|
|
180
|
+
```
|
|
181
|
+
|
|
167
182
|
#### `expect(subject).toBeJaypieError()`
|
|
168
183
|
|
|
169
184
|
Validates instance objects:
|
|
@@ -315,6 +330,7 @@ const event = sqsTestRecords(
|
|
|
315
330
|
|
|
316
331
|
| Date | Version | Summary |
|
|
317
332
|
| ---------- | ------- | -------------- |
|
|
333
|
+
| 9/13/2024 | 1.0.27 | Matcher `toBeCalledAboveTrace` |
|
|
318
334
|
| 7/16/2024 | 1.0.21 | Export Jaypie mock as default |
|
|
319
335
|
| 3/20/2024 | 1.0.2 | Export `LOG` |
|
|
320
336
|
| 3/16/2024 | 1.0.0 | Artists ship |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaypie/testkit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.27",
|
|
4
4
|
"author": "Finlayson Studio",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -24,12 +24,14 @@
|
|
|
24
24
|
"new:test": "hygen jaypie vitest",
|
|
25
25
|
"test": "vitest",
|
|
26
26
|
"test:spec:constants": "vitest run ./src/__tests__/constants.spec.js",
|
|
27
|
+
"test:spec:expressHandler.mock": "vitest run ./src/__tests__/expressHandler-supertest.mock.spec.js",
|
|
27
28
|
"test:spec:index": "vitest run ./src/__tests__/index.spec.js",
|
|
28
29
|
"test:spec:jaypie.mock": "vitest run ./src/__tests__/jaypie.mock.spec.js",
|
|
29
30
|
"test:spec:jsonApiSchema.module": "vitest run ./src/__tests__/jsonApiSchema.module.spec.js",
|
|
30
31
|
"test:spec:matchers.module": "vitest run ./src/__tests__/matchers.module.spec.js",
|
|
31
32
|
"test:spec:mockLog.module": "vitest run ./src/__tests__/mockLog.module.spec.js",
|
|
32
33
|
"test:spec:sqsTestRecords.function": "vitest run ./src/__tests__/sqsTestRecords.function.spec.js",
|
|
34
|
+
"test:spec:toBeCalledAboveTrace.matcher": "vitest run ./src/matchers/__tests__/toBeCalledAboveTrace.matcher.spec.js",
|
|
33
35
|
"test:spec:toBeCalledWithInitialParams.matcher": "vitest run ./src/matchers/__tests__/toBeCalledWithInitialParams.matcher.spec.js",
|
|
34
36
|
"test:spec:toBeClass.matcher": "vitest run ./src/matchers/__tests__/toBeClass.matcher.spec.js",
|
|
35
37
|
"test:spec:toBeJaypieError.matcher": "vitest run ./src/matchers/__tests__/toBeJaypieError.matcher.spec.js",
|
|
@@ -46,10 +48,12 @@
|
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"eslint": "^8.57.0",
|
|
48
50
|
"eslint-config-jaypie": "^1.0.7",
|
|
51
|
+
"express": "^4.19.2",
|
|
49
52
|
"hygen": "^6.2.11",
|
|
50
53
|
"jest-extended": "^4.0.2",
|
|
51
54
|
"prettier": "^3.2.5",
|
|
52
55
|
"sort-package-json": "^2.8.0",
|
|
56
|
+
"supertest": "^7.0.0",
|
|
53
57
|
"vitest": "^1.4.0"
|
|
54
58
|
}
|
|
55
59
|
}
|
package/src/jaypie.mock.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
JAYPIE,
|
|
7
7
|
log,
|
|
8
8
|
UnavailableError,
|
|
9
|
+
UnhandledError,
|
|
9
10
|
} from "@jaypie/core";
|
|
10
11
|
import { beforeAll, vi } from "vitest";
|
|
11
12
|
|
|
@@ -138,6 +139,12 @@ export const submitMetricSet = vi.fn(() => {
|
|
|
138
139
|
// @jaypie/express
|
|
139
140
|
|
|
140
141
|
export const expressHandler = vi.fn((handler, props = {}) => {
|
|
142
|
+
// If handler is an object and options is a function, swap them
|
|
143
|
+
if (typeof handler === "object" && typeof props === "function") {
|
|
144
|
+
const temp = handler;
|
|
145
|
+
handler = props;
|
|
146
|
+
props = temp;
|
|
147
|
+
}
|
|
141
148
|
if (typeof handler !== "function") {
|
|
142
149
|
throw new BadRequestError("handler must be a function");
|
|
143
150
|
}
|
|
@@ -190,47 +197,65 @@ export const expressHandler = vi.fn((handler, props = {}) => {
|
|
|
190
197
|
const jaypieFunction = jaypieHandler(handler, props);
|
|
191
198
|
return async (req = {}, res = {}, ...extra) => {
|
|
192
199
|
const status = HTTP.CODE.OK;
|
|
193
|
-
|
|
194
|
-
|
|
200
|
+
let response;
|
|
201
|
+
let supertestMode = false;
|
|
202
|
+
if (
|
|
203
|
+
res &&
|
|
204
|
+
typeof res.socket === "object" &&
|
|
205
|
+
res.constructor.name === "ServerResponse"
|
|
206
|
+
) {
|
|
207
|
+
// Use the response object in supertest mode
|
|
208
|
+
supertestMode = true;
|
|
195
209
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
210
|
+
try {
|
|
211
|
+
response = await jaypieFunction(req, res, ...extra);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
// In the mock context, if status is a function we are in a "supertest"
|
|
214
|
+
if (supertestMode) {
|
|
215
|
+
// In theory jaypieFunction has handled all errors
|
|
216
|
+
const errorStatus = error.status || HTTP.CODE.INTERNAL_SERVER_ERROR;
|
|
217
|
+
let errorResponse;
|
|
218
|
+
if (typeof error.json === "function") {
|
|
219
|
+
errorResponse = error.json();
|
|
203
220
|
} else {
|
|
204
|
-
|
|
221
|
+
// This should never happen
|
|
222
|
+
errorResponse = new UnhandledError().json();
|
|
223
|
+
}
|
|
224
|
+
res.status(errorStatus).json(errorResponse);
|
|
225
|
+
return;
|
|
226
|
+
} else {
|
|
227
|
+
// else, res.status is not a function, throw the error
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (supertestMode) {
|
|
232
|
+
if (response) {
|
|
233
|
+
// res.status(200);
|
|
234
|
+
if (typeof response === "object") {
|
|
235
|
+
if (typeof response.json === "function") {
|
|
236
|
+
res.json(response.json());
|
|
237
|
+
} else {
|
|
205
238
|
res.status(status).json(response);
|
|
206
239
|
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
if (res && typeof res.status === "function") {
|
|
240
|
+
} else if (typeof response === "string") {
|
|
241
|
+
try {
|
|
211
242
|
res.status(status).json(JSON.parse(response));
|
|
243
|
+
} catch (error) {
|
|
244
|
+
if (supertestMode) {
|
|
245
|
+
res.status(status).send(response);
|
|
246
|
+
}
|
|
212
247
|
}
|
|
213
|
-
}
|
|
214
|
-
if (res && typeof res.status === "function") {
|
|
215
|
-
res.status(status).send(response);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
} else if (response === true) {
|
|
219
|
-
if (res && typeof res.status === "function") {
|
|
248
|
+
} else if (response === true) {
|
|
220
249
|
res.status(HTTP.CODE.CREATED).send();
|
|
221
|
-
}
|
|
222
|
-
} else {
|
|
223
|
-
if (res && typeof res.status === "function") {
|
|
250
|
+
} else {
|
|
224
251
|
res.status(status).send(response);
|
|
225
252
|
}
|
|
226
|
-
}
|
|
227
|
-
} else {
|
|
228
|
-
// No response
|
|
229
|
-
if (res && typeof res.status === "function") {
|
|
253
|
+
} else {
|
|
230
254
|
res.status(HTTP.CODE.NO_CONTENT).send();
|
|
231
255
|
}
|
|
256
|
+
} else {
|
|
257
|
+
return response;
|
|
232
258
|
}
|
|
233
|
-
return response;
|
|
234
259
|
};
|
|
235
260
|
});
|
|
236
261
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//
|
|
2
|
+
//
|
|
3
|
+
// Constants
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
//
|
|
8
|
+
// Helper Functions
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
//
|
|
12
|
+
//
|
|
13
|
+
// Main
|
|
14
|
+
//
|
|
15
|
+
|
|
16
|
+
const calledAboveTrace = (log) => {
|
|
17
|
+
// TODO: what if log is not an object?
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
if (
|
|
21
|
+
log.debug.mock.calls.length > 0 ||
|
|
22
|
+
log.info.mock.calls.length > 0 ||
|
|
23
|
+
log.warn.mock.calls.length > 0 ||
|
|
24
|
+
log.error.mock.calls.length > 0 ||
|
|
25
|
+
log.fatal.mock.calls.length > 0
|
|
26
|
+
) {
|
|
27
|
+
return {
|
|
28
|
+
message: () => `expected log not to have been called above trace`,
|
|
29
|
+
pass: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw Error(`[calledAboveTrace] log is not a mock object`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
message: () => `expected log not to have been called above trace`,
|
|
38
|
+
pass: false,
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
//
|
|
43
|
+
//
|
|
44
|
+
// Export
|
|
45
|
+
//
|
|
46
|
+
|
|
47
|
+
export default calledAboveTrace;
|
package/src/matchers.module.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { matchers as jsonSchemaMatchers } from "jest-json-schema";
|
|
2
2
|
|
|
3
|
+
import toBeCalledAboveTrace from "./matchers/toBeCalledAboveTrace.matcher.js";
|
|
3
4
|
import toBeCalledWithInitialParams from "./matchers/toBeCalledWithInitialParams.matcher.js";
|
|
4
5
|
import toBeClass from "./matchers/toBeClass.matcher.js";
|
|
5
6
|
import toBeJaypieError from "./matchers/toBeJaypieError.matcher.js";
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
//
|
|
29
30
|
|
|
30
31
|
export default {
|
|
32
|
+
toBeCalledAboveTrace,
|
|
31
33
|
toBeCalledWithInitialParams,
|
|
32
34
|
toBeClass,
|
|
33
35
|
toBeJaypieError,
|