wrangler 2.0.29 → 2.1.2

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 (45) hide show
  1. package/miniflare-dist/index.mjs +1136 -372
  2. package/package.json +3 -2
  3. package/src/__tests__/helpers/mock-cfetch.ts +39 -19
  4. package/src/__tests__/helpers/mock-console.ts +11 -2
  5. package/src/__tests__/helpers/msw/handlers/index.ts +13 -0
  6. package/src/__tests__/helpers/msw/handlers/namespaces.ts +104 -0
  7. package/src/__tests__/helpers/msw/handlers/oauth.ts +36 -0
  8. package/src/__tests__/helpers/msw/handlers/r2.ts +80 -0
  9. package/src/__tests__/helpers/msw/handlers/user.ts +63 -0
  10. package/src/__tests__/helpers/msw/index.ts +4 -0
  11. package/src/__tests__/index.test.ts +9 -7
  12. package/src/__tests__/init.test.ts +356 -5
  13. package/src/__tests__/jest.setup.ts +16 -0
  14. package/src/__tests__/middleware.test.ts +768 -0
  15. package/src/__tests__/pages.test.ts +11 -12
  16. package/src/__tests__/publish.test.ts +516 -438
  17. package/src/__tests__/r2.test.ts +128 -93
  18. package/src/__tests__/secret.test.ts +78 -0
  19. package/src/__tests__/tail.test.ts +47 -74
  20. package/src/__tests__/whoami.test.tsx +49 -64
  21. package/src/api/dev.ts +23 -4
  22. package/src/bundle.ts +225 -1
  23. package/src/dev/dev.tsx +3 -1
  24. package/src/dev/local.tsx +2 -2
  25. package/src/dev/remote.tsx +6 -3
  26. package/src/dev/start-server.ts +11 -7
  27. package/src/dev/use-esbuild.ts +4 -0
  28. package/src/dev.tsx +6 -16
  29. package/src/dialogs.tsx +12 -0
  30. package/src/index.tsx +95 -4
  31. package/src/init.ts +286 -11
  32. package/src/miniflare-cli/assets.ts +130 -415
  33. package/src/miniflare-cli/index.ts +3 -1
  34. package/src/pages/dev.tsx +5 -1
  35. package/src/pages/hash.tsx +13 -0
  36. package/src/pages/upload.tsx +3 -18
  37. package/src/publish.ts +38 -4
  38. package/src/tail/filters.ts +1 -5
  39. package/src/tail/index.ts +6 -3
  40. package/templates/middleware/common.ts +62 -0
  41. package/templates/middleware/loader-modules.ts +84 -0
  42. package/templates/middleware/loader-sw.ts +213 -0
  43. package/templates/middleware/middleware-pretty-error.ts +40 -0
  44. package/templates/middleware/middleware-scheduled.ts +14 -0
  45. package/wrangler-dist/cli.js +65900 -65432
@@ -1,11 +1,8 @@
1
1
  import * as fs from "node:fs";
2
+ import { rest } from "msw";
2
3
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
3
- import {
4
- setMockFetchR2Objects,
5
- setMockResponse,
6
- unsetAllMocks,
7
- } from "./helpers/mock-cfetch";
8
4
  import { mockConsoleMethods } from "./helpers/mock-console";
5
+ import { msw } from "./helpers/msw";
9
6
  import { runInTempDir } from "./helpers/run-in-tmp";
10
7
  import { runWrangler } from "./helpers/run-wrangler";
11
8
  import type { R2BucketInfo } from "../r2";
@@ -16,10 +13,6 @@ describe("wrangler", () => {
16
13
  runInTempDir();
17
14
  const std = mockConsoleMethods();
18
15
 
19
- afterEach(() => {
20
- unsetAllMocks();
21
- });
22
-
23
16
  describe("r2", () => {
24
17
  describe("bucket", () => {
25
18
  it("should show the correct help when an invalid command is passed", async () => {
@@ -50,26 +43,41 @@ describe("wrangler", () => {
50
43
  });
51
44
 
52
45
  describe("list", () => {
53
- function mockListRequest(buckets: R2BucketInfo[]) {
54
- const requests = { count: 0 };
55
- setMockResponse(
56
- "/accounts/:accountId/r2/buckets",
57
- ([_url, accountId], init) => {
58
- requests.count++;
59
- expect(accountId).toEqual("some-account-id");
60
- expect(init).toEqual({});
61
- return { buckets };
62
- }
63
- );
64
- return requests;
65
- }
66
-
67
- it("should list buckets", async () => {
46
+ it("should list buckets & check request inputs", async () => {
68
47
  const expectedBuckets: R2BucketInfo[] = [
69
- { name: "bucket-1", creation_date: "01-01-2001" },
70
- { name: "bucket-2", creation_date: "01-01-2001" },
48
+ { name: "bucket-1-local-once", creation_date: "01-01-2001" },
49
+ { name: "bucket-2-local-once", creation_date: "01-01-2001" },
71
50
  ];
72
- mockListRequest(expectedBuckets);
51
+ msw.use(
52
+ rest.get(
53
+ "*/accounts/:accountId/r2/buckets",
54
+ async (request, response, context) => {
55
+ const { accountId } = request.params;
56
+ expect(accountId).toEqual("some-account-id");
57
+ expect(await request.text()).toEqual("");
58
+ return response.once(
59
+ context.status(200),
60
+ context.json({
61
+ success: true,
62
+ errors: [],
63
+ messages: [],
64
+ result: {
65
+ buckets: [
66
+ {
67
+ name: "bucket-1-local-once",
68
+ creation_date: "01-01-2001",
69
+ },
70
+ {
71
+ name: "bucket-2-local-once",
72
+ creation_date: "01-01-2001",
73
+ },
74
+ ],
75
+ },
76
+ })
77
+ );
78
+ }
79
+ )
80
+ );
73
81
  await runWrangler("r2 bucket list");
74
82
 
75
83
  expect(std.err).toMatchInlineSnapshot(`""`);
@@ -79,21 +87,6 @@ describe("wrangler", () => {
79
87
  });
80
88
 
81
89
  describe("create", () => {
82
- function mockCreateRequest(expectedBucketName: string) {
83
- const requests = { count: 0 };
84
- setMockResponse(
85
- "/accounts/:accountId/r2/buckets",
86
- "POST",
87
- ([_url, accountId], { body }) => {
88
- expect(accountId).toEqual("some-account-id");
89
- const bucketName = JSON.parse(body as string).name;
90
- expect(bucketName).toEqual(expectedBucketName);
91
- requests.count += 1;
92
- }
93
- );
94
- return requests;
95
- }
96
-
97
90
  it("should error if no bucket name is given", async () => {
98
91
  await expect(
99
92
  runWrangler("r2 bucket create")
@@ -148,32 +141,35 @@ describe("wrangler", () => {
148
141
  `);
149
142
  });
150
143
 
151
- it("should create a bucket", async () => {
152
- const requests = mockCreateRequest("testBucket");
144
+ it("should create a bucket & check request inputs", async () => {
145
+ msw.use(
146
+ rest.post(
147
+ "*/accounts/:accountId/r2/buckets",
148
+ async (request, response, context) => {
149
+ const { accountId } = request.params;
150
+ expect(accountId).toEqual("some-account-id");
151
+ expect(await request.json()).toEqual({ name: "testBucket" });
152
+ response.once(
153
+ context.status(200),
154
+ context.json({
155
+ success: true,
156
+ errors: [],
157
+ messages: [],
158
+ result: {},
159
+ })
160
+ );
161
+ }
162
+ )
163
+ );
153
164
  await runWrangler("r2 bucket create testBucket");
154
165
  expect(std.out).toMatchInlineSnapshot(`
155
166
  "Creating bucket testBucket.
156
167
  Created bucket testBucket."
157
168
  `);
158
- expect(requests.count).toEqual(1);
159
169
  });
160
170
  });
161
171
 
162
172
  describe("delete", () => {
163
- function mockDeleteRequest(expectedBucketName: string) {
164
- const requests = { count: 0 };
165
- setMockResponse(
166
- "/accounts/:accountId/r2/buckets/:bucketName",
167
- "DELETE",
168
- ([_url, accountId, bucketName]) => {
169
- expect(accountId).toEqual("some-account-id");
170
- expect(bucketName).toEqual(expectedBucketName);
171
- requests.count += 1;
172
- }
173
- );
174
- return requests;
175
- }
176
-
177
173
  it("should error if no bucket name is given", async () => {
178
174
  await expect(
179
175
  runWrangler("r2 bucket delete")
@@ -228,23 +224,42 @@ describe("wrangler", () => {
228
224
  `);
229
225
  });
230
226
 
231
- it("should delete a bucket specified by name", async () => {
232
- const requests = mockDeleteRequest("some-bucket");
227
+ it("should delete a bucket specified by name & check requests inputs", async () => {
228
+ msw.use(
229
+ rest.delete(
230
+ "*/accounts/:accountId/r2/buckets/:bucketName",
231
+ async (request, response, context) => {
232
+ const { accountId, bucketName } = request.params;
233
+ expect(accountId).toEqual("some-account-id");
234
+ expect(bucketName).toEqual("some-bucket");
235
+ expect(await request.text()).toEqual("");
236
+ expect(request.headers.get("authorization")).toEqual(
237
+ "Bearer some-api-token"
238
+ );
239
+
240
+ return response.once(
241
+ context.status(200),
242
+ context.json({
243
+ success: true,
244
+ errors: [],
245
+ messages: [],
246
+ result: null,
247
+ })
248
+ );
249
+ }
250
+ )
251
+ );
233
252
  await runWrangler(`r2 bucket delete some-bucket`);
234
- expect(requests.count).toEqual(1);
253
+ expect(std.out).toMatchInlineSnapshot(`
254
+ "Deleting bucket some-bucket.
255
+ Deleted bucket some-bucket."
256
+ `);
235
257
  });
236
258
  });
237
259
  });
238
260
 
239
261
  describe("r2 object", () => {
240
262
  it("should download R2 object from bucket", async () => {
241
- setMockFetchR2Objects({
242
- accountId: "some-account-id",
243
- bucketName: "bucketName-object-test",
244
- objectName: "wormhole-img.png",
245
- mockResponse: "R2-objects-test-data",
246
- });
247
-
248
263
  await runWrangler(
249
264
  `r2 object get bucketName-object-test/wormhole-img.png --file ./wormhole-img.png`
250
265
  );
@@ -256,11 +271,6 @@ describe("wrangler", () => {
256
271
  });
257
272
 
258
273
  it("should upload R2 object from bucket", async () => {
259
- setMockFetchR2Objects({
260
- accountId: "some-account-id",
261
- bucketName: "bucketName-object-test",
262
- objectName: "wormhole-img.png",
263
- });
264
274
  fs.writeFileSync("wormhole-img.png", "passageway");
265
275
  await runWrangler(
266
276
  `r2 object put bucketName-object-test/wormhole-img.png --file ./wormhole-img.png`
@@ -272,15 +282,52 @@ describe("wrangler", () => {
272
282
  `);
273
283
  });
274
284
 
275
- it("should pass all fetch option flags into requestInit", async () => {
285
+ it("should pass all fetch option flags into requestInit & check request inputs", async () => {
286
+ msw.use(
287
+ rest.put(
288
+ "*/accounts/:accountId/r2/buckets/:bucketName/objects/:objectName",
289
+ (request, response, context) => {
290
+ const { accountId, bucketName, objectName } = request.params;
291
+ expect(accountId).toEqual("some-account-id");
292
+ expect(bucketName).toEqual("bucketName-object-test");
293
+ expect(objectName).toEqual("wormhole-img.png");
294
+ const headersObject = request.headers.all();
295
+ delete headersObject["user-agent"];
296
+ expect(headersObject).toMatchInlineSnapshot(`
297
+ Object {
298
+ "accept": "*/*",
299
+ "accept-encoding": "gzip,deflate",
300
+ "authorization": "Bearer some-api-token",
301
+ "cache-control": "cache-control-mock",
302
+ "connection": "close",
303
+ "content-disposition": "content-disposition-mock",
304
+ "content-encoding": "content-encoding-mock",
305
+ "content-language": "content-lang-mock",
306
+ "content-length": "10",
307
+ "content-type": "content-type-mock",
308
+ "expires": "expire-time-mock",
309
+ "host": "api.cloudflare.com",
310
+ }
311
+ `);
312
+ response.once(
313
+ context.status(200),
314
+ context.json({
315
+ success: true,
316
+ errors: [],
317
+ messages: [],
318
+ result: {
319
+ accountId: "some-account-id",
320
+ bucketName: "bucketName-object-test",
321
+ objectName: "wormhole-img.png",
322
+ },
323
+ })
324
+ );
325
+ }
326
+ )
327
+ );
276
328
  fs.writeFileSync("wormhole-img.png", "passageway");
277
- setMockFetchR2Objects({
278
- accountId: "some-account-id",
279
- bucketName: "bucketName-object-test",
280
- objectName: "wormhole-img.png",
281
- });
282
329
  const flags =
283
- "--ct content-type --cd content-disposition --ce content-encoding --cl content-lang --cc cache-control --e expire-time";
330
+ "--ct content-type-mock --cd content-disposition-mock --ce content-encoding-mock --cl content-lang-mock --cc cache-control-mock --e expire-time-mock";
284
331
 
285
332
  await runWrangler(
286
333
  `r2 object put bucketName-object-test/wormhole-img.png ${flags} --file wormhole-img.png`
@@ -293,12 +340,6 @@ describe("wrangler", () => {
293
340
  });
294
341
 
295
342
  it("should delete R2 object from bucket", async () => {
296
- setMockFetchR2Objects({
297
- accountId: "some-account-id",
298
- bucketName: "bucketName-object-test",
299
- objectName: "wormhole-img.png",
300
- });
301
-
302
343
  await runWrangler(
303
344
  `r2 object delete bucketName-object-test/wormhole-img.png`
304
345
  );
@@ -311,12 +352,6 @@ describe("wrangler", () => {
311
352
 
312
353
  it("should not allow `--pipe` & `--file` to run together", async () => {
313
354
  fs.writeFileSync("wormhole-img.png", "passageway");
314
- setMockFetchR2Objects({
315
- accountId: "some-account-id",
316
- bucketName: "bucketName-object-test",
317
- objectName: "wormhole-img.png",
318
- });
319
-
320
355
  await expect(
321
356
  runWrangler(
322
357
  `r2 object put bucketName-object-test/wormhole-img.png --pipe --file wormhole-img.png`
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs";
2
+ import { writeFileSync } from "node:fs";
2
3
  import * as TOML from "@iarna/toml";
3
4
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
4
5
  import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
@@ -95,6 +96,83 @@ describe("wrangler secret", () => {
95
96
  expect(std.err).toMatchInlineSnapshot(`""`);
96
97
  });
97
98
 
99
+ it("should create secret:bulk", async () => {
100
+ writeFileSync(
101
+ "secret.json",
102
+ JSON.stringify({
103
+ "secret-name-1": "secret_text",
104
+ "secret-name-2": "secret_text",
105
+ })
106
+ );
107
+
108
+ // User counter to pass different secrets to the request mock
109
+ let counter = 0;
110
+ setMockResponse(
111
+ `/accounts/:accountId/workers/scripts/:scriptName/secrets`,
112
+ "PUT",
113
+ ([_url, accountId]) => {
114
+ expect(accountId).toEqual("some-account-id");
115
+ counter++;
116
+
117
+ return { name: `secret-name-${counter}`, type: "secret_text" };
118
+ }
119
+ );
120
+
121
+ await runWrangler("secret:bulk ./secret.json --name script-name");
122
+
123
+ expect(std.out).toMatchInlineSnapshot(`
124
+ "🌀 Creating the secrets for the Worker \\"script-name\\"
125
+ ✨ Successfully created secret for key: secret-name-1
126
+ ✨ Successfully created secret for key: secret-name-2
127
+ ✨ Finished processing secrets JSON file"
128
+ `);
129
+ expect(std.err).toMatchInlineSnapshot(`""`);
130
+ });
131
+
132
+ it("should handle failed secret:bulk", async () => {
133
+ writeFileSync(
134
+ "secret.json",
135
+ JSON.stringify({
136
+ "secret-name-1": "secret_text",
137
+ "secret-name-2": "secret_text",
138
+ })
139
+ );
140
+
141
+ // User counter to pass different secrets to the request mock
142
+ let counter = 0;
143
+ setMockResponse(
144
+ `/accounts/:accountId/workers/scripts/:scriptName/secrets`,
145
+ "PUT",
146
+ ([_url, accountId]) => {
147
+ expect(accountId).toEqual("some-account-id");
148
+ counter++;
149
+
150
+ return Promise.reject(
151
+ new Error(`Failed to create secret ${counter}`)
152
+ );
153
+ }
154
+ );
155
+
156
+ await runWrangler("secret:bulk ./secret.json --name script-name");
157
+
158
+ expect(std.out).toMatchInlineSnapshot(`
159
+ "🌀 Creating the secrets for the Worker \\"script-name\\"
160
+ ✨ Finished processing secrets JSON file"
161
+ `);
162
+ expect(std.err).toMatchInlineSnapshot(`
163
+ "X [ERROR] 🚨 Error uploading secret for key: secret-name-1:
164
+
165
+ Failed to create secret 1
166
+
167
+
168
+ X [ERROR] 🚨 Error uploading secret for key: secret-name-2:
169
+
170
+ Failed to create secret 2
171
+
172
+ "
173
+ `);
174
+ });
175
+
98
176
  it("should create a secret: legacy envs", async () => {
99
177
  mockPrompt({
100
178
  text: "Enter a secret value:",
@@ -14,6 +14,7 @@ import type {
14
14
  ScheduledEvent,
15
15
  AlarmEvent,
16
16
  } from "../tail";
17
+ import type { RequestInit } from "undici";
17
18
  import type WebSocket from "ws";
18
19
 
19
20
  describe("tail", () => {
@@ -44,12 +45,12 @@ describe("tail", () => {
44
45
 
45
46
  it("creates and then delete tails", async () => {
46
47
  const api = mockWebsocketAPIs();
47
- expect(api.requests.creation.count).toStrictEqual(0);
48
+ expect(api.requests.creation.length).toStrictEqual(0);
48
49
 
49
50
  await runWrangler("tail test-worker");
50
51
 
51
52
  await expect(api.ws.connected).resolves.toBeTruthy();
52
- expect(api.requests.creation.count).toStrictEqual(1);
53
+ expect(api.requests.creation.length).toStrictEqual(1);
53
54
  expect(api.requests.deletion.count).toStrictEqual(0);
54
55
 
55
56
  api.ws.close();
@@ -57,7 +58,7 @@ describe("tail", () => {
57
58
  });
58
59
  it("should connect to the worker assigned to a given route", async () => {
59
60
  const api = mockWebsocketAPIs();
60
- expect(api.requests.creation.count).toStrictEqual(0);
61
+ expect(api.requests.creation.length).toStrictEqual(0);
61
62
 
62
63
  mockGetZoneFromHostRequest("example.com", "test-zone");
63
64
  mockCollectKnownRoutesRequest([
@@ -69,7 +70,7 @@ describe("tail", () => {
69
70
  await runWrangler("tail example.com/*");
70
71
 
71
72
  await expect(api.ws.connected).resolves.toBeTruthy();
72
- expect(api.requests.creation.count).toStrictEqual(1);
73
+ expect(api.requests.creation.length).toStrictEqual(1);
73
74
  expect(api.requests.deletion.count).toStrictEqual(0);
74
75
 
75
76
  api.ws.close();
@@ -90,12 +91,12 @@ describe("tail", () => {
90
91
 
91
92
  it("creates and then delete tails: legacy envs", async () => {
92
93
  const api = mockWebsocketAPIs("some-env", true);
93
- expect(api.requests.creation.count).toStrictEqual(0);
94
+ expect(api.requests.creation.length).toStrictEqual(0);
94
95
 
95
96
  await runWrangler("tail test-worker --env some-env --legacy-env true");
96
97
 
97
98
  await expect(api.ws.connected).resolves.toBeTruthy();
98
- expect(api.requests.creation.count).toStrictEqual(1);
99
+ expect(api.requests.creation.length).toStrictEqual(1);
99
100
  expect(api.requests.deletion.count).toStrictEqual(0);
100
101
 
101
102
  api.ws.close();
@@ -104,12 +105,12 @@ describe("tail", () => {
104
105
 
105
106
  it("creates and then delete tails: service envs", async () => {
106
107
  const api = mockWebsocketAPIs("some-env");
107
- expect(api.requests.creation.count).toStrictEqual(0);
108
+ expect(api.requests.creation.length).toStrictEqual(0);
108
109
 
109
110
  await runWrangler("tail test-worker --env some-env --legacy-env false");
110
111
 
111
112
  await expect(api.ws.connected).resolves.toBeTruthy();
112
- expect(api.requests.creation.count).toStrictEqual(1);
113
+ expect(api.requests.creation.length).toStrictEqual(1);
113
114
  expect(api.requests.deletion.count).toStrictEqual(0);
114
115
 
115
116
  api.ws.close();
@@ -143,65 +144,57 @@ describe("tail", () => {
143
144
  await expect(tooLow).rejects.toThrow();
144
145
 
145
146
  await runWrangler("tail test-worker --sampling-rate 0.25");
146
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
147
- { sampling_rate: 0.25 },
148
- ]);
147
+ expect(api.requests.creation[0].body).toEqual(
148
+ `{"filters":[{"sampling_rate":0.25}]}`
149
+ );
149
150
  });
150
151
 
151
152
  it("sends single status filters", async () => {
152
153
  const api = mockWebsocketAPIs();
153
154
  await runWrangler("tail test-worker --status error");
154
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
155
- { outcome: ["exception", "exceededCpu", "exceededMemory", "unknown"] },
156
- ]);
155
+ expect(api.requests.creation[0].body).toEqual(
156
+ `{"filters":[{"outcome":["exception","exceededCpu","exceededMemory","unknown"]}]}`
157
+ );
157
158
  });
158
159
 
159
160
  it("sends multiple status filters", async () => {
160
161
  const api = mockWebsocketAPIs();
161
162
  await runWrangler("tail test-worker --status error --status canceled");
162
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
163
- {
164
- outcome: [
165
- "exception",
166
- "exceededCpu",
167
- "exceededMemory",
168
- "unknown",
169
- "canceled",
170
- ],
171
- },
172
- ]);
163
+ expect(api.requests.creation[0].body).toEqual(
164
+ `{"filters":[{"outcome":["exception","exceededCpu","exceededMemory","unknown","canceled"]}]}`
165
+ );
173
166
  });
174
167
 
175
168
  it("sends single HTTP method filters", async () => {
176
169
  const api = mockWebsocketAPIs();
177
170
  await runWrangler("tail test-worker --method POST");
178
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
179
- { method: ["POST"] },
180
- ]);
171
+ expect(api.requests.creation[0].body).toEqual(
172
+ `{"filters":[{"method":["POST"]}]}`
173
+ );
181
174
  });
182
175
 
183
176
  it("sends multiple HTTP method filters", async () => {
184
177
  const api = mockWebsocketAPIs();
185
178
  await runWrangler("tail test-worker --method POST --method GET");
186
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
187
- { method: ["POST", "GET"] },
188
- ]);
179
+ expect(api.requests.creation[0].body).toEqual(
180
+ `{"filters":[{"method":["POST","GET"]}]}`
181
+ );
189
182
  });
190
183
 
191
184
  it("sends header filters without a query", async () => {
192
185
  const api = mockWebsocketAPIs();
193
186
  await runWrangler("tail test-worker --header X-CUSTOM-HEADER");
194
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
195
- { header: { key: "X-CUSTOM-HEADER" } },
196
- ]);
187
+ expect(api.requests.creation[0].body).toEqual(
188
+ `{"filters":[{"header":{"key":"X-CUSTOM-HEADER"}}]}`
189
+ );
197
190
  });
198
191
 
199
192
  it("sends header filters with a query", async () => {
200
193
  const api = mockWebsocketAPIs();
201
194
  await runWrangler("tail test-worker --header X-CUSTOM-HEADER:some-value");
202
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
203
- { header: { key: "X-CUSTOM-HEADER", query: "some-value" } },
204
- ]);
195
+ expect(api.requests.creation[0].body).toEqual(
196
+ `{"filters":[{"header":{"key":"X-CUSTOM-HEADER","query":"some-value"}}]}`
197
+ );
205
198
  });
206
199
 
207
200
  it("sends single IP filters", async () => {
@@ -209,9 +202,9 @@ describe("tail", () => {
209
202
  const fakeIp = "192.0.2.1";
210
203
 
211
204
  await runWrangler(`tail test-worker --ip ${fakeIp}`);
212
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
213
- { client_ip: [fakeIp] },
214
- ]);
205
+ expect(api.requests.creation[0].body).toEqual(
206
+ `{"filters":[{"client_ip":["${fakeIp}"]}]}`
207
+ );
215
208
  });
216
209
 
217
210
  it("sends multiple IP filters", async () => {
@@ -219,9 +212,9 @@ describe("tail", () => {
219
212
  const fakeIp = "192.0.2.1";
220
213
 
221
214
  await runWrangler(`tail test-worker --ip ${fakeIp} --ip self`);
222
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
223
- { client_ip: [fakeIp, "self"] },
224
- ]);
215
+ expect(api.requests.creation[0].body).toEqual(
216
+ `{"filters":[{"client_ip":["${fakeIp}","self"]}]}`
217
+ );
225
218
  });
226
219
 
227
220
  it("sends search filters", async () => {
@@ -229,9 +222,9 @@ describe("tail", () => {
229
222
  const search = "filterMe";
230
223
 
231
224
  await runWrangler(`tail test-worker --search ${search}`);
232
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
233
- { query: search },
234
- ]);
225
+ expect(api.requests.creation[0].body).toEqual(
226
+ `{"filters":[{"query":"${search}"}]}`
227
+ );
235
228
  });
236
229
 
237
230
  it("sends everything but the kitchen sink", async () => {
@@ -252,30 +245,10 @@ describe("tail", () => {
252
245
  `--search ${query} ` +
253
246
  `--debug`;
254
247
 
255
- const expectedWebsocketMessage = {
256
- filters: [
257
- { sampling_rate },
258
- {
259
- outcome: [
260
- "ok",
261
- "exception",
262
- "exceededCpu",
263
- "exceededMemory",
264
- "unknown",
265
- ],
266
- },
267
- { method },
268
- { header: { key: "X-HELLO", query: "world" } },
269
- { client_ip },
270
- { query },
271
- ],
272
- debug: true,
273
- };
248
+ const expectedWebsocketMessage = `{"filters":[{"sampling_rate":0.69},{"outcome":["ok","exception","exceededCpu","exceededMemory","unknown"]},{"method":["GET","POST","PUT"]},{"header":{"key":"X-HELLO","query":"world"}},{"client_ip":["192.0.2.1","self"]},{"query":"onlyTheseMessagesPlease"}]}`;
274
249
 
275
250
  await runWrangler(`tail test-worker ${cliFilters}`);
276
- await expect(api.nextMessageJson()).resolves.toEqual(
277
- expectedWebsocketMessage
278
- );
251
+ expect(api.requests.creation[0].body).toEqual(expectedWebsocketMessage);
279
252
  });
280
253
  });
281
254
 
@@ -589,7 +562,7 @@ function deserializeToJson(message: WebSocket.RawData): string {
589
562
  */
590
563
  type MockAPI = {
591
564
  requests: {
592
- creation: RequestCounter;
565
+ creation: RequestInit[];
593
566
  deletion: RequestCounter;
594
567
  };
595
568
  ws: MockWebSocket;
@@ -615,15 +588,15 @@ function mockCreateTailRequest(
615
588
  websocketURL: string,
616
589
  env?: string,
617
590
  legacyEnv = false
618
- ): RequestCounter {
619
- const requests = { count: 0 };
591
+ ): RequestInit[] {
592
+ const requests: RequestInit[] = [];
620
593
  const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
621
594
  const environment = env && !legacyEnv ? "/environments/:envName" : "";
622
595
  setMockResponse(
623
596
  `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails`,
624
597
  "POST",
625
- ([_url, accountId, scriptName, envName]) => {
626
- requests.count++;
598
+ ([_url, accountId, scriptName, envName], req) => {
599
+ requests.push(req);
627
600
  expect(accountId).toEqual("some-account-id");
628
601
  expect(scriptName).toEqual(
629
602
  legacyEnv && env ? `test-worker-${env}` : "test-worker"
@@ -710,7 +683,7 @@ function mockWebsocketAPIs(env?: string, legacyEnv = false): MockAPI {
710
683
  const api: MockAPI = {
711
684
  requests: {
712
685
  deletion: { count: 0 },
713
- creation: { count: 0 },
686
+ creation: [],
714
687
  },
715
688
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
716
689
  ws: null!, // will be set in the `beforeEach()` below.