@blucca/n8n-check 0.0.0-stage → 0.1.6

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 (70) hide show
  1. package/Dockerfile +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +319 -2
  4. package/bin/n8n-check.mjs +62 -0
  5. package/examples/agregado-enrichment/README.md +68 -0
  6. package/examples/agregado-enrichment/n8n-synthetic +11 -0
  7. package/examples/agregado-enrichment/observed-results.json +806 -0
  8. package/examples/agregado-enrichment/prepare.mjs +39 -0
  9. package/examples/identity-projection/README.md +39 -0
  10. package/examples/identity-projection/case.json +33 -0
  11. package/examples/identity-projection/observed-results.json +117 -0
  12. package/examples/identity-projection/workflow.json +71 -0
  13. package/examples/identity-projection/wrong-id.json +71 -0
  14. package/examples/morsof-invoice-history/README.md +77 -0
  15. package/examples/morsof-invoice-history/UPSTREAM-LICENSE +21 -0
  16. package/examples/morsof-invoice-history/n8n-datatable.cjs +28 -0
  17. package/examples/morsof-invoice-history/observed-results.json +113 -0
  18. package/examples/morsof-invoice-history/prepare.mjs +57 -0
  19. package/examples/morsof-invoice-history/replay.mjs +35 -0
  20. package/examples/morsof-invoice-history/run.sh +19 -0
  21. package/examples/object-body/broken.json +74 -0
  22. package/examples/object-body/case.json +81 -0
  23. package/examples/object-body/fixed.json +74 -0
  24. package/examples/object-body/observed-results.json +449 -0
  25. package/examples/object-body/retry-case.json +112 -0
  26. package/examples/object-body/retry.json +77 -0
  27. package/examples/propfind-body/README.md +75 -0
  28. package/examples/propfind-body/case.json +51 -0
  29. package/examples/propfind-body/no-body-control.json +96 -0
  30. package/examples/propfind-body/observed-results.json +307 -0
  31. package/examples/propfind-body/workflow.json +96 -0
  32. package/examples/raw-response/README.md +71 -0
  33. package/examples/raw-response/file-case.json +54 -0
  34. package/examples/raw-response/json-body.json +58 -0
  35. package/examples/raw-response/json-case.json +52 -0
  36. package/examples/raw-response/observed-results.json +383 -0
  37. package/examples/raw-response/raw-file.json +88 -0
  38. package/examples/raw-response/raw-json.json +58 -0
  39. package/examples/raw-response/raw-text.json +58 -0
  40. package/examples/raw-response/text-case.json +50 -0
  41. package/examples/retry-isolation/README.md +71 -0
  42. package/examples/retry-isolation/direct-case.json +112 -0
  43. package/examples/retry-isolation/direct.json +101 -0
  44. package/examples/retry-isolation/editor-template.json +168 -0
  45. package/examples/retry-isolation/http-batching-case.json +112 -0
  46. package/examples/retry-isolation/http-batching.json +107 -0
  47. package/examples/retry-isolation/loop-case.json +117 -0
  48. package/examples/retry-isolation/loop.json +133 -0
  49. package/examples/retry-isolation/observed-results.json +155 -0
  50. package/examples/silent-filter/README.md +57 -0
  51. package/examples/silent-filter/broken.json +96 -0
  52. package/examples/silent-filter/case.json +120 -0
  53. package/examples/silent-filter/fixed.json +96 -0
  54. package/examples/silent-filter/observed-results.json +273 -0
  55. package/examples/stop-after/README.md +66 -0
  56. package/examples/stop-after/broken.json +134 -0
  57. package/examples/stop-after/case.json +34 -0
  58. package/examples/stop-after/fixed.json +134 -0
  59. package/examples/stop-after/observed-results.json +162 -0
  60. package/examples/version-matrix/README.md +65 -0
  61. package/examples/version-matrix/observed-results.json +307 -0
  62. package/examples/version-matrix/upgrade-check.yml +32 -0
  63. package/package.json +41 -4
  64. package/src/action.mjs +108 -0
  65. package/src/case-draft.mjs +163 -0
  66. package/src/mock.mjs +72 -0
  67. package/src/report.mjs +73 -0
  68. package/src/runner.mjs +111 -0
  69. package/src/version.mjs +3 -0
  70. package/src/workflow.mjs +140 -0
@@ -0,0 +1,71 @@
1
+ # Keep a raw request and read its JSON receipt
2
+
3
+ **Keep the outgoing body set to Raw. Receive the response as a File, then extract JSON with an explicit UTF-8 encoding.**
4
+
5
+ [roman8roman-pixel reported n8n #36402](https://github.com/n8n-io/n8n/issues/36402): switching a raw-body HTTP node to an explicit JSON response left an unresolved stream in its output. A downstream check then treated an accepted delivery as failed because the returned identifier was absent from the expected JSON field.
6
+
7
+ We tested the reported settings on **n8n 2.41.7 / HTTP Request 4.4** with a local endpoint returning a synthetic receipt. These files exercise the actual HTTP node and preserve a repeatable request/output contract.
8
+
9
+ ## The workflow change
10
+
11
+ 1. Keep **Body Content Type: Raw** and your existing outgoing body.
12
+ 2. In the HTTP Request node, set **Response Format: File** and **Put Output in Field: data**.
13
+ 3. Add **Extract from File → Extract From JSON**:
14
+ - Input Binary Field: `data`
15
+ - Destination Output Field: `receipt`
16
+ - Options → File Encoding: **UTF-8**
17
+ 4. Read the identifier from `{{ $json.receipt.id }}` downstream.
18
+
19
+ [`raw-file.json`](raw-file.json) is the complete three-node workflow. It uses the built-in Extract from File node, version 1.1. Explicit `options.encoding: "utf8"` selects the response decoding for this UTF-8 API contract; the extraction implementation otherwise has an encoding-detection fallback.
20
+
21
+ Our response is:
22
+
23
+ ```json
24
+ {"id":"delivery-42","status":"accepted","message":"Livré · 已送达"}
25
+ ```
26
+
27
+ The check expects the complete receipt under `receipt`, including every non-ASCII character, and exactly one POST carrying `{"message":"hello"}`. The mock compares the parsed request JSON value. All recorded requests go to the local mock and use a synthetic receipt. The exports retain the original public echo URL; n8n-check redirects it locally. For a live workflow, set your provider URL and receipt fields.
28
+
29
+ For a provider accepting n8n's JSON body mode, [`json-body.json`](json-body.json) is the shorter alternative: choose **JSON** for both request body and response format. The File/extraction route retains the Raw body setting.
30
+
31
+ ## Run the passing contract
32
+
33
+ These examples live on **main** and run with the released **v0.1.3** CLI/Action. Clone main to get the files:
34
+
35
+ ```sh
36
+ git clone https://github.com/blucca/n8n-check.git
37
+ cd n8n-check
38
+ docker build -t n8n-check .
39
+ docker run --rm --network none -v "$PWD:/work" n8n-check \
40
+ examples/raw-response/raw-file.json examples/raw-response/file-case.json \
41
+ --out /work/results/raw-file
42
+ # PASSED: 6 checks; one POST; complete UTF-8 receipt; exit 0
43
+ ```
44
+
45
+ On Linux, add `--user "$(id -u):$(id -g)"` when your UID differs from the image's default 1000. Reports are written to `results/raw-file/report.json` and `junit.xml`.
46
+
47
+ ## Reproduce the reported failure
48
+
49
+ ```sh
50
+ docker run --rm --network none -v "$PWD:/work" n8n-check \
51
+ examples/raw-response/raw-json.json examples/raw-response/json-case.json \
52
+ --out /work/results/raw-json
53
+ # FAILED: the request is received, but a parsed receipt is absent; exit 1
54
+ ```
55
+
56
+ [Recorded executions](observed-results.json) used n8n 2.41.7, a loopback-only namespace, and one local response per run:
57
+
58
+ | Request / response settings | Observed result | Check |
59
+ |---|---|---|
60
+ | Raw / JSON | CLI output serialization hits a circular stream structure | Exit 1 |
61
+ | Raw / Text | HTTP node's `toText` hits a circular stream structure | Exit 1 |
62
+ | JSON / JSON | Complete parsed receipt | 6/6, exit 0 |
63
+ | Raw / File → Extract JSON, UTF-8 | Complete parsed receipt under `receipt` | 6/6, exit 0 |
64
+
65
+ The JSON failure occurs while the CLI serializes its result; the Text failure occurs in the HTTP node. Both runs delivered one POST to the mock. The checked-in runner now includes the CLI diagnostic tail when execution JSON is absent; v0.1.3 also retains the original command logs in its run directory.
66
+
67
+ Apply the passing case to your own receipt schema and n8n version before changing response settings. For an earlier delivery with an unreadable receipt, use the provider's status/query endpoint to reconcile its state before scheduling another POST.
68
+
69
+ Sources: [original report](https://github.com/n8n-io/n8n/issues/36402), [HTTP implementation at 2.41.7](https://github.com/n8n-io/n8n/blob/n8n%402.41.7/packages/nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts), [extraction implementation](https://github.com/n8n-io/n8n/blob/n8n%402.41.7/packages/nodes-base/nodes/Files/ExtractFromFile/actions/moveTo.operation.ts), [Extract from File documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.extractfromfile/).
70
+
71
+ Maintained by [blucca](https://github.com/blucca), an AI-operated software practice. [Fixed-scope regression implementation](https://blucca.github.io/n8n-release-checks/).
@@ -0,0 +1,54 @@
1
+ {
2
+ "version": 1,
3
+ "name": "Keep raw body and decode the UTF-8 receipt",
4
+ "input": {
5
+ "node": "When clicking Test workflow",
6
+ "items": [
7
+ {}
8
+ ]
9
+ },
10
+ "mocks": [
11
+ {
12
+ "node": "Send raw request",
13
+ "url": "/deliver",
14
+ "routes": [
15
+ {
16
+ "method": "POST",
17
+ "path": "/deliver",
18
+ "responses": [
19
+ {
20
+ "status": 200,
21
+ "json": {
22
+ "id": "delivery-42",
23
+ "status": "accepted",
24
+ "message": "Livré · 已送达"
25
+ }
26
+ }
27
+ ],
28
+ "expect": {
29
+ "count": 1,
30
+ "bodies": [
31
+ {
32
+ "message": "hello"
33
+ }
34
+ ]
35
+ }
36
+ }
37
+ ]
38
+ }
39
+ ],
40
+ "assertions": [
41
+ {
42
+ "node": "Read receipt",
43
+ "equals": [
44
+ {
45
+ "receipt": {
46
+ "id": "delivery-42",
47
+ "status": "accepted",
48
+ "message": "Livré · 已送达"
49
+ }
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "JSON body + explicit JSON response",
3
+ "nodes": [
4
+ {
5
+ "parameters": {},
6
+ "id": "raw-response-node-0",
7
+ "name": "When clicking Test workflow",
8
+ "type": "n8n-nodes-base.manualTrigger",
9
+ "typeVersion": 1,
10
+ "position": [
11
+ 0,
12
+ 0
13
+ ]
14
+ },
15
+ {
16
+ "parameters": {
17
+ "method": "POST",
18
+ "url": "https://postman-echo.com/post",
19
+ "sendBody": true,
20
+ "contentType": "json",
21
+ "options": {
22
+ "response": {
23
+ "response": {
24
+ "responseFormat": "json"
25
+ }
26
+ }
27
+ },
28
+ "specifyBody": "json",
29
+ "jsonBody": "{\"message\": \"hello\"}"
30
+ },
31
+ "id": "raw-response-node-1",
32
+ "name": "Send raw request",
33
+ "type": "n8n-nodes-base.httpRequest",
34
+ "typeVersion": 4.4,
35
+ "position": [
36
+ 220,
37
+ 0
38
+ ]
39
+ }
40
+ ],
41
+ "connections": {
42
+ "When clicking Test workflow": {
43
+ "main": [
44
+ [
45
+ {
46
+ "node": "Send raw request",
47
+ "type": "main",
48
+ "index": 0
49
+ }
50
+ ]
51
+ ]
52
+ }
53
+ },
54
+ "pinData": {},
55
+ "settings": {
56
+ "executionOrder": "v1"
57
+ }
58
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "version": 1,
3
+ "name": "One request returns a readable delivery receipt",
4
+ "input": {
5
+ "node": "When clicking Test workflow",
6
+ "items": [
7
+ {}
8
+ ]
9
+ },
10
+ "mocks": [
11
+ {
12
+ "node": "Send raw request",
13
+ "url": "/deliver",
14
+ "routes": [
15
+ {
16
+ "method": "POST",
17
+ "path": "/deliver",
18
+ "responses": [
19
+ {
20
+ "status": 200,
21
+ "json": {
22
+ "id": "delivery-42",
23
+ "status": "accepted",
24
+ "message": "Livré · 已送达"
25
+ }
26
+ }
27
+ ],
28
+ "expect": {
29
+ "count": 1,
30
+ "bodies": [
31
+ {
32
+ "message": "hello"
33
+ }
34
+ ]
35
+ }
36
+ }
37
+ ]
38
+ }
39
+ ],
40
+ "assertions": [
41
+ {
42
+ "node": "Send raw request",
43
+ "equals": [
44
+ {
45
+ "id": "delivery-42",
46
+ "status": "accepted",
47
+ "message": "Livré · 已送达"
48
+ }
49
+ ]
50
+ }
51
+ ]
52
+ }
@@ -0,0 +1,383 @@
1
+ {
2
+ "description": "Four actual n8n 2.41.7 runs of raw-request response settings. Synthetic JSON receipt from a loopback HTTP mock. CLI diagnostic summaries retain the first error line; full command logs are generated on every rerun.",
3
+ "sourceIssue": "https://github.com/n8n-io/n8n/issues/36402",
4
+ "runs": [
5
+ {
6
+ "runnerVersion": "0.1.3",
7
+ "n8nVersion": "2.41.7",
8
+ "nodeVersion": "v26.10.0",
9
+ "startedAt": "2026-10-06T16:32:59.651Z",
10
+ "durationMs": 10072,
11
+ "network": {
12
+ "mode": "loopback-only",
13
+ "enforced": true,
14
+ "interfaces": [
15
+ "lo"
16
+ ]
17
+ },
18
+ "status": "failed",
19
+ "exitCode": 1,
20
+ "requests": [
21
+ {
22
+ "node": "Send raw request",
23
+ "method": "POST",
24
+ "path": "/deliver",
25
+ "body": {
26
+ "message": "hello"
27
+ },
28
+ "matched": true,
29
+ "status": 200,
30
+ "response": {
31
+ "id": "delivery-42",
32
+ "status": "accepted",
33
+ "message": "Livré · 已送达"
34
+ }
35
+ }
36
+ ],
37
+ "workflow": "raw-json.json",
38
+ "workflowSha256": "75ce2eb56be2cf19c9a09e8cb31b8d5d057f4f77e58f10e39db5262394d19631",
39
+ "case": "json-case.json",
40
+ "caseSha256": "2b23cc34729a79ba001d92f95e60bec9c18272bcc6dac467a56da4b874922208",
41
+ "checks": [
42
+ {
43
+ "name": "n8n execution succeeds",
44
+ "passed": false,
45
+ "actual": {
46
+ "cliExitCode": 1,
47
+ "executionFound": false,
48
+ "diagnosticSummary": "Converting circular structure to JSON"
49
+ }
50
+ },
51
+ {
52
+ "name": "Send raw request: output 0",
53
+ "passed": false,
54
+ "expected": [
55
+ {
56
+ "id": "delivery-42",
57
+ "status": "accepted",
58
+ "message": "Livré · 已送达"
59
+ }
60
+ ],
61
+ "actual": []
62
+ },
63
+ {
64
+ "name": "mock: all requests match routes",
65
+ "passed": true,
66
+ "actual": []
67
+ },
68
+ {
69
+ "name": "mock: request limits and server",
70
+ "passed": true,
71
+ "actual": []
72
+ },
73
+ {
74
+ "name": "Send raw request: POST /deliver request count",
75
+ "passed": true,
76
+ "expected": 1,
77
+ "actual": 1
78
+ },
79
+ {
80
+ "name": "Send raw request: POST /deliver request bodies",
81
+ "passed": true,
82
+ "expected": [
83
+ {
84
+ "message": "hello"
85
+ }
86
+ ],
87
+ "actual": [
88
+ {
89
+ "message": "hello"
90
+ }
91
+ ]
92
+ }
93
+ ],
94
+ "failureLocation": "n8n CLI Execute.run while serializing rawOutput"
95
+ },
96
+ {
97
+ "runnerVersion": "0.1.3",
98
+ "n8nVersion": "2.41.7",
99
+ "nodeVersion": "v26.10.0",
100
+ "startedAt": "2026-10-06T16:33:28.793Z",
101
+ "durationMs": 9360,
102
+ "network": {
103
+ "mode": "loopback-only",
104
+ "enforced": true,
105
+ "interfaces": [
106
+ "lo"
107
+ ]
108
+ },
109
+ "status": "failed",
110
+ "exitCode": 1,
111
+ "requests": [
112
+ {
113
+ "node": "Send raw request",
114
+ "method": "POST",
115
+ "path": "/deliver",
116
+ "body": {
117
+ "message": "hello"
118
+ },
119
+ "matched": true,
120
+ "status": 200,
121
+ "response": {
122
+ "id": "delivery-42",
123
+ "status": "accepted",
124
+ "message": "Livré · 已送达"
125
+ }
126
+ }
127
+ ],
128
+ "workflow": "raw-text.json",
129
+ "workflowSha256": "83df0a3b7c0cf479e979d235fa470cfb3acc9ce4a432af64e6e57dbc5e157e5c",
130
+ "case": "text-case.json",
131
+ "caseSha256": "85615a647ade15f35b95d34fbe463477ba34df2af5c9eba39fe9f6e42dd5954e",
132
+ "checks": [
133
+ {
134
+ "name": "n8n execution succeeds",
135
+ "passed": false,
136
+ "actual": {
137
+ "cliExitCode": 1,
138
+ "lastNode": "Send raw request",
139
+ "message": "Converting circular structure to JSON\n --> starting at object with constructor 'Socket'\n | property '_httpMessage' -> object with constructor 'ClientRequest'\n | property 'agent' -> object with constructor 'EnvProxyHttpAgent'\n | ...\n | property '127.0.0.1:42549:' -> object with constructor 'Array'\n --- index 0 closes the circle",
140
+ "executionFound": true
141
+ }
142
+ },
143
+ {
144
+ "name": "Send raw request: output 0",
145
+ "passed": false,
146
+ "expected": [
147
+ {
148
+ "data": "{\"id\":\"delivery-42\",\"status\":\"accepted\",\"message\":\"Livré · 已送达\"}"
149
+ }
150
+ ],
151
+ "actual": []
152
+ },
153
+ {
154
+ "name": "mock: all requests match routes",
155
+ "passed": true,
156
+ "actual": []
157
+ },
158
+ {
159
+ "name": "mock: request limits and server",
160
+ "passed": true,
161
+ "actual": []
162
+ },
163
+ {
164
+ "name": "Send raw request: POST /deliver request count",
165
+ "passed": true,
166
+ "expected": 1,
167
+ "actual": 1
168
+ },
169
+ {
170
+ "name": "Send raw request: POST /deliver request bodies",
171
+ "passed": true,
172
+ "expected": [
173
+ {
174
+ "message": "hello"
175
+ }
176
+ ],
177
+ "actual": [
178
+ {
179
+ "message": "hello"
180
+ }
181
+ ]
182
+ }
183
+ ],
184
+ "failureLocation": "HTTP Request V3 toText while serializing the response stream"
185
+ },
186
+ {
187
+ "runnerVersion": "0.1.3",
188
+ "n8nVersion": "2.41.7",
189
+ "nodeVersion": "v26.10.0",
190
+ "startedAt": "2026-10-06T16:33:09.875Z",
191
+ "durationMs": 9211,
192
+ "network": {
193
+ "mode": "loopback-only",
194
+ "enforced": true,
195
+ "interfaces": [
196
+ "lo"
197
+ ]
198
+ },
199
+ "status": "passed",
200
+ "exitCode": 0,
201
+ "requests": [
202
+ {
203
+ "node": "Send raw request",
204
+ "method": "POST",
205
+ "path": "/deliver",
206
+ "body": {
207
+ "message": "hello"
208
+ },
209
+ "matched": true,
210
+ "status": 200,
211
+ "response": {
212
+ "id": "delivery-42",
213
+ "status": "accepted",
214
+ "message": "Livré · 已送达"
215
+ }
216
+ }
217
+ ],
218
+ "workflow": "json-body.json",
219
+ "workflowSha256": "37b7e0449412da466c874b2f2f44dbc93c441c293956908e83d61126b474217e",
220
+ "case": "json-case.json",
221
+ "caseSha256": "2b23cc34729a79ba001d92f95e60bec9c18272bcc6dac467a56da4b874922208",
222
+ "checks": [
223
+ {
224
+ "name": "n8n execution succeeds",
225
+ "passed": true,
226
+ "actual": {
227
+ "cliExitCode": 0,
228
+ "lastNode": "Send raw request",
229
+ "executionFound": true
230
+ }
231
+ },
232
+ {
233
+ "name": "Send raw request: output 0",
234
+ "passed": true,
235
+ "expected": [
236
+ {
237
+ "id": "delivery-42",
238
+ "status": "accepted",
239
+ "message": "Livré · 已送达"
240
+ }
241
+ ],
242
+ "actual": [
243
+ {
244
+ "id": "delivery-42",
245
+ "status": "accepted",
246
+ "message": "Livré · 已送达"
247
+ }
248
+ ]
249
+ },
250
+ {
251
+ "name": "mock: all requests match routes",
252
+ "passed": true,
253
+ "actual": []
254
+ },
255
+ {
256
+ "name": "mock: request limits and server",
257
+ "passed": true,
258
+ "actual": []
259
+ },
260
+ {
261
+ "name": "Send raw request: POST /deliver request count",
262
+ "passed": true,
263
+ "expected": 1,
264
+ "actual": 1
265
+ },
266
+ {
267
+ "name": "Send raw request: POST /deliver request bodies",
268
+ "passed": true,
269
+ "expected": [
270
+ {
271
+ "message": "hello"
272
+ }
273
+ ],
274
+ "actual": [
275
+ {
276
+ "message": "hello"
277
+ }
278
+ ]
279
+ }
280
+ ]
281
+ },
282
+ {
283
+ "runnerVersion": "0.1.3",
284
+ "n8nVersion": "2.41.7",
285
+ "nodeVersion": "v26.10.0",
286
+ "startedAt": "2026-10-06T16:33:19.227Z",
287
+ "durationMs": 9457,
288
+ "network": {
289
+ "mode": "loopback-only",
290
+ "enforced": true,
291
+ "interfaces": [
292
+ "lo"
293
+ ]
294
+ },
295
+ "status": "passed",
296
+ "exitCode": 0,
297
+ "requests": [
298
+ {
299
+ "node": "Send raw request",
300
+ "method": "POST",
301
+ "path": "/deliver",
302
+ "body": {
303
+ "message": "hello"
304
+ },
305
+ "matched": true,
306
+ "status": 200,
307
+ "response": {
308
+ "id": "delivery-42",
309
+ "status": "accepted",
310
+ "message": "Livré · 已送达"
311
+ }
312
+ }
313
+ ],
314
+ "workflow": "raw-file.json",
315
+ "workflowSha256": "76fbb52f7c125371dbcc8cf408014245d72aef3107f4880895e2daf424bbbfb5",
316
+ "case": "file-case.json",
317
+ "caseSha256": "1e1b181bd6ee5f48f2f9e1b976a3025472f1ffae6c53e48cb1edd1529b28a44c",
318
+ "checks": [
319
+ {
320
+ "name": "n8n execution succeeds",
321
+ "passed": true,
322
+ "actual": {
323
+ "cliExitCode": 0,
324
+ "lastNode": "Read receipt",
325
+ "executionFound": true
326
+ }
327
+ },
328
+ {
329
+ "name": "Read receipt: output 0",
330
+ "passed": true,
331
+ "expected": [
332
+ {
333
+ "receipt": {
334
+ "id": "delivery-42",
335
+ "status": "accepted",
336
+ "message": "Livré · 已送达"
337
+ }
338
+ }
339
+ ],
340
+ "actual": [
341
+ {
342
+ "receipt": {
343
+ "id": "delivery-42",
344
+ "status": "accepted",
345
+ "message": "Livré · 已送达"
346
+ }
347
+ }
348
+ ]
349
+ },
350
+ {
351
+ "name": "mock: all requests match routes",
352
+ "passed": true,
353
+ "actual": []
354
+ },
355
+ {
356
+ "name": "mock: request limits and server",
357
+ "passed": true,
358
+ "actual": []
359
+ },
360
+ {
361
+ "name": "Send raw request: POST /deliver request count",
362
+ "passed": true,
363
+ "expected": 1,
364
+ "actual": 1
365
+ },
366
+ {
367
+ "name": "Send raw request: POST /deliver request bodies",
368
+ "passed": true,
369
+ "expected": [
370
+ {
371
+ "message": "hello"
372
+ }
373
+ ],
374
+ "actual": [
375
+ {
376
+ "message": "hello"
377
+ }
378
+ ]
379
+ }
380
+ ]
381
+ }
382
+ ]
383
+ }