wrangler 0.0.0-e22f9d7 → 0.0.0-e2a26a0

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 (54) hide show
  1. package/bin/wrangler.js +2 -2
  2. package/package.json +15 -10
  3. package/pages/functions/buildWorker.ts +1 -1
  4. package/pages/functions/filepath-routing.test.ts +21 -13
  5. package/pages/functions/filepath-routing.ts +38 -28
  6. package/pages/functions/routes.ts +8 -6
  7. package/pages/functions/template-worker.ts +16 -24
  8. package/src/__tests__/dev.test.tsx +7 -3
  9. package/src/__tests__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
  10. package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
  11. package/src/__tests__/helpers/mock-account-id.ts +30 -0
  12. package/src/__tests__/helpers/mock-bin.ts +33 -0
  13. package/src/__tests__/{mock-cfetch.ts → helpers/mock-cfetch.ts} +49 -13
  14. package/src/__tests__/helpers/mock-console.ts +56 -0
  15. package/src/__tests__/{mock-dialogs.ts → helpers/mock-dialogs.ts} +1 -1
  16. package/src/__tests__/helpers/mock-kv.ts +40 -0
  17. package/src/__tests__/helpers/mock-user.ts +27 -0
  18. package/src/__tests__/helpers/run-in-tmp.ts +29 -0
  19. package/src/__tests__/helpers/run-wrangler.ts +14 -0
  20. package/src/__tests__/index.test.ts +312 -56
  21. package/src/__tests__/jest.setup.ts +17 -2
  22. package/src/__tests__/kv.test.ts +344 -316
  23. package/src/__tests__/logout.test.ts +50 -0
  24. package/src/__tests__/package-manager.test.ts +206 -0
  25. package/src/__tests__/publish.test.ts +1222 -0
  26. package/src/__tests__/secret.test.ts +210 -0
  27. package/src/__tests__/whoami.test.tsx +86 -0
  28. package/src/api/form_data.ts +10 -7
  29. package/src/api/preview.ts +2 -2
  30. package/src/api/worker.ts +3 -3
  31. package/src/cfetch/index.ts +14 -14
  32. package/src/cfetch/internal.ts +40 -8
  33. package/src/config.ts +162 -8
  34. package/src/dev.tsx +103 -53
  35. package/src/dialogs.tsx +2 -2
  36. package/src/index.tsx +438 -311
  37. package/src/inspect.ts +80 -23
  38. package/src/kv.tsx +9 -1
  39. package/src/module-collection.ts +5 -6
  40. package/src/package-manager.ts +120 -0
  41. package/src/pages.tsx +41 -26
  42. package/src/paths.ts +26 -0
  43. package/src/proxy.ts +78 -10
  44. package/src/publish.ts +98 -52
  45. package/src/sites.tsx +175 -53
  46. package/src/user.tsx +51 -59
  47. package/src/whoami.tsx +69 -0
  48. package/templates/new-worker.js +15 -0
  49. package/templates/new-worker.ts +15 -0
  50. package/{static-asset-facade.js → templates/static-asset-facade.js} +0 -0
  51. package/wrangler-dist/cli.js +111479 -110187
  52. package/wrangler-dist/cli.js.map +3 -3
  53. package/src/__tests__/run-in-tmp.ts +0 -19
  54. package/src/__tests__/run-wrangler.ts +0 -32
@@ -0,0 +1,56 @@
1
+ /**
2
+ * We use this module to mock console methods, and optionally
3
+ * assert on the values they're called with in our tests.
4
+ */
5
+
6
+ let logSpy: jest.SpyInstance,
7
+ errorSpy: jest.SpyInstance,
8
+ warnSpy: jest.SpyInstance;
9
+
10
+ const std = {
11
+ get out() {
12
+ return normalizeSlashes(stripTimings(logSpy.mock.calls.flat(2).join("\n")));
13
+ },
14
+ get err() {
15
+ return normalizeSlashes(
16
+ stripTimings(errorSpy.mock.calls.flat(2).join("\n"))
17
+ );
18
+ },
19
+ get warn() {
20
+ return normalizeSlashes(
21
+ stripTimings(warnSpy.mock.calls.flat(2).join("\n"))
22
+ );
23
+ },
24
+ };
25
+
26
+ export function mockConsoleMethods() {
27
+ beforeEach(() => {
28
+ logSpy = jest.spyOn(console, "log").mockImplementation();
29
+ errorSpy = jest.spyOn(console, "error").mockImplementation();
30
+ warnSpy = jest.spyOn(console, "warn").mockImplementation();
31
+ });
32
+ afterEach(() => {
33
+ logSpy.mockRestore();
34
+ errorSpy.mockRestore();
35
+ warnSpy.mockRestore();
36
+ });
37
+ return std;
38
+ }
39
+
40
+ /**
41
+ * Ensure slashes in the `str` are OS file-system agnostic.
42
+ *
43
+ * Use this in snapshot tests to be resilient to file-system differences.
44
+ */
45
+ export function normalizeSlashes(str: string): string {
46
+ return str.replace(/\\/g, "/");
47
+ }
48
+
49
+ /**
50
+ * Strip "timing data" out of the `stdout` string, since this is not always deterministic.
51
+ *
52
+ * Use this in snapshot tests to be resilient to slight changes in timing of processing.
53
+ */
54
+ export function stripTimings(stdout: string): string {
55
+ return stdout.replace(/\(\d+\.\d+ sec\)/g, "(TIMINGS)");
56
+ }
@@ -1,4 +1,4 @@
1
- import { confirm, prompt } from "../dialogs";
1
+ import { confirm, prompt } from "../../dialogs";
2
2
 
3
3
  /**
4
4
  * The expected values for a confirmation request.
@@ -0,0 +1,40 @@
1
+ import { createFetchResult, setMockRawResponse } from "./mock-cfetch";
2
+
3
+ export function mockKeyListRequest(
4
+ expectedNamespaceId: string,
5
+ expectedKeys: string[],
6
+ keysPerRequest = 1000,
7
+ blankCursorValue: "" | undefined | null = undefined
8
+ ) {
9
+ const requests = { count: 0 };
10
+ // See https://api.cloudflare.com/#workers-kv-namespace-list-a-namespace-s-keys
11
+ const expectedKeyObjects = expectedKeys.map((name) => ({
12
+ name,
13
+ expiration: 123456789,
14
+ metadata: {},
15
+ }));
16
+ setMockRawResponse(
17
+ "/accounts/:accountId/storage/kv/namespaces/:namespaceId/keys",
18
+ "GET",
19
+ ([_url, accountId, namespaceId], _init, query) => {
20
+ requests.count++;
21
+ expect(accountId).toEqual("some-account-id");
22
+ expect(namespaceId).toEqual(expectedNamespaceId);
23
+ if (expectedKeyObjects.length <= keysPerRequest) {
24
+ return createFetchResult(expectedKeyObjects);
25
+ } else {
26
+ const start = parseInt(query.get("cursor") ?? "0") || 0;
27
+ const end = start + keysPerRequest;
28
+ const cursor = end < expectedKeyObjects.length ? end : blankCursorValue;
29
+ return createFetchResult(
30
+ expectedKeyObjects.slice(start, end),
31
+ true,
32
+ [],
33
+ [],
34
+ { cursor }
35
+ );
36
+ }
37
+ }
38
+ );
39
+ return requests;
40
+ }
@@ -0,0 +1,27 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+
5
+ export function writeUserConfig(
6
+ oauth_token?: string,
7
+ refresh_token?: string,
8
+ expiration_time?: string
9
+ ) {
10
+ const lines: string[] = [];
11
+ if (oauth_token) {
12
+ lines.push(`oauth_token = "${oauth_token}"`);
13
+ }
14
+ if (refresh_token) {
15
+ lines.push(`refresh_token = "${refresh_token}"`);
16
+ }
17
+ if (expiration_time) {
18
+ lines.push(`expiration_time = "${expiration_time}"`);
19
+ }
20
+ const configPath = path.join(os.homedir(), ".wrangler/config");
21
+ mkdirSync(configPath, { recursive: true });
22
+ writeFileSync(
23
+ path.join(configPath, "default.toml"),
24
+ lines.join("\n"),
25
+ "utf-8"
26
+ );
27
+ }
@@ -0,0 +1,29 @@
1
+ import * as fs from "node:fs";
2
+ import os from "node:os";
3
+ import * as path from "node:path";
4
+
5
+ const originalCwd = process.cwd();
6
+
7
+ export function runInTempDir({ homedir }: { homedir?: string } = {}) {
8
+ let tmpDir: string;
9
+
10
+ beforeEach(() => {
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "wrangler-tests"));
12
+ process.chdir(tmpDir);
13
+ if (homedir !== undefined) {
14
+ // Override where the home directory is so that we can write our own user config,
15
+ // without destroying the real thing.
16
+ fs.mkdirSync(homedir);
17
+ // Note it is very important that we use the "default" value from "node:os" (e.g. `import os from "node:os";`)
18
+ // rather than an alias to the module (e.g. `import * as os from "node:os";`).
19
+ // This is because the module gets transpiled so that the "method" `homedir()` gets converted to a
20
+ // getter that is not configurable (and so cannot be spied upon).
21
+ jest.spyOn(os, "homedir").mockReturnValue(homedir);
22
+ }
23
+ });
24
+
25
+ afterEach(() => {
26
+ process.chdir(originalCwd);
27
+ fs.rmSync(tmpDir, { recursive: true });
28
+ });
29
+ }
@@ -0,0 +1,14 @@
1
+ import { main } from "../../index";
2
+ import { normalizeSlashes, stripTimings } from "./mock-console";
3
+
4
+ /**
5
+ * A helper to 'run' wrangler commands for tests.
6
+ */
7
+ export async function runWrangler(cmd?: string) {
8
+ try {
9
+ await main(cmd?.split(" ") ?? []);
10
+ } catch (e) {
11
+ e.message = normalizeSlashes(stripTimings(e.message));
12
+ throw e;
13
+ }
14
+ }
@@ -1,22 +1,38 @@
1
+ import * as fs from "node:fs";
1
2
  import * as fsp from "node:fs/promises";
2
3
  import * as TOML from "@iarna/toml";
3
- import { mockConfirm } from "./mock-dialogs";
4
- import { runWrangler } from "./run-wrangler";
5
- import { runInTempDir } from "./run-in-tmp";
6
- import * as fs from "node:fs";
4
+ import { version as wranglerVersion } from "../../package.json";
5
+ import { getPackageManager } from "../package-manager";
6
+ import { mockConsoleMethods } from "./helpers/mock-console";
7
+ import { mockConfirm } from "./helpers/mock-dialogs";
8
+ import { runInTempDir } from "./helpers/run-in-tmp";
9
+ import { runWrangler } from "./helpers/run-wrangler";
10
+ import type { PackageManager } from "../package-manager";
7
11
 
8
12
  describe("wrangler", () => {
13
+ let mockPackageManager: PackageManager;
9
14
  runInTempDir();
10
15
 
16
+ beforeEach(() => {
17
+ mockPackageManager = {
18
+ addDevDeps: jest.fn(),
19
+ install: jest.fn(),
20
+ };
21
+ (getPackageManager as jest.Mock).mockResolvedValue(mockPackageManager);
22
+ });
23
+
24
+ const std = mockConsoleMethods();
25
+
11
26
  describe("no command", () => {
12
27
  it("should display a list of available commands", async () => {
13
- const { stdout, stderr } = await runWrangler();
28
+ await runWrangler();
14
29
 
15
- expect(stdout).toMatchInlineSnapshot(`
30
+ expect(std.out).toMatchInlineSnapshot(`
16
31
  "wrangler
17
32
 
18
33
  Commands:
19
34
  wrangler init [name] 📥 Create a wrangler.toml configuration file
35
+ wrangler whoami 🕵️ Retrieve your user info and test your auth config
20
36
  wrangler dev <filename> 👂 Start a local server for developing your worker
21
37
  wrangler publish [script] 🆙 Publish your Worker to Cloudflare.
22
38
  wrangler tail [name] 🦚 Starts a log tailing session for a deployed Worker.
@@ -35,20 +51,25 @@ describe("wrangler", () => {
35
51
  -l, --local Run on my machine [boolean] [default: false]"
36
52
  `);
37
53
 
38
- expect(stderr).toMatchInlineSnapshot(`""`);
54
+ expect(std.err).toMatchInlineSnapshot(`""`);
39
55
  });
40
56
  });
41
57
 
42
58
  describe("invalid command", () => {
43
59
  it("should display an error", async () => {
44
- const { error, stdout, stderr } = await runWrangler("invalid-command");
60
+ await expect(
61
+ runWrangler("invalid-command")
62
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
63
+ `"Unknown command: invalid-command."`
64
+ );
45
65
 
46
- expect(stdout).toMatchInlineSnapshot(`""`);
47
- expect(stderr).toMatchInlineSnapshot(`
66
+ expect(std.out).toMatchInlineSnapshot(`""`);
67
+ expect(std.err).toMatchInlineSnapshot(`
48
68
  "wrangler
49
69
 
50
70
  Commands:
51
71
  wrangler init [name] 📥 Create a wrangler.toml configuration file
72
+ wrangler whoami 🕵️ Retrieve your user info and test your auth config
52
73
  wrangler dev <filename> 👂 Start a local server for developing your worker
53
74
  wrangler publish [script] 🆙 Publish your Worker to Cloudflare.
54
75
  wrangler tail [name] 🦚 Starts a log tailing session for a deployed Worker.
@@ -68,9 +89,6 @@ describe("wrangler", () => {
68
89
 
69
90
  Unknown command: invalid-command."
70
91
  `);
71
- expect(error).toMatchInlineSnapshot(
72
- `[Error: Unknown command: invalid-command.]`
73
- );
74
92
  });
75
93
  });
76
94
 
@@ -88,19 +106,27 @@ describe("wrangler", () => {
88
106
  });
89
107
 
90
108
  it("should display warning when wrangler.toml already exists, and exit if user does not want to carry on", async () => {
91
- fs.writeFileSync("./wrangler.toml", "", "utf-8");
109
+ fs.writeFileSync(
110
+ "./wrangler.toml",
111
+ 'compatibility_date="something-else"', // use a fake value to make sure the file is not overwritten
112
+ "utf-8"
113
+ );
92
114
  mockConfirm({
93
115
  text: "Do you want to continue initializing this project?",
94
116
  result: false,
95
117
  });
96
- const { warnings } = await runWrangler("init");
97
- expect(warnings).toContain("wrangler.toml file already exists!");
118
+ await runWrangler("init");
119
+ expect(std.warn).toContain("wrangler.toml file already exists!");
98
120
  const parsed = TOML.parse(await fsp.readFile("./wrangler.toml", "utf-8"));
99
- expect(typeof parsed.compatibility_date).toBe("undefined");
121
+ expect(parsed.compatibility_date).toBe("something-else");
100
122
  });
101
123
 
102
124
  it("should display warning when wrangler.toml already exists, but continue if user does want to carry on", async () => {
103
- fs.writeFileSync("./wrangler.toml", "", "utf-8");
125
+ fs.writeFileSync(
126
+ "./wrangler.toml",
127
+ `compatibility_date="something-else"`,
128
+ "utf-8"
129
+ );
104
130
  mockConfirm(
105
131
  {
106
132
  text: "Do you want to continue initializing this project?",
@@ -111,10 +137,10 @@ describe("wrangler", () => {
111
137
  result: false,
112
138
  }
113
139
  );
114
- const { warnings } = await runWrangler("init");
115
- expect(warnings).toContain("wrangler.toml file already exists!");
140
+ await runWrangler("init");
141
+ expect(std.warn).toContain("wrangler.toml file already exists!");
116
142
  const parsed = TOML.parse(await fsp.readFile("./wrangler.toml", "utf-8"));
117
- expect(typeof parsed.compatibility_date).toBe("string");
143
+ expect(parsed.compatibility_date).toBe("something-else");
118
144
  });
119
145
 
120
146
  it("should create a package.json if none is found and user confirms", async () => {
@@ -124,7 +150,11 @@ describe("wrangler", () => {
124
150
  result: true,
125
151
  },
126
152
  {
127
- text: "Would you like to use typescript?",
153
+ text: "Would you like to use TypeScript?",
154
+ result: false,
155
+ },
156
+ {
157
+ text: "Would you like to create a Worker at src/index.js?",
128
158
  result: false,
129
159
  }
130
160
  );
@@ -134,15 +164,59 @@ describe("wrangler", () => {
134
164
  fs.readFileSync("./package.json", "utf-8")
135
165
  );
136
166
  expect(packageJson.name).toEqual("worker"); // TODO: should we infer the name from the directory?
137
- expect(packageJson.version).toEqual("0.0.1");
167
+ expect(packageJson.version).toEqual("0.0.0");
168
+ expect(packageJson.devDependencies).toEqual({
169
+ wrangler: expect.any(String),
170
+ });
138
171
  expect(fs.existsSync("./tsconfig.json")).toBe(false);
172
+ expect(mockPackageManager.install).toHaveBeenCalled();
139
173
  });
140
174
 
141
175
  it("should not touch an existing package.json in the same directory", async () => {
142
- mockConfirm({
143
- text: "Would you like to use typescript?",
144
- result: false,
145
- });
176
+ mockConfirm(
177
+ {
178
+ text: "Would you like to install wrangler into your package.json?",
179
+ result: false,
180
+ },
181
+ {
182
+ text: "Would you like to use TypeScript?",
183
+ result: false,
184
+ },
185
+ {
186
+ text: "Would you like to create a Worker at src/index.js?",
187
+ result: false,
188
+ }
189
+ );
190
+
191
+ fs.writeFileSync(
192
+ "./package.json",
193
+ JSON.stringify({ name: "test", version: "1.0.0" }),
194
+ "utf-8"
195
+ );
196
+
197
+ await runWrangler("init");
198
+ const packageJson = JSON.parse(
199
+ fs.readFileSync("./package.json", "utf-8")
200
+ );
201
+ expect(packageJson.name).toEqual("test");
202
+ expect(packageJson.version).toEqual("1.0.0");
203
+ });
204
+
205
+ it("should offer to install wrangler into an existing package.json", async () => {
206
+ mockConfirm(
207
+ {
208
+ text: "Would you like to install wrangler into your package.json?",
209
+ result: true,
210
+ },
211
+ {
212
+ text: "Would you like to use TypeScript?",
213
+ result: false,
214
+ },
215
+ {
216
+ text: "Would you like to create a Worker at src/index.js?",
217
+ result: false,
218
+ }
219
+ );
146
220
 
147
221
  fs.writeFileSync(
148
222
  "./package.json",
@@ -156,13 +230,26 @@ describe("wrangler", () => {
156
230
  );
157
231
  expect(packageJson.name).toEqual("test");
158
232
  expect(packageJson.version).toEqual("1.0.0");
233
+ expect(mockPackageManager.addDevDeps).toHaveBeenCalledWith(
234
+ `wrangler@${wranglerVersion}`
235
+ );
159
236
  });
160
237
 
161
238
  it("should not touch an existing package.json in an ancestor directory", async () => {
162
- mockConfirm({
163
- text: "Would you like to use typescript?",
164
- result: false,
165
- });
239
+ mockConfirm(
240
+ {
241
+ text: "Would you like to install wrangler into your package.json?",
242
+ result: false,
243
+ },
244
+ {
245
+ text: "Would you like to use TypeScript?",
246
+ result: false,
247
+ },
248
+ {
249
+ text: "Would you like to create a Worker at src/index.js?",
250
+ result: false,
251
+ }
252
+ );
166
253
 
167
254
  fs.writeFileSync(
168
255
  "./package.json",
@@ -180,8 +267,118 @@ describe("wrangler", () => {
180
267
  const packageJson = JSON.parse(
181
268
  fs.readFileSync("../../package.json", "utf-8")
182
269
  );
183
- expect(packageJson.name).toEqual("test");
184
- expect(packageJson.version).toEqual("1.0.0");
270
+ expect(packageJson).toMatchInlineSnapshot(`
271
+ Object {
272
+ "name": "test",
273
+ "version": "1.0.0",
274
+ }
275
+ `);
276
+ });
277
+
278
+ it("should offer to create a worker in a non-typescript project", async () => {
279
+ mockConfirm(
280
+ {
281
+ text: "Would you like to install wrangler into your package.json?",
282
+ result: false,
283
+ },
284
+ {
285
+ text: "Would you like to use TypeScript?",
286
+ result: false,
287
+ },
288
+ {
289
+ text: "Would you like to create a Worker at src/index.js?",
290
+ result: true,
291
+ }
292
+ );
293
+
294
+ fs.writeFileSync(
295
+ "./package.json",
296
+ JSON.stringify({ name: "test", version: "1.0.0" }),
297
+ "utf-8"
298
+ );
299
+
300
+ await runWrangler("init");
301
+ expect(fs.existsSync("./src/index.js")).toBe(true);
302
+ expect(fs.existsSync("./src/index.ts")).toBe(false);
303
+ });
304
+
305
+ it("should offer to create a worker in a typescript project", async () => {
306
+ mockConfirm(
307
+ {
308
+ text: "Would you like to install wrangler into your package.json?",
309
+ result: false,
310
+ },
311
+ {
312
+ text: "Would you like to use TypeScript?",
313
+ result: true,
314
+ },
315
+ {
316
+ text: "Would you like to create a Worker at src/index.ts?",
317
+ result: true,
318
+ }
319
+ );
320
+
321
+ fs.writeFileSync(
322
+ "./package.json",
323
+ JSON.stringify({ name: "test", version: "1.0.0" }),
324
+ "utf-8"
325
+ );
326
+
327
+ await runWrangler("init");
328
+ expect(fs.existsSync("./src/index.js")).toBe(false);
329
+ expect(fs.existsSync("./src/index.ts")).toBe(true);
330
+ });
331
+
332
+ it("should not offer to create a worker in a non-ts project if a file already exists at the location", async () => {
333
+ mockConfirm(
334
+ {
335
+ text: "Would you like to install wrangler into your package.json?",
336
+ result: false,
337
+ },
338
+ {
339
+ text: "Would you like to use TypeScript?",
340
+ result: false,
341
+ }
342
+ );
343
+
344
+ fs.writeFileSync(
345
+ "./package.json",
346
+ JSON.stringify({ name: "test", version: "1.0.0" }),
347
+ "utf-8"
348
+ );
349
+ fs.mkdirSync("./src", { recursive: true });
350
+ const PLACEHOLDER = "/* placeholder text */";
351
+ fs.writeFileSync("./src/index.js", PLACEHOLDER, "utf-8");
352
+
353
+ await runWrangler("init");
354
+ expect(fs.readFileSync("./src/index.js", "utf-8")).toBe(PLACEHOLDER);
355
+ expect(fs.existsSync("./src/index.ts")).toBe(false);
356
+ });
357
+
358
+ it("should not offer to create a worker in a ts project if a file already exists at the location", async () => {
359
+ mockConfirm(
360
+ {
361
+ text: "Would you like to install wrangler into your package.json?",
362
+ result: false,
363
+ },
364
+ {
365
+ text: "Would you like to use TypeScript?",
366
+ result: true,
367
+ }
368
+ );
369
+
370
+ fs.writeFileSync(
371
+ "./package.json",
372
+ JSON.stringify({ name: "test", version: "1.0.0" }),
373
+ "utf-8"
374
+ );
375
+ fs.mkdirSync("./src", { recursive: true });
376
+ const PLACEHOLDER = "/* placeholder text */";
377
+ fs.writeFileSync("./src/index.ts", PLACEHOLDER, "utf-8");
378
+
379
+ await runWrangler("init");
380
+ expect(fs.existsSync("./src/index.js")).toBe(false);
381
+ expect(fs.readFileSync("./src/index.ts", "utf-8")).toBe(PLACEHOLDER);
185
382
  });
186
383
 
187
384
  it("should create a tsconfig.json and install `workers-types` if none is found and user confirms", async () => {
@@ -191,8 +388,12 @@ describe("wrangler", () => {
191
388
  result: true,
192
389
  },
193
390
  {
194
- text: "Would you like to use typescript?",
391
+ text: "Would you like to use TypeScript?",
195
392
  result: true,
393
+ },
394
+ {
395
+ text: "Would you like to create a Worker at src/index.ts?",
396
+ result: false,
196
397
  }
197
398
  );
198
399
  await runWrangler("init");
@@ -203,18 +404,23 @@ describe("wrangler", () => {
203
404
  expect(tsconfigJson.compilerOptions.types).toEqual([
204
405
  "@cloudflare/workers-types",
205
406
  ]);
206
- const packageJson = JSON.parse(
207
- fs.readFileSync("./package.json", "utf-8")
407
+ expect(mockPackageManager.addDevDeps).toHaveBeenCalledWith(
408
+ "@cloudflare/workers-types",
409
+ "typescript"
208
410
  );
209
- expect(packageJson.devDependencies).toEqual({
210
- "@cloudflare/workers-types": expect.any(String),
211
- });
212
411
  });
213
412
 
214
413
  it("should not touch an existing tsconfig.json in the same directory", async () => {
215
414
  fs.writeFileSync(
216
415
  "./package.json",
217
- JSON.stringify({ name: "test", version: "1.0.0" }),
416
+ JSON.stringify({
417
+ name: "test",
418
+ version: "1.0.0",
419
+ devDependencies: {
420
+ wrangler: "0.0.0",
421
+ "@cloudflare/workers-types": "0.0.0",
422
+ },
423
+ }),
218
424
  "utf-8"
219
425
  );
220
426
  fs.writeFileSync(
@@ -230,10 +436,57 @@ describe("wrangler", () => {
230
436
  expect(tsconfigJson.compilerOptions).toEqual({});
231
437
  });
232
438
 
233
- it("should not touch an existing package.json in an ancestor directory", async () => {
439
+ it("should offer to install type definitions in an existing typescript project", async () => {
440
+ mockConfirm(
441
+ {
442
+ text: "Would you like to install wrangler into your package.json?",
443
+ result: false,
444
+ },
445
+ {
446
+ text: "Would you like to install the type definitions for Workers into your package.json?",
447
+ result: true,
448
+ },
449
+ {
450
+ text: "Would you like to create a Worker at src/index.ts?",
451
+ result: false,
452
+ }
453
+ );
234
454
  fs.writeFileSync(
235
455
  "./package.json",
236
- JSON.stringify({ name: "test", version: "1.0.0" }),
456
+ JSON.stringify({
457
+ name: "test",
458
+ version: "1.0.0",
459
+ }),
460
+ "utf-8"
461
+ );
462
+ fs.writeFileSync(
463
+ "./tsconfig.json",
464
+ JSON.stringify({ compilerOptions: {} }),
465
+ "utf-8"
466
+ );
467
+
468
+ await runWrangler("init");
469
+ const tsconfigJson = JSON.parse(
470
+ fs.readFileSync("./tsconfig.json", "utf-8")
471
+ );
472
+ // unchanged tsconfig
473
+ expect(tsconfigJson.compilerOptions).toEqual({});
474
+ expect(mockPackageManager.addDevDeps).toHaveBeenCalledWith(
475
+ "@cloudflare/workers-types"
476
+ );
477
+ });
478
+
479
+ it("should not touch an existing tsconfig.json in an ancestor directory", async () => {
480
+ fs.writeFileSync(
481
+ "./package.json",
482
+ JSON.stringify({
483
+ name: "test",
484
+ version: "1.0.0",
485
+ devDependencies: {
486
+ wrangler: "0.0.0",
487
+ "@cloudflare/workers-types": "0.0.0",
488
+ },
489
+ }),
237
490
  "utf-8"
238
491
  );
239
492
  fs.writeFileSync(
@@ -256,32 +509,35 @@ describe("wrangler", () => {
256
509
  });
257
510
 
258
511
  it("should error if `--type` is used", async () => {
259
- const { error } = await runWrangler("init --type");
260
- expect(error).toMatchInlineSnapshot(
261
- `[Error: The --type option is no longer supported.]`
512
+ await expect(
513
+ runWrangler("init --type")
514
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
515
+ `"The --type option is no longer supported."`
262
516
  );
263
517
  });
264
518
 
265
519
  it("should error if `--type javascript` is used", async () => {
266
- const { error } = await runWrangler("init --type javascript");
267
- expect(error).toMatchInlineSnapshot(
268
- `[Error: The --type option is no longer supported.]`
520
+ await expect(
521
+ runWrangler("init --type javascript")
522
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
523
+ `"The --type option is no longer supported."`
269
524
  );
270
525
  });
271
526
 
272
527
  it("should error if `--type rust` is used", async () => {
273
- const { error } = await runWrangler("init --type rust");
274
- expect(error).toMatchInlineSnapshot(
275
- `[Error: The --type option is no longer supported.]`
528
+ await expect(
529
+ runWrangler("init --type rust")
530
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
531
+ `"The --type option is no longer supported."`
276
532
  );
277
533
  });
278
534
 
279
535
  it("should error if `--type webpack` is used", async () => {
280
- const { error } = await runWrangler("init --type webpack");
281
- expect(error).toMatchInlineSnapshot(`
282
- [Error: The --type option is no longer supported.
283
- If you wish to use webpack then you will need to create a custom build.]
284
- `);
536
+ await expect(runWrangler("init --type webpack")).rejects
537
+ .toThrowErrorMatchingInlineSnapshot(`
538
+ "The --type option is no longer supported.
539
+ If you wish to use webpack then you will need to create a custom build."
540
+ `);
285
541
  });
286
542
  });
287
543
  });