@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 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 { restoreLog, spyLog } from "@jaypie/testkit";
19
- import { log } from "@jaypie/core";
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.20",
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
+ });