@in2grate/testing 0.1.0

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.
Files changed (49) hide show
  1. package/dist/cassette-clients.d.ts +26 -0
  2. package/dist/cassette-clients.d.ts.map +1 -0
  3. package/dist/cassette-clients.js +174 -0
  4. package/dist/cassette-clients.js.map +1 -0
  5. package/dist/cassette-store.d.ts +16 -0
  6. package/dist/cassette-store.d.ts.map +1 -0
  7. package/dist/cassette-store.js +34 -0
  8. package/dist/cassette-store.js.map +1 -0
  9. package/dist/cassette.test.d.ts +2 -0
  10. package/dist/cassette.test.d.ts.map +1 -0
  11. package/dist/cassette.test.js +414 -0
  12. package/dist/cassette.test.js.map +1 -0
  13. package/dist/error-helpers.test.d.ts +2 -0
  14. package/dist/error-helpers.test.d.ts.map +1 -0
  15. package/dist/error-helpers.test.js +66 -0
  16. package/dist/error-helpers.test.js.map +1 -0
  17. package/dist/http-mocks.test.d.ts +2 -0
  18. package/dist/http-mocks.test.d.ts.map +1 -0
  19. package/dist/http-mocks.test.js +89 -0
  20. package/dist/http-mocks.test.js.map +1 -0
  21. package/dist/index.d.ts +133 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +333 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/oauth.test.d.ts +2 -0
  26. package/dist/oauth.test.d.ts.map +1 -0
  27. package/dist/oauth.test.js +53 -0
  28. package/dist/oauth.test.js.map +1 -0
  29. package/dist/poll.test.d.ts +2 -0
  30. package/dist/poll.test.d.ts.map +1 -0
  31. package/dist/poll.test.js +78 -0
  32. package/dist/poll.test.js.map +1 -0
  33. package/dist/redact.d.ts +20 -0
  34. package/dist/redact.d.ts.map +1 -0
  35. package/dist/redact.js +83 -0
  36. package/dist/redact.js.map +1 -0
  37. package/dist/replay.test.d.ts +2 -0
  38. package/dist/replay.test.d.ts.map +1 -0
  39. package/dist/replay.test.js +169 -0
  40. package/dist/replay.test.js.map +1 -0
  41. package/dist/secrets.test.d.ts +2 -0
  42. package/dist/secrets.test.d.ts.map +1 -0
  43. package/dist/secrets.test.js +30 -0
  44. package/dist/secrets.test.js.map +1 -0
  45. package/dist/state.test.d.ts +2 -0
  46. package/dist/state.test.d.ts.map +1 -0
  47. package/dist/state.test.js +66 -0
  48. package/dist/state.test.js.map +1 -0
  49. package/package.json +32 -0
@@ -0,0 +1,414 @@
1
+ import { describe, it, before, after } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import http from 'node:http';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import os from 'node:os';
7
+ import { defineFlow } from '@in2grate/sdk';
8
+ import { runFlowTest } from './index.js';
9
+ import { redactHeaders, hashBody, redactBody } from './redact.js';
10
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
11
+ function startMockServer(handler) {
12
+ return new Promise((resolve, reject) => {
13
+ const server = http.createServer(handler);
14
+ server.once('error', reject);
15
+ server.listen(0, '127.0.0.1', () => {
16
+ const addr = server.address();
17
+ resolve({
18
+ port: addr.port,
19
+ close: () => new Promise((res) => server.close(() => res())),
20
+ });
21
+ });
22
+ });
23
+ }
24
+ function setEnv(key, value) {
25
+ const prev = process.env[key];
26
+ if (value === undefined) {
27
+ delete process.env[key];
28
+ }
29
+ else {
30
+ process.env[key] = value;
31
+ }
32
+ return prev;
33
+ }
34
+ // ─── redactHeaders ────────────────────────────────────────────────────────────
35
+ describe('redactHeaders', () => {
36
+ it('redacts Authorization header', () => {
37
+ const result = redactHeaders({ Authorization: 'Bearer secret-token' });
38
+ assert.equal(result['Authorization'], '[REDACTED]');
39
+ });
40
+ it('redacts cookie header (case-insensitive)', () => {
41
+ const result = redactHeaders({ cookie: 'session=abc123', Cookie: 'session=xyz' });
42
+ assert.equal(result['cookie'], '[REDACTED]');
43
+ assert.equal(result['Cookie'], '[REDACTED]');
44
+ });
45
+ it('redacts set-cookie header', () => {
46
+ const result = redactHeaders({ 'set-cookie': 'session=secret-value; HttpOnly' });
47
+ assert.equal(result['set-cookie'], '[REDACTED]');
48
+ });
49
+ it('redacts headers containing "token"', () => {
50
+ const result = redactHeaders({ 'x-access-token': 'my-token-value' });
51
+ assert.equal(result['x-access-token'], '[REDACTED]');
52
+ });
53
+ it('redacts headers containing "secret"', () => {
54
+ const result = redactHeaders({ 'x-api-secret': 'very-secret' });
55
+ assert.equal(result['x-api-secret'], '[REDACTED]');
56
+ });
57
+ it('redacts headers containing "key"', () => {
58
+ const result = redactHeaders({ 'x-api-key': 'key-value' });
59
+ assert.equal(result['x-api-key'], '[REDACTED]');
60
+ });
61
+ it('leaves non-sensitive headers unchanged', () => {
62
+ const headers = {
63
+ 'content-type': 'application/json',
64
+ 'x-request-id': 'abc-123',
65
+ accept: 'application/json',
66
+ };
67
+ const result = redactHeaders(headers);
68
+ assert.deepEqual(result, headers);
69
+ });
70
+ });
71
+ // ─── hashBody ─────────────────────────────────────────────────────────────────
72
+ describe('hashBody', () => {
73
+ it('returns empty string for null/undefined', () => {
74
+ assert.equal(hashBody(null), '');
75
+ assert.equal(hashBody(undefined), '');
76
+ });
77
+ it('same JSON body hashes the same regardless of key order', () => {
78
+ const h1 = hashBody({ b: 2, a: 1 });
79
+ const h2 = hashBody({ a: 1, b: 2 });
80
+ assert.equal(h1, h2, 'Hashes must be order-independent for JSON bodies');
81
+ });
82
+ it('different bodies produce different hashes', () => {
83
+ assert.notEqual(hashBody({ action: 'a' }), hashBody({ action: 'b' }));
84
+ });
85
+ it('hashes string bodies directly', () => {
86
+ assert.ok(hashBody('hello').length === 64, 'SHA-256 hex should be 64 chars');
87
+ });
88
+ });
89
+ // ─── redactBody ───────────────────────────────────────────────────────────────
90
+ describe('redactBody', () => {
91
+ it('redacts top-level fields from IN2_CASSETTE_REDACT_PATHS', () => {
92
+ const prev = setEnv('IN2_CASSETTE_REDACT_PATHS', 'access_token,secret');
93
+ try {
94
+ const result = redactBody({ access_token: 'tok-123', name: 'alice', secret: 'shh' });
95
+ const obj = result;
96
+ assert.equal(obj['access_token'], '[REDACTED]');
97
+ assert.equal(obj['secret'], '[REDACTED]');
98
+ assert.equal(obj['name'], 'alice');
99
+ }
100
+ finally {
101
+ setEnv('IN2_CASSETTE_REDACT_PATHS', prev);
102
+ }
103
+ });
104
+ it('redacts nested dot-path fields', () => {
105
+ const prev = setEnv('IN2_CASSETTE_REDACT_PATHS', 'data.token');
106
+ try {
107
+ const result = redactBody({ data: { token: 'tok-xyz', id: 1 } });
108
+ const obj = result;
109
+ assert.equal(obj.data['token'], '[REDACTED]');
110
+ assert.equal(obj.data['id'], 1);
111
+ }
112
+ finally {
113
+ setEnv('IN2_CASSETTE_REDACT_PATHS', prev);
114
+ }
115
+ });
116
+ it('returns body unchanged when IN2_CASSETTE_REDACT_PATHS is empty', () => {
117
+ const prev = setEnv('IN2_CASSETTE_REDACT_PATHS', '');
118
+ try {
119
+ const body = { access_token: 'tok', name: 'alice' };
120
+ const result = redactBody(body);
121
+ assert.deepEqual(result, body);
122
+ }
123
+ finally {
124
+ setEnv('IN2_CASSETTE_REDACT_PATHS', prev);
125
+ }
126
+ });
127
+ });
128
+ // ─── CAR: cassette record/replay via runFlowTest ──────────────────────────────
129
+ describe('cassette record/replay (CAR)', () => {
130
+ let tempDir;
131
+ before(() => {
132
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'in2-cassette-test-'));
133
+ });
134
+ after(() => {
135
+ fs.rmSync(tempDir, { recursive: true, force: true });
136
+ });
137
+ it('CAR-01: record mode writes cassette file with interactions', async () => {
138
+ const mock = await startMockServer((_req, res) => {
139
+ res.writeHead(200, { 'content-type': 'application/json' });
140
+ res.end(JSON.stringify({ hello: 'world' }));
141
+ });
142
+ const prevMode = setEnv('IN2_CASSETTE_MODE', 'record');
143
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
144
+ const prevName = setEnv('IN2_CASSETTE_TEST_NAME', 'car-01');
145
+ try {
146
+ const flow = defineFlow({
147
+ name: 'car-01',
148
+ trigger: { type: 'webhook' },
149
+ async handler(ctx) {
150
+ return ctx.http.get(`http://127.0.0.1:${mock.port}/greet`);
151
+ },
152
+ });
153
+ const result = await runFlowTest(flow, { input: {} });
154
+ assert.equal(result.httpCalls.length, 1);
155
+ const cassetteFile = path.join(tempDir, 'car-01.json');
156
+ assert.ok(fs.existsSync(cassetteFile), 'cassette file should be created');
157
+ const cassette = JSON.parse(fs.readFileSync(cassetteFile, 'utf-8'));
158
+ assert.equal(cassette.meta.version, 1);
159
+ assert.ok(typeof cassette.meta.createdAt === 'string');
160
+ assert.equal(cassette.interactions.length, 1);
161
+ assert.equal(cassette.interactions[0].request.method, 'GET');
162
+ assert.equal(cassette.interactions[0].response.status, 200);
163
+ assert.equal(cassette.interactions[0].response.bodyType, 'json');
164
+ }
165
+ finally {
166
+ await mock.close();
167
+ setEnv('IN2_CASSETTE_MODE', prevMode);
168
+ setEnv('IN2_CASSETTE_DIR', prevDir);
169
+ setEnv('IN2_CASSETTE_TEST_NAME', prevName);
170
+ }
171
+ });
172
+ it('CAR-02: replay mode serves response from cassette without real network', async () => {
173
+ const cassetteName = 'car-02';
174
+ const cassette = {
175
+ meta: { createdAt: new Date().toISOString(), version: 1 },
176
+ interactions: [
177
+ {
178
+ request: { method: 'GET', url: 'https://example.test/data', headers: {}, bodyHash: '' },
179
+ response: { status: 200, headers: {}, bodyType: 'json', body: { value: 99 } },
180
+ },
181
+ ],
182
+ };
183
+ fs.writeFileSync(path.join(tempDir, `${cassetteName}.json`), JSON.stringify(cassette), 'utf-8');
184
+ const prevMode = setEnv('IN2_CASSETTE_MODE', 'replay');
185
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
186
+ const prevName = setEnv('IN2_CASSETTE_TEST_NAME', cassetteName);
187
+ try {
188
+ const flow = defineFlow({
189
+ name: cassetteName,
190
+ trigger: { type: 'webhook' },
191
+ async handler(ctx) {
192
+ const res = await ctx.http.get('https://example.test/data');
193
+ return { value: res.data.value };
194
+ },
195
+ });
196
+ const result = await runFlowTest(flow, { input: {} });
197
+ assert.deepEqual(result.output, { value: 99 });
198
+ assert.equal(result.httpCalls.length, 1);
199
+ }
200
+ finally {
201
+ setEnv('IN2_CASSETTE_MODE', prevMode);
202
+ setEnv('IN2_CASSETTE_DIR', prevDir);
203
+ setEnv('IN2_CASSETTE_TEST_NAME', prevName);
204
+ }
205
+ });
206
+ it('CAR-02b: explicit cassetteName replays by default when a cassette exists', async () => {
207
+ const cassetteName = 'car-02b';
208
+ const cassette = {
209
+ meta: { createdAt: new Date().toISOString(), version: 1 },
210
+ interactions: [
211
+ {
212
+ request: {
213
+ method: 'GET',
214
+ url: 'https://example.test/default-replay',
215
+ headers: {},
216
+ bodyHash: '',
217
+ },
218
+ response: { status: 200, headers: {}, bodyType: 'json', body: { value: 42 } },
219
+ },
220
+ ],
221
+ };
222
+ fs.writeFileSync(path.join(tempDir, `${cassetteName}.json`), JSON.stringify(cassette), 'utf-8');
223
+ const prevMode = setEnv('IN2_CASSETTE_MODE', undefined);
224
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
225
+ const prevName = setEnv('IN2_CASSETTE_TEST_NAME', undefined);
226
+ try {
227
+ const flow = defineFlow({
228
+ name: 'car-02b-flow',
229
+ trigger: { type: 'webhook' },
230
+ async handler(ctx) {
231
+ const res = await ctx.http.get('https://example.test/default-replay');
232
+ return { value: res.data.value };
233
+ },
234
+ });
235
+ const result = await runFlowTest(flow, { input: {}, cassetteName });
236
+ assert.deepEqual(result.output, { value: 42 });
237
+ assert.equal(result.httpCalls.length, 1);
238
+ }
239
+ finally {
240
+ setEnv('IN2_CASSETTE_MODE', prevMode);
241
+ setEnv('IN2_CASSETTE_DIR', prevDir);
242
+ setEnv('IN2_CASSETTE_TEST_NAME', prevName);
243
+ }
244
+ });
245
+ it('CAR-03: cassette miss in replay throws with in2 test --record hint', async () => {
246
+ const prevMode = setEnv('IN2_CASSETTE_MODE', 'replay');
247
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
248
+ const prevName = setEnv('IN2_CASSETTE_TEST_NAME', 'car-03-nonexistent');
249
+ try {
250
+ const flow = defineFlow({
251
+ name: 'car-03',
252
+ trigger: { type: 'webhook' },
253
+ async handler(ctx) {
254
+ return ctx.http.get('https://example.test/missing');
255
+ },
256
+ });
257
+ // No cassette file exists → the error is thrown lazily when an HTTP call is made
258
+ await assert.rejects(() => runFlowTest(flow, { input: {} }), (err) => {
259
+ assert.ok(err.message.includes('in2 test --record'), `Expected "--record" hint in error message, got:\n${err.message}`);
260
+ assert.ok(err.message.includes('car-03-nonexistent'), `Expected cassette name in error message, got:\n${err.message}`);
261
+ return true;
262
+ });
263
+ }
264
+ finally {
265
+ setEnv('IN2_CASSETTE_MODE', prevMode);
266
+ setEnv('IN2_CASSETTE_DIR', prevDir);
267
+ setEnv('IN2_CASSETTE_TEST_NAME', prevName);
268
+ }
269
+ });
270
+ it('CAR-04: recorded cassette contains no Authorization or Cookie values', async () => {
271
+ const mock = await startMockServer((_req, res) => {
272
+ res.writeHead(200, {
273
+ 'content-type': 'application/json',
274
+ 'set-cookie': 'session=secret-cookie-value; HttpOnly',
275
+ });
276
+ res.end(JSON.stringify({ ok: true }));
277
+ });
278
+ const prevMode = setEnv('IN2_CASSETTE_MODE', 'record');
279
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
280
+ const prevName = setEnv('IN2_CASSETTE_TEST_NAME', 'car-04');
281
+ try {
282
+ const flow = defineFlow({
283
+ name: 'car-04',
284
+ trigger: { type: 'webhook' },
285
+ async handler(ctx) {
286
+ return ctx.http.get(`http://127.0.0.1:${mock.port}/secure`, {
287
+ headers: {
288
+ Authorization: 'Bearer super-secret-token-1234',
289
+ Cookie: 'session=my-cookie-value',
290
+ },
291
+ });
292
+ },
293
+ });
294
+ await runFlowTest(flow, { input: {} });
295
+ const cassetteRaw = fs.readFileSync(path.join(tempDir, 'car-04.json'), 'utf-8');
296
+ assert.ok(!cassetteRaw.includes('super-secret-token-1234'), 'Authorization value must not appear in cassette');
297
+ assert.ok(!cassetteRaw.includes('my-cookie-value'), 'Cookie request value must not appear in cassette');
298
+ assert.ok(!cassetteRaw.includes('secret-cookie-value'), 'Set-Cookie response value must not appear in cassette');
299
+ }
300
+ finally {
301
+ await mock.close();
302
+ setEnv('IN2_CASSETTE_MODE', prevMode);
303
+ setEnv('IN2_CASSETTE_DIR', prevDir);
304
+ setEnv('IN2_CASSETTE_TEST_NAME', prevName);
305
+ }
306
+ });
307
+ it('CAR-05: body hash matching — two different POST bodies are matched independently', async () => {
308
+ const mock = await startMockServer((req, res) => {
309
+ let body = '';
310
+ req.on('data', (chunk) => {
311
+ body += chunk.toString();
312
+ });
313
+ req.on('end', () => {
314
+ const parsed = JSON.parse(body);
315
+ res.writeHead(200, { 'content-type': 'application/json' });
316
+ res.end(JSON.stringify({ result: parsed.action }));
317
+ });
318
+ });
319
+ const cassetteName = 'car-05';
320
+ const prevMode = setEnv('IN2_CASSETTE_MODE', 'record');
321
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
322
+ const prevName = setEnv('IN2_CASSETTE_TEST_NAME', cassetteName);
323
+ try {
324
+ // Record a single run that makes two POST calls with different bodies
325
+ const flow = defineFlow({
326
+ name: cassetteName,
327
+ trigger: { type: 'webhook' },
328
+ async handler(ctx) {
329
+ const resA = await ctx.http.post(`http://127.0.0.1:${mock.port}/submit`, { action: 'a' });
330
+ const resB = await ctx.http.post(`http://127.0.0.1:${mock.port}/submit`, { action: 'b' });
331
+ return { a: resA.data.result, b: resB.data.result };
332
+ },
333
+ });
334
+ await runFlowTest(flow, { input: {} });
335
+ // Verify cassette has 2 interactions with different body hashes
336
+ const cassette = JSON.parse(fs.readFileSync(path.join(tempDir, `${cassetteName}.json`), 'utf-8'));
337
+ assert.equal(cassette.interactions.length, 2);
338
+ assert.notEqual(cassette.interactions[0].request.bodyHash, cassette.interactions[1].request.bodyHash, 'Body hashes must differ for different request bodies');
339
+ // Replay — responses should match based on body hash, not position
340
+ setEnv('IN2_CASSETTE_MODE', 'replay');
341
+ const replayResult = await runFlowTest(flow, { input: {} });
342
+ assert.deepEqual(replayResult.output, { a: 'a', b: 'b' });
343
+ }
344
+ finally {
345
+ await mock.close();
346
+ setEnv('IN2_CASSETTE_MODE', prevMode);
347
+ setEnv('IN2_CASSETTE_DIR', prevDir);
348
+ setEnv('IN2_CASSETTE_TEST_NAME', prevName);
349
+ }
350
+ });
351
+ it('CAR-06: cassetteName option overrides IN2_CASSETTE_TEST_NAME', async () => {
352
+ const cassette = {
353
+ meta: { createdAt: new Date().toISOString(), version: 1 },
354
+ interactions: [
355
+ {
356
+ request: { method: 'GET', url: 'https://example.test/thing', headers: {}, bodyHash: '' },
357
+ response: { status: 200, headers: {}, bodyType: 'json', body: { explicit: true } },
358
+ },
359
+ ],
360
+ };
361
+ fs.writeFileSync(path.join(tempDir, 'explicit-name.json'), JSON.stringify(cassette), 'utf-8');
362
+ const prevMode = setEnv('IN2_CASSETTE_MODE', 'replay');
363
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
364
+ const prevName = setEnv('IN2_CASSETTE_TEST_NAME', 'wrong-name');
365
+ try {
366
+ const flow = defineFlow({
367
+ name: 'car-06',
368
+ trigger: { type: 'webhook' },
369
+ async handler(ctx) {
370
+ const res = await ctx.http.get('https://example.test/thing');
371
+ return res.data;
372
+ },
373
+ });
374
+ // cassetteName option should win over IN2_CASSETTE_TEST_NAME env var
375
+ const result = await runFlowTest(flow, { input: {}, cassetteName: 'explicit-name' });
376
+ assert.deepEqual(result.output, { explicit: true });
377
+ }
378
+ finally {
379
+ setEnv('IN2_CASSETTE_MODE', prevMode);
380
+ setEnv('IN2_CASSETTE_DIR', prevDir);
381
+ setEnv('IN2_CASSETTE_TEST_NAME', prevName);
382
+ }
383
+ });
384
+ it('CAR-07: explicit httpMocks take precedence over IN2_CASSETTE_MODE', async () => {
385
+ const prevMode = setEnv('IN2_CASSETTE_MODE', 'record');
386
+ const prevDir = setEnv('IN2_CASSETTE_DIR', tempDir);
387
+ try {
388
+ const flow = defineFlow({
389
+ name: 'car-07',
390
+ trigger: { type: 'webhook' },
391
+ async handler(ctx) {
392
+ const res = await ctx.http.get('https://api.example.com/mocked');
393
+ return res.data;
394
+ },
395
+ });
396
+ // httpMocks is set → must be used, ignore IN2_CASSETTE_MODE=record
397
+ const result = await runFlowTest(flow, {
398
+ input: {},
399
+ httpMocks: {
400
+ 'https://api.example.com/mocked': { status: 200, data: { mocked: true } },
401
+ },
402
+ });
403
+ assert.deepEqual(result.output, { mocked: true });
404
+ // No cassette file should have been written
405
+ const cassetteFile = path.join(tempDir, 'car-07.json');
406
+ assert.ok(!fs.existsSync(cassetteFile), 'No cassette should be written when httpMocks is set');
407
+ }
408
+ finally {
409
+ setEnv('IN2_CASSETTE_MODE', prevMode);
410
+ setEnv('IN2_CASSETTE_DIR', prevDir);
411
+ }
412
+ });
413
+ });
414
+ //# sourceMappingURL=cassette.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cassette.test.js","sourceRoot":"","sources":["../src/cassette.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=error-helpers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-helpers.test.d.ts","sourceRoot":"","sources":["../src/error-helpers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,66 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { assertThrows, assertPermanentError } from './index.js';
4
+ describe('assertThrows', () => {
5
+ it('returns the thrown error when fn throws', async () => {
6
+ const err = await assertThrows(async () => {
7
+ throw new Error('boom');
8
+ });
9
+ assert.equal(err.message, 'boom');
10
+ });
11
+ it('fails when fn does not throw', async () => {
12
+ await assert.rejects(() => assertThrows(async () => 'resolved fine'), /Expected function to throw/);
13
+ });
14
+ it('string matcher — passes when message includes the string', async () => {
15
+ const err = await assertThrows(async () => {
16
+ throw new Error('intentional failure here');
17
+ }, 'intentional failure');
18
+ assert.ok(err.message.includes('intentional failure'));
19
+ });
20
+ it('string matcher — fails when message does not include the string', async () => {
21
+ await assert.rejects(() => assertThrows(async () => {
22
+ throw new Error('something else');
23
+ }, 'intentional failure'), /Expected error message to include/);
24
+ });
25
+ it('RegExp matcher — passes when message matches', async () => {
26
+ const err = await assertThrows(async () => {
27
+ throw new Error('error code 404');
28
+ }, /code \d+/);
29
+ assert.match(err.message, /code \d+/);
30
+ });
31
+ it('RegExp matcher — fails when message does not match', async () => {
32
+ await assert.rejects(() => assertThrows(async () => {
33
+ throw new Error('something');
34
+ }, /code \d+/), /Expected error message to match/);
35
+ });
36
+ it('function matcher — passes when predicate returns true', async () => {
37
+ const err = await assertThrows(async () => {
38
+ throw Object.assign(new Error('typed'), { code: 42 });
39
+ }, (e) => e.code === 42);
40
+ assert.equal(err.code, 42);
41
+ });
42
+ it('function matcher — fails when predicate returns false', async () => {
43
+ await assert.rejects(() => assertThrows(async () => {
44
+ throw new Error('wrong');
45
+ }, (e) => e.message === 'right'), /Matcher predicate returned false/);
46
+ });
47
+ });
48
+ describe('assertPermanentError', () => {
49
+ it('passes when fn throws an error with name === "PermanentError"', async () => {
50
+ class PermanentError extends Error {
51
+ name = 'PermanentError';
52
+ }
53
+ await assertPermanentError(async () => {
54
+ throw new PermanentError('bad input');
55
+ });
56
+ });
57
+ it('fails when fn throws a plain Error', async () => {
58
+ await assert.rejects(() => assertPermanentError(async () => {
59
+ throw new Error('regular error');
60
+ }), /Expected a PermanentError/);
61
+ });
62
+ it('fails when fn does not throw', async () => {
63
+ await assert.rejects(() => assertPermanentError(async () => 'fine'), /Expected function to throw/);
64
+ });
65
+ });
66
+ //# sourceMappingURL=error-helpers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-helpers.test.js","sourceRoot":"","sources":["../src/error-helpers.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=http-mocks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-mocks.test.d.ts","sourceRoot":"","sources":["../src/http-mocks.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { runFlowTest } from './index.js';
4
+ const flow = {
5
+ name: 'mock-test-flow',
6
+ trigger: { type: 'webhook' },
7
+ async handler(ctx, _input) {
8
+ const res = await ctx.http.get('https://api.example.com/resource');
9
+ return res.data;
10
+ },
11
+ };
12
+ const postFlow = {
13
+ name: 'mock-post-flow',
14
+ trigger: { type: 'webhook' },
15
+ async handler(ctx, _input) {
16
+ const res = await ctx.http.post('https://api.example.com/resource', { foo: 'bar' });
17
+ return res.data;
18
+ },
19
+ };
20
+ const multiFlow = {
21
+ name: 'mock-multi-flow',
22
+ trigger: { type: 'webhook' },
23
+ async handler(ctx, _input) {
24
+ const get = await ctx.http.get('https://api.example.com/resource');
25
+ const post = await ctx.http.post('https://api.example.com/resource', {});
26
+ return { get: get.data, post: post.data };
27
+ },
28
+ };
29
+ describe('httpMocks — method-aware keys', () => {
30
+ it('plain URL key still works (backward compat)', async () => {
31
+ const result = await runFlowTest(flow, {
32
+ input: {},
33
+ httpMocks: { 'https://api.example.com/resource': { status: 200, data: { ok: true } } },
34
+ });
35
+ assert.deepEqual(result.output, { ok: true });
36
+ });
37
+ it('method-qualified key "GET https://..." matches a GET request', async () => {
38
+ const result = await runFlowTest(flow, {
39
+ input: {},
40
+ httpMocks: {
41
+ 'GET https://api.example.com/resource': { status: 200, data: { from: 'get-key' } },
42
+ },
43
+ });
44
+ assert.deepEqual(result.output, { from: 'get-key' });
45
+ });
46
+ it('method-qualified "POST https://..." matches POST but not GET to same URL', async () => {
47
+ await assert.rejects(() => runFlowTest(flow, {
48
+ input: {},
49
+ httpMocks: {
50
+ 'POST https://api.example.com/resource': { status: 200, data: { ok: true } },
51
+ },
52
+ }), /No HTTP mock/);
53
+ const result = await runFlowTest(postFlow, {
54
+ input: {},
55
+ httpMocks: {
56
+ 'POST https://api.example.com/resource': { status: 201, data: { created: true } },
57
+ },
58
+ });
59
+ assert.deepEqual(result.output, { created: true });
60
+ });
61
+ it('method-qualified key takes precedence over plain URL key', async () => {
62
+ const result = await runFlowTest(flow, {
63
+ input: {},
64
+ httpMocks: {
65
+ 'https://api.example.com/resource': { status: 200, data: { from: 'plain' } },
66
+ 'GET https://api.example.com/resource': { status: 200, data: { from: 'method-key' } },
67
+ },
68
+ });
69
+ assert.deepEqual(result.output, { from: 'method-key' });
70
+ });
71
+ it('different method keys route GET and POST to different mocks', async () => {
72
+ const result = await runFlowTest(multiFlow, {
73
+ input: {},
74
+ httpMocks: {
75
+ 'GET https://api.example.com/resource': { status: 200, data: { from: 'get' } },
76
+ 'POST https://api.example.com/resource': { status: 201, data: { from: 'post' } },
77
+ },
78
+ });
79
+ assert.deepEqual(result.output, { get: { from: 'get' }, post: { from: 'post' } });
80
+ });
81
+ it('error message mentions both key forms when mock is missing', async () => {
82
+ await assert.rejects(() => runFlowTest(flow, {
83
+ input: {},
84
+ httpMocks: {},
85
+ }), (err) => err.message.includes('GET https://api.example.com/resource') &&
86
+ err.message.includes('https://api.example.com/resource'));
87
+ });
88
+ });
89
+ //# sourceMappingURL=http-mocks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-mocks.test.js","sourceRoot":"","sources":["../src/http-mocks.test.ts"],"names":[],"mappings":"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"}