wrangler 2.6.2 → 2.7.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.
- package/bin/wrangler.js +9 -1
- package/miniflare-dist/index.mjs +1 -1
- package/package.json +12 -10
- package/src/__tests__/api-dev.test.ts +65 -36
- package/src/__tests__/api-devregistry.test.js +14 -6
- package/src/__tests__/configuration.test.ts +2 -31
- package/src/__tests__/{d1.test.ts → d1/d1.test.ts} +48 -5
- package/src/__tests__/d1/splitter.test.ts +255 -0
- package/src/__tests__/delete.test.ts +5 -2
- package/src/__tests__/deployments.test.ts +20 -6
- package/src/__tests__/dev.test.tsx +52 -19
- package/src/__tests__/generate.test.ts +7 -4
- package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
- package/src/__tests__/helpers/mock-cfetch.ts +2 -57
- package/src/__tests__/helpers/mock-dialogs.ts +70 -86
- package/src/__tests__/helpers/mock-oauth-flow.ts +64 -49
- package/src/__tests__/helpers/mock-process.ts +8 -13
- package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
- package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
- package/src/__tests__/index.test.ts +46 -44
- package/src/__tests__/init.test.ts +761 -537
- package/src/__tests__/jest.setup.ts +20 -24
- package/src/__tests__/kv.test.ts +286 -173
- package/src/__tests__/logout.test.ts +1 -1
- package/src/__tests__/metrics.test.ts +5 -7
- package/src/__tests__/middleware.scheduled.test.ts +40 -30
- package/src/__tests__/middleware.test.ts +144 -120
- package/src/__tests__/pages.test.ts +1617 -1161
- package/src/__tests__/publish.test.ts +174 -125
- package/src/__tests__/r2.test.ts +2 -2
- package/src/__tests__/secret.test.ts +183 -126
- package/src/__tests__/tail.test.ts +6 -0
- package/src/__tests__/tsconfig-sanity.ts +12 -0
- package/src/__tests__/tsconfig.json +8 -0
- package/src/__tests__/tsconfig.tsbuildinfo +1 -0
- package/src/__tests__/whoami.test.tsx +1 -96
- package/src/api/dev.ts +78 -41
- package/src/api/index.ts +1 -1
- package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
- package/src/cfetch/index.ts +0 -2
- package/src/cfetch/internal.ts +6 -15
- package/src/cli.ts +2 -2
- package/src/config/validation.ts +1 -2
- package/src/create-worker-upload-form.ts +2 -2
- package/src/d1/{delete.tsx → delete.ts} +0 -0
- package/src/d1/execute.tsx +8 -37
- package/src/d1/migrations/apply.tsx +29 -19
- package/src/d1/migrations/{index.tsx → index.ts} +0 -0
- package/src/d1/splitter.ts +161 -0
- package/src/d1/{types.tsx → types.ts} +0 -0
- package/src/delete.ts +3 -8
- package/src/deployments.ts +6 -0
- package/src/deprecated/index.ts +2 -295
- package/src/dev/dev.tsx +2 -2
- package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
- package/src/dev/local.tsx +16 -4
- package/src/dev/remote.tsx +28 -1
- package/src/dev/start-server.ts +19 -11
- package/src/dev/use-esbuild.ts +1 -1
- package/src/{dev-registry.tsx → dev-registry.ts} +0 -0
- package/src/dev.tsx +21 -2
- package/src/dialogs.ts +136 -0
- package/src/dispatch-namespace.ts +1 -1
- package/src/docs/index.ts +3 -0
- package/src/environment-variables/factory.ts +88 -0
- package/src/environment-variables/misc-variables.ts +30 -0
- package/src/generate/index.ts +300 -0
- package/src/{index.tsx → index.ts} +10 -13
- package/src/init.ts +92 -52
- package/src/jest.d.ts +4 -0
- package/src/logger.ts +15 -3
- package/src/metrics/metrics-config.ts +1 -1
- package/src/miniflare-cli/assets.ts +4 -0
- package/src/miniflare-cli/index.ts +1 -5
- package/src/miniflare-cli/tsconfig.json +9 -0
- package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
- package/src/miniflare-cli/types.ts +11 -0
- package/src/pages/{build.tsx → build.ts} +0 -0
- package/src/pages/{deployment-tails.tsx → deployment-tails.ts} +0 -0
- package/src/pages/{dev.tsx → dev.ts} +53 -55
- package/src/pages/functions/buildWorker.ts +1 -1
- package/src/pages/functions/tsconfig.json +8 -0
- package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
- package/src/pages/{functions.tsx → functions.ts} +0 -0
- package/src/pages/{hash.tsx → hash.ts} +0 -0
- package/src/pages/{index.tsx → index.ts} +0 -0
- package/src/pages/projects.tsx +3 -5
- package/src/pages/publish.tsx +5 -4
- package/src/pages/upload.tsx +1 -1
- package/src/publish/publish.ts +9 -7
- package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +1 -1
- package/src/secret/index.ts +1 -1
- package/src/{sites.tsx → sites.ts} +0 -0
- package/src/tail/index.ts +2 -3
- package/src/tsconfig-sanity.ts +16 -0
- package/src/user/access.ts +0 -1
- package/src/user/auth-variables.ts +113 -0
- package/src/user/choose-account.tsx +1 -31
- package/src/user/index.ts +0 -1
- package/src/user/{user.tsx → user.ts} +107 -73
- package/src/{whoami.tsx → whoami.ts} +37 -71
- package/templates/__tests__/tsconfig-sanity.ts +12 -0
- package/templates/__tests__/tsconfig.json +8 -0
- package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
- package/templates/d1-beta-facade.js +36 -0
- package/templates/facade.d.ts +14 -0
- package/templates/first-party-worker-module-facade.ts +4 -3
- package/templates/format-dev-errors.ts +7 -6
- package/templates/init-tests/test-jest-new-worker.js +3 -5
- package/templates/init-tests/test-vitest-new-worker.js +3 -5
- package/templates/init-tests/test-vitest-new-worker.ts +25 -0
- package/templates/middleware/loader-modules.ts +0 -2
- package/templates/middleware/loader-sw.ts +6 -0
- package/templates/pages-dev-pipeline.ts +4 -1
- package/templates/pages-shim.ts +4 -1
- package/templates/pages-template-plugin.ts +12 -7
- package/templates/serve-static-assets.ts +16 -14
- package/templates/tsconfig-sanity.ts +11 -0
- package/templates/tsconfig.init.json +106 -0
- package/templates/tsconfig.json +5 -103
- package/templates/tsconfig.tsbuildinfo +1 -0
- package/wrangler-dist/cli.d.ts +58 -60
- package/wrangler-dist/cli.js +34440 -55514
- package/wrangler-dist/wasm-sync.wasm +0 -0
- package/src/__tests__/dialogs.test.tsx +0 -40
- package/src/dialogs.tsx +0 -168
- package/src/environment-variables.ts +0 -50
- package/src/user/env-vars.ts +0 -46
|
@@ -2,17 +2,20 @@ import { rest } from "msw";
|
|
|
2
2
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
3
3
|
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
4
4
|
import { mockConfirm } from "./helpers/mock-dialogs";
|
|
5
|
+
import { useMockIsTTY } from "./helpers/mock-istty";
|
|
5
6
|
import { msw } from "./helpers/msw";
|
|
6
7
|
import { runInTempDir } from "./helpers/run-in-tmp";
|
|
7
8
|
import { runWrangler } from "./helpers/run-wrangler";
|
|
8
9
|
import writeWranglerToml from "./helpers/write-wrangler-toml";
|
|
9
10
|
import type { KVNamespaceInfo } from "../kv/helpers";
|
|
10
|
-
|
|
11
11
|
describe("delete", () => {
|
|
12
12
|
mockAccountId();
|
|
13
13
|
mockApiToken();
|
|
14
14
|
runInTempDir();
|
|
15
|
-
|
|
15
|
+
const { setIsTTY } = useMockIsTTY();
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
setIsTTY(true);
|
|
18
|
+
});
|
|
16
19
|
const std = mockConsoleMethods();
|
|
17
20
|
|
|
18
21
|
it("should delete an entire service by name", async () => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// import * as fs from "fs";
|
|
2
2
|
// import * as TOML from "@iarna/toml";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as TOML from "@iarna/toml";
|
|
3
5
|
import { rest } from "msw";
|
|
4
6
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
5
7
|
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
@@ -26,11 +28,7 @@ describe("deployments", () => {
|
|
|
26
28
|
...mswSuccessUserHandlers,
|
|
27
29
|
rest.get(
|
|
28
30
|
"*/accounts/:accountId/workers/services/:scriptName",
|
|
29
|
-
(
|
|
30
|
-
expect(["undefined", "somethingElse"]).toContain(
|
|
31
|
-
request.params.scriptName
|
|
32
|
-
);
|
|
33
|
-
|
|
31
|
+
(_, response, context) => {
|
|
34
32
|
return response.once(
|
|
35
33
|
context.status(200),
|
|
36
34
|
context.json({
|
|
@@ -52,6 +50,16 @@ describe("deployments", () => {
|
|
|
52
50
|
});
|
|
53
51
|
|
|
54
52
|
it("should log deployments", async () => {
|
|
53
|
+
fs.writeFileSync(
|
|
54
|
+
"./wrangler.toml",
|
|
55
|
+
TOML.stringify({
|
|
56
|
+
compatibility_date: "2022-01-12",
|
|
57
|
+
name: "test-script-name",
|
|
58
|
+
first_party_worker: true,
|
|
59
|
+
}),
|
|
60
|
+
"utf-8"
|
|
61
|
+
);
|
|
62
|
+
|
|
55
63
|
await runWrangler("deployments");
|
|
56
64
|
expect(std.out).toMatchInlineSnapshot(`
|
|
57
65
|
"🚧\`wrangler deployments\` is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
@@ -71,7 +79,7 @@ describe("deployments", () => {
|
|
|
71
79
|
});
|
|
72
80
|
|
|
73
81
|
it("should log deployments for script with passed in name option", async () => {
|
|
74
|
-
await runWrangler("deployments --name
|
|
82
|
+
await runWrangler("deployments --name something-else");
|
|
75
83
|
expect(std.out).toMatchInlineSnapshot(`
|
|
76
84
|
"🚧\`wrangler deployments\` is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
77
85
|
|
|
@@ -88,4 +96,10 @@ describe("deployments", () => {
|
|
|
88
96
|
🟩 Active"
|
|
89
97
|
`);
|
|
90
98
|
});
|
|
99
|
+
|
|
100
|
+
it("should error on missing script name", async () => {
|
|
101
|
+
await expect(runWrangler("deployments")).rejects.toMatchInlineSnapshot(
|
|
102
|
+
`[Error: Required Worker name missing. Please specify the Worker name in wrangler.toml, or pass it as an argument with \`--name\`]`
|
|
103
|
+
);
|
|
104
|
+
});
|
|
91
105
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import getPort from "get-port";
|
|
3
|
+
import { rest } from "msw";
|
|
3
4
|
import patchConsole from "patch-console";
|
|
4
5
|
import dedent from "ts-dedent";
|
|
5
6
|
import Dev from "../dev/dev";
|
|
6
7
|
import { CI } from "../is-ci";
|
|
7
8
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
8
|
-
import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
|
|
9
9
|
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
10
10
|
import {
|
|
11
11
|
msw,
|
|
@@ -33,7 +33,7 @@ describe("wrangler dev", () => {
|
|
|
33
33
|
afterEach(() => {
|
|
34
34
|
(Dev as jest.Mock).mockClear();
|
|
35
35
|
patchConsole(() => {});
|
|
36
|
-
|
|
36
|
+
msw.resetHandlers();
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
describe("authorization", () => {
|
|
@@ -439,16 +439,44 @@ describe("wrangler dev", () => {
|
|
|
439
439
|
main: "index.js",
|
|
440
440
|
});
|
|
441
441
|
fs.writeFileSync("index.js", `export default {};`);
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
442
|
+
|
|
443
|
+
msw.use(
|
|
444
|
+
rest.get("*/zones", (req, res, ctx) => {
|
|
445
|
+
let zone: [] | [{ id: "some-zone-id" }] = [];
|
|
446
|
+
if (
|
|
447
|
+
req.url.searchParams.get("name") === "111.222.333.some-host.com"
|
|
448
|
+
) {
|
|
449
|
+
zone = [];
|
|
450
|
+
} else if (
|
|
451
|
+
req.url.searchParams.get("name") === "222.333.some-host.com"
|
|
452
|
+
) {
|
|
453
|
+
zone = [];
|
|
454
|
+
} else if (req.url.searchParams.get("name") === "333.some-host.com") {
|
|
455
|
+
zone = [{ id: "some-zone-id" }];
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return res(
|
|
459
|
+
ctx.status(200),
|
|
460
|
+
ctx.json({
|
|
461
|
+
success: true,
|
|
462
|
+
errors: [],
|
|
463
|
+
messages: [],
|
|
464
|
+
result: zone,
|
|
465
|
+
})
|
|
466
|
+
);
|
|
450
467
|
})
|
|
451
468
|
);
|
|
469
|
+
|
|
470
|
+
await runWrangler("dev --host 111.222.333.some-host.com");
|
|
471
|
+
|
|
472
|
+
const devMockCall = (Dev as jest.Mock).mock.calls[0][0];
|
|
473
|
+
|
|
474
|
+
expect(devMockCall).toHaveProperty("host", "111.222.333.some-host.com");
|
|
475
|
+
expect(devMockCall).toHaveProperty(
|
|
476
|
+
"localUpstream",
|
|
477
|
+
"111.222.333.some-host.com"
|
|
478
|
+
);
|
|
479
|
+
expect(devMockCall).toHaveProperty("zone", "some-zone-id");
|
|
452
480
|
});
|
|
453
481
|
|
|
454
482
|
it("should, in order, use args.host/config.dev.host/args.routes/(config.route|config.routes)", async () => {
|
|
@@ -1540,14 +1568,19 @@ describe("wrangler dev", () => {
|
|
|
1540
1568
|
});
|
|
1541
1569
|
|
|
1542
1570
|
function mockGetZones(domain: string, zones: { id: string }[] = []) {
|
|
1543
|
-
|
|
1544
|
-
"
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1571
|
+
msw.use(
|
|
1572
|
+
rest.get("*/zones", (req, res, ctx) => {
|
|
1573
|
+
expect([...req.url.searchParams.entries()]).toEqual([["name", domain]]);
|
|
1574
|
+
|
|
1575
|
+
return res(
|
|
1576
|
+
ctx.status(200),
|
|
1577
|
+
ctx.json({
|
|
1578
|
+
success: true,
|
|
1579
|
+
errors: [],
|
|
1580
|
+
messages: [],
|
|
1581
|
+
result: zones,
|
|
1582
|
+
})
|
|
1583
|
+
);
|
|
1584
|
+
})
|
|
1552
1585
|
);
|
|
1553
1586
|
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
4
|
-
import { mockConfirm
|
|
4
|
+
import { mockConfirm } from "./helpers/mock-dialogs";
|
|
5
|
+
import { useMockIsTTY } from "./helpers/mock-istty";
|
|
5
6
|
import { runInTempDir } from "./helpers/run-in-tmp";
|
|
6
7
|
import { runWrangler } from "./helpers/run-wrangler";
|
|
7
8
|
|
|
8
9
|
describe("generate", () => {
|
|
9
10
|
runInTempDir();
|
|
11
|
+
const { setIsTTY } = useMockIsTTY();
|
|
10
12
|
const std = mockConsoleMethods();
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
setIsTTY(true);
|
|
15
|
+
});
|
|
11
16
|
|
|
12
17
|
describe("cli functionality", () => {
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
clearConfirmMocks();
|
|
15
|
-
});
|
|
18
|
+
afterEach(() => {});
|
|
16
19
|
|
|
17
20
|
it("defers to `wrangler init` when no template is given", async () => {
|
|
18
21
|
mockConfirm(
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const ORIGINAL_WRANGLER_AUTH_DOMAIN = process.env.WRANGLER_AUTH_DOMAIN;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Mock the Auth URL domain so that we can control where we attempt to login.
|
|
5
|
+
*
|
|
6
|
+
* Note that you can remove any API token from the environment by setting the value to `null`.
|
|
7
|
+
* This is useful if a higher `describe()` block has already called `mockAuthDomain()`.
|
|
8
|
+
*/
|
|
9
|
+
export function mockAuthDomain({ domain }: { domain: string | null }) {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
if (domain === null) {
|
|
12
|
+
delete process.env.WRANGLER_AUTH_DOMAIN;
|
|
13
|
+
} else {
|
|
14
|
+
process.env.WRANGLER_AUTH_DOMAIN = domain;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
process.env.WRANGLER_AUTH_DOMAIN = ORIGINAL_WRANGLER_AUTH_DOMAIN;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
@@ -2,7 +2,7 @@ import { Readable } from "node:stream";
|
|
|
2
2
|
import { URL, URLSearchParams } from "node:url";
|
|
3
3
|
import { pathToRegexp } from "path-to-regexp";
|
|
4
4
|
import { Response } from "undici";
|
|
5
|
-
import { getCloudflareApiBaseUrl } from "../../
|
|
5
|
+
import { getCloudflareApiBaseUrl } from "../../environment-variables/misc-variables";
|
|
6
6
|
import type { FetchResult, FetchError } from "../../cfetch";
|
|
7
7
|
import type {
|
|
8
8
|
fetchInternal,
|
|
@@ -175,6 +175,7 @@ export function setMockResponse<ResponseType>(
|
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
177
|
* A helper to make it easier to create `FetchResult` objects in tests.
|
|
178
|
+
* TODO: Hijack this for MSW response objects. - JACOB
|
|
178
179
|
*/
|
|
179
180
|
export async function createFetchResult<ResponseType>(
|
|
180
181
|
result: ResponseType | Promise<ResponseType>,
|
|
@@ -219,31 +220,6 @@ const kvGetMocks = new Map<string, string | Buffer>();
|
|
|
219
220
|
const r2GetMocks = new Map<string, string | undefined>();
|
|
220
221
|
const dashScriptMocks = new Map<string, string | undefined>();
|
|
221
222
|
|
|
222
|
-
/**
|
|
223
|
-
* @mocked typeof fetchKVGetValue
|
|
224
|
-
*/
|
|
225
|
-
export function mockFetchKVGetValue(
|
|
226
|
-
accountId: string,
|
|
227
|
-
namespaceId: string,
|
|
228
|
-
key: string
|
|
229
|
-
) {
|
|
230
|
-
const mapKey = `${accountId}/${namespaceId}/${key}`;
|
|
231
|
-
if (kvGetMocks.has(mapKey)) {
|
|
232
|
-
const value = kvGetMocks.get(mapKey);
|
|
233
|
-
if (value !== undefined) return Promise.resolve(value);
|
|
234
|
-
}
|
|
235
|
-
throw new Error(`no mock value found for \`kv:key get\` - ${mapKey}`);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export function setMockFetchKVGetValue(
|
|
239
|
-
accountId: string,
|
|
240
|
-
namespaceId: string,
|
|
241
|
-
key: string,
|
|
242
|
-
value: string | Buffer
|
|
243
|
-
) {
|
|
244
|
-
kvGetMocks.set(`${accountId}/${namespaceId}/${key}`, value);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
223
|
/**
|
|
248
224
|
* @mocked typeof fetchR2Objects
|
|
249
225
|
*/
|
|
@@ -300,34 +276,3 @@ export function unsetSpecialMockFns() {
|
|
|
300
276
|
r2GetMocks.clear();
|
|
301
277
|
dashScriptMocks.clear();
|
|
302
278
|
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* @mocked typeof fetchDashScript
|
|
306
|
-
* multipart/form-data is the response for modules and raw text for the Script endpoint.
|
|
307
|
-
*/
|
|
308
|
-
export async function mockFetchDashScript(resource: string): Promise<string> {
|
|
309
|
-
if (dashScriptMocks.has(resource)) {
|
|
310
|
-
return dashScriptMocks.get(resource) ?? "";
|
|
311
|
-
}
|
|
312
|
-
throw new Error(`no mock found for \`init from-dash\` - ${resource}`);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Mock setter for usage within test blocks, companion helper to `mockFetchDashScript`
|
|
317
|
-
*/
|
|
318
|
-
export function setMockFetchDashScript({
|
|
319
|
-
accountId,
|
|
320
|
-
fromDashScriptName,
|
|
321
|
-
environment,
|
|
322
|
-
mockResponse,
|
|
323
|
-
}: {
|
|
324
|
-
accountId: string;
|
|
325
|
-
fromDashScriptName: string;
|
|
326
|
-
environment: string;
|
|
327
|
-
mockResponse?: string;
|
|
328
|
-
}) {
|
|
329
|
-
dashScriptMocks.set(
|
|
330
|
-
`/accounts/${accountId}/workers/services/${fromDashScriptName}/environments/${environment}/content`,
|
|
331
|
-
mockResponse
|
|
332
|
-
);
|
|
333
|
-
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { normalizeSlashes } from "./mock-console";
|
|
3
|
-
|
|
1
|
+
import prompts from "prompts";
|
|
4
2
|
/**
|
|
5
3
|
* The expected values for a confirmation request.
|
|
6
4
|
*/
|
|
7
5
|
export interface ConfirmExpectation {
|
|
8
6
|
/** The text expected to be seen in the confirmation dialog. */
|
|
9
7
|
text: string;
|
|
8
|
+
|
|
9
|
+
options?: { defaultValue: boolean };
|
|
10
10
|
/** The mock response send back from the confirmation dialog. */
|
|
11
11
|
result: boolean;
|
|
12
12
|
}
|
|
@@ -19,35 +19,21 @@ export interface ConfirmExpectation {
|
|
|
19
19
|
* then an error is thrown.
|
|
20
20
|
*/
|
|
21
21
|
export function mockConfirm(...expectations: ConfirmExpectation[]) {
|
|
22
|
-
(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
for (const expectation of expectations) {
|
|
23
|
+
(prompts as unknown as jest.Mock).mockImplementationOnce(
|
|
24
|
+
({ type, name, message, initial }) => {
|
|
25
|
+
expect({ type, name, message }).toStrictEqual({
|
|
26
|
+
type: "confirm",
|
|
27
|
+
name: "value",
|
|
28
|
+
message: expectation.text,
|
|
29
|
+
});
|
|
30
|
+
if (expectation.options) {
|
|
31
|
+
expect(initial).toStrictEqual(expectation.options?.defaultValue);
|
|
32
|
+
}
|
|
33
|
+
return Promise.resolve({ value: expectation.result });
|
|
27
34
|
}
|
|
28
|
-
}
|
|
29
|
-
throw new Error(`Unexpected confirmation message: ${text}`);
|
|
30
|
-
});
|
|
31
|
-
return () => {
|
|
32
|
-
if (expectations.length > 0) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
"The following expected confirmation dialogs were not used:\n" +
|
|
35
|
-
expectations.map((e) => `- "${e.text}"`).join("\n")
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function clearConfirmMocks() {
|
|
42
|
-
(confirm as jest.Mock).mockReset();
|
|
43
|
-
// Because confirm was originally a spy, calling mockReset will simply reset
|
|
44
|
-
// it as a function with no return value (!), so we need to accitionally reset
|
|
45
|
-
// the mock implementation to the one that throws (from jest.setup.js).
|
|
46
|
-
(confirm as jest.Mock).mockImplementation((text: string) => {
|
|
47
|
-
throw new Error(
|
|
48
|
-
`Unexpected call to \`confirm("${text}")\`.\nYou should use \`mockConfirm()\` to mock calls to \`confirm()\` with expectations. Search the codebase for \`mockConfirm\` to learn more.`
|
|
49
35
|
);
|
|
50
|
-
}
|
|
36
|
+
}
|
|
51
37
|
}
|
|
52
38
|
|
|
53
39
|
/**
|
|
@@ -57,7 +43,10 @@ export interface PromptExpectation {
|
|
|
57
43
|
/** The text expected to be seen in the prompt dialog. */
|
|
58
44
|
text: string;
|
|
59
45
|
/** The type of the prompt. */
|
|
60
|
-
|
|
46
|
+
options?: {
|
|
47
|
+
defaultValue?: string;
|
|
48
|
+
isSecret?: boolean;
|
|
49
|
+
};
|
|
61
50
|
/** The mock response send back from the prompt dialog. */
|
|
62
51
|
result: string;
|
|
63
52
|
}
|
|
@@ -70,45 +59,44 @@ export interface PromptExpectation {
|
|
|
70
59
|
* then an error is thrown.
|
|
71
60
|
*/
|
|
72
61
|
export function mockPrompt(...expectations: PromptExpectation[]) {
|
|
73
|
-
(
|
|
74
|
-
(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
62
|
+
for (const expectation of expectations) {
|
|
63
|
+
(prompts as unknown as jest.Mock).mockImplementationOnce(
|
|
64
|
+
({ type, name, message, initial, style }) => {
|
|
65
|
+
expect({ type, name, message }).toStrictEqual({
|
|
66
|
+
type: "text",
|
|
67
|
+
name: "value",
|
|
68
|
+
message: expectation.text,
|
|
69
|
+
});
|
|
70
|
+
if (expectation.options) {
|
|
71
|
+
expect(initial).toStrictEqual(expectation.options?.defaultValue);
|
|
72
|
+
expect(style).toStrictEqual(
|
|
73
|
+
expectation.options?.isSecret ? "password" : "default"
|
|
74
|
+
);
|
|
79
75
|
}
|
|
76
|
+
return Promise.resolve({ value: expectation.result });
|
|
80
77
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
);
|
|
84
|
-
return () => {
|
|
85
|
-
if (expectations.length > 0) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
"The following expected prompt dialogs were not used:\n" +
|
|
88
|
-
expectations.map((e) => `- "${e.text}"`).join("\n")
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
78
|
+
);
|
|
79
|
+
}
|
|
92
80
|
}
|
|
93
81
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// it as a function with no return value (!), so we need to accitionally reset
|
|
98
|
-
// the mock implementation to the one that throws (from jest.setup.js).
|
|
99
|
-
(prompt as jest.Mock).mockImplementation((text: string) => {
|
|
100
|
-
throw new Error(
|
|
101
|
-
`Unexpected call to \`prompt(${text}, ...)\`.\nYou should use \`mockPrompt()\` to mock calls to \`prompt()\` with expectations. Search the codebase for \`mockPrompt\` to learn more.`
|
|
102
|
-
);
|
|
103
|
-
});
|
|
82
|
+
interface SelectOptions<Values> {
|
|
83
|
+
choices: SelectOption<Values>[];
|
|
84
|
+
defaultOption?: number;
|
|
104
85
|
}
|
|
105
86
|
|
|
87
|
+
interface SelectOption<Values> {
|
|
88
|
+
title: string;
|
|
89
|
+
description?: string;
|
|
90
|
+
value: Values;
|
|
91
|
+
}
|
|
106
92
|
/**
|
|
107
93
|
* The expected values for a select request.
|
|
108
94
|
*/
|
|
109
|
-
export interface SelectExpectation {
|
|
95
|
+
export interface SelectExpectation<Values> {
|
|
110
96
|
/** The text expected to be seen in the select dialog. */
|
|
111
97
|
text: string;
|
|
98
|
+
|
|
99
|
+
options?: SelectOptions<Values>;
|
|
112
100
|
/** The mock response send back from the select dialog. */
|
|
113
101
|
result: string;
|
|
114
102
|
}
|
|
@@ -120,34 +108,30 @@ export interface SelectExpectation {
|
|
|
120
108
|
* If there is a call to `select()` that does not match any of the expectations
|
|
121
109
|
* then an error is thrown.
|
|
122
110
|
*/
|
|
123
|
-
export function mockSelect(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
111
|
+
export function mockSelect<Values>(
|
|
112
|
+
...expectations: SelectExpectation<Values>[]
|
|
113
|
+
) {
|
|
114
|
+
for (const expectation of expectations) {
|
|
115
|
+
(prompts as unknown as jest.Mock).mockImplementationOnce(
|
|
116
|
+
({ type, name, message, choices, initial }) => {
|
|
117
|
+
expect({ type, name, message }).toStrictEqual({
|
|
118
|
+
type: "select",
|
|
119
|
+
name: "value",
|
|
120
|
+
message: expectation.text,
|
|
121
|
+
});
|
|
122
|
+
if (expectation.options) {
|
|
123
|
+
expect(choices).toStrictEqual(expectation.options?.choices);
|
|
124
|
+
expect(initial).toStrictEqual(expectation.options?.defaultOption);
|
|
125
|
+
}
|
|
126
|
+
return Promise.resolve({ value: expectation.result });
|
|
129
127
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
});
|
|
133
|
-
return () => {
|
|
134
|
-
if (expectations.length > 0) {
|
|
135
|
-
throw new Error(
|
|
136
|
-
"The following expected select dialogs were not used:\n" +
|
|
137
|
-
expectations.map((e) => `- "${e.text}"`).join("\n")
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
128
|
+
);
|
|
129
|
+
}
|
|
141
130
|
}
|
|
142
131
|
|
|
143
|
-
export function
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
(select as jest.Mock).mockImplementation((text: string) => {
|
|
149
|
-
throw new Error(
|
|
150
|
-
`Unexpected call to \`select("${text}")\`.\nYou should use \`mockSelect()\` to mock calls to \`select()\` with expectations. Search the codebase for \`mockSelect\` to learn more.`
|
|
151
|
-
);
|
|
152
|
-
});
|
|
132
|
+
export function clearDialogs() {
|
|
133
|
+
// No dialog mocks should be left after each test, and so calling the dialog methods should throw
|
|
134
|
+
expect(() => prompts({ type: "select", name: "unknown" })).toThrow(
|
|
135
|
+
"Unexpected call to "
|
|
136
|
+
);
|
|
153
137
|
}
|