wrangler 0.0.0-eee5c78 → 0.0.0-ef9dac8
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 +61 -4
- package/package.json +5 -4
- package/src/__tests__/configuration.test.ts +61 -0
- package/src/__tests__/dev.test.tsx +156 -2
- package/src/__tests__/helpers/mock-cfetch.ts +2 -2
- package/src/__tests__/helpers/mock-console.ts +11 -1
- package/src/__tests__/helpers/mock-dialogs.ts +36 -13
- package/src/__tests__/helpers/mock-istty.ts +8 -3
- package/src/__tests__/helpers/mock-oauth-flow.ts +19 -24
- package/src/__tests__/helpers/mock-process.ts +39 -0
- package/src/__tests__/helpers/mock-stdin.ts +5 -0
- package/src/__tests__/index.test.ts +2 -1
- package/src/__tests__/init.test.ts +789 -434
- package/src/__tests__/jest.setup.ts +30 -0
- package/src/__tests__/kv.test.ts +148 -10
- package/src/__tests__/logger.test.ts +26 -0
- package/src/__tests__/pages.test.ts +514 -14
- package/src/__tests__/publish.test.ts +748 -150
- package/src/__tests__/secret.test.ts +30 -25
- package/src/__tests__/user.test.ts +1 -0
- package/src/bundle-reporter.tsx +29 -0
- package/src/cfetch/internal.ts +2 -2
- package/src/config/config.ts +9 -0
- package/src/config/validation.ts +32 -0
- package/src/config-cache.ts +0 -1
- package/src/dev/dev.tsx +38 -38
- package/src/dev/local.tsx +28 -19
- package/src/dev/remote.tsx +64 -19
- package/src/dev/use-esbuild.ts +1 -7
- package/src/dev.tsx +469 -0
- package/src/entry.ts +7 -1
- package/src/generate.ts +33 -0
- package/src/git-client.ts +42 -0
- package/src/index.tsx +79 -1090
- package/src/init.ts +549 -0
- package/src/kv.ts +2 -2
- package/src/logger.ts +8 -1
- package/src/open-in-browser.ts +1 -3
- package/src/pages/build.tsx +202 -0
- package/src/pages/constants.ts +7 -0
- package/src/pages/deployments.tsx +101 -0
- package/src/pages/dev.tsx +957 -0
- package/{pages → src/pages}/functions/buildPlugin.ts +1 -1
- package/{pages → src/pages}/functions/buildWorker.ts +1 -1
- package/{pages → src/pages}/functions/filepath-routing.test.ts +3 -3
- package/{pages → src/pages}/functions/filepath-routing.ts +2 -2
- package/{pages → src/pages}/functions/identifiers.ts +0 -0
- package/{pages → src/pages}/functions/routes.ts +1 -6
- package/src/pages/index.tsx +84 -0
- package/src/pages/projects.tsx +157 -0
- package/src/pages/publish.tsx +335 -0
- package/src/pages/types.ts +40 -0
- package/src/pages/upload.tsx +384 -0
- package/src/pages/utils.ts +12 -0
- package/src/parse.ts +19 -0
- package/src/preview.tsx +149 -0
- package/src/proxy.ts +7 -9
- package/src/publish.ts +28 -9
- package/src/sites.tsx +52 -6
- package/src/user/choose-account.tsx +60 -0
- package/src/user/env-vars.ts +17 -0
- package/src/user/generate-auth-url.ts +33 -0
- package/src/user/generate-random-state.ts +16 -0
- package/src/user/index.ts +3 -0
- package/src/{user.tsx → user/user.tsx} +54 -135
- package/src/zones.ts +11 -8
- package/templates/no-op-worker.js +10 -0
- package/{pages/functions/template-plugin.ts → templates/pages-template-plugin.ts} +9 -1
- package/{pages/functions/template-worker.ts → templates/pages-template-worker.ts} +26 -8
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +84632 -84250
- package/src/pages.tsx +0 -2093
package/bin/wrangler.js
CHANGED
|
@@ -9,7 +9,10 @@ const MIN_NODE_VERSION = "16.7.0";
|
|
|
9
9
|
|
|
10
10
|
let wranglerProcess;
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Executes ../wrangler-dist/cli.js
|
|
14
|
+
*/
|
|
15
|
+
function runWrangler() {
|
|
13
16
|
if (semiver(process.versions.node, MIN_NODE_VERSION) < 0) {
|
|
14
17
|
// Note Volta and nvm are also recommended in the official docs:
|
|
15
18
|
// https://developers.cloudflare.com/workers/get-started/guide#2-install-the-workers-cli
|
|
@@ -46,7 +49,7 @@ Consider using a Node.js version manager such as https://volta.sh/ or https://gi
|
|
|
46
49
|
pathToCACerts = certPath;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
return spawn(
|
|
50
53
|
process.execPath,
|
|
51
54
|
[
|
|
52
55
|
...(semiver(process.versions.node, "18.0.0") >= 0
|
|
@@ -70,11 +73,65 @@ Consider using a Node.js version manager such as https://volta.sh/ or https://gi
|
|
|
70
73
|
);
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Runs a locally-installed version of wrangler, delegating from this version.
|
|
78
|
+
* @throws {MODULE_NOT_FOUND} if there isn't a locally installed version of wrangler.
|
|
79
|
+
*/
|
|
80
|
+
function runDelegatedWrangler() {
|
|
81
|
+
const packageJsonPath = require.resolve("wrangler/package.json", {
|
|
82
|
+
paths: [process.cwd()],
|
|
83
|
+
});
|
|
84
|
+
const {
|
|
85
|
+
bin: { wrangler: binaryPath },
|
|
86
|
+
version,
|
|
87
|
+
} = JSON.parse(fs.readFileSync(packageJsonPath));
|
|
88
|
+
const resolvedBinaryPath = path.resolve(packageJsonPath, "..", binaryPath);
|
|
89
|
+
|
|
90
|
+
console.log(
|
|
91
|
+
`Delegating to locally-installed version of wrangler @ v${version}`
|
|
92
|
+
);
|
|
93
|
+
// this call to `spawn` is simpler because the delegated version will do all
|
|
94
|
+
// of the other work.
|
|
95
|
+
return spawn(
|
|
96
|
+
process.execPath,
|
|
97
|
+
[resolvedBinaryPath, ...process.argv.slice(2)],
|
|
98
|
+
{
|
|
99
|
+
stdio: "inherit",
|
|
100
|
+
}
|
|
101
|
+
).on("exit", (code) =>
|
|
102
|
+
process.exit(code === undefined || code === null ? 0 : code)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Indicates if this invocation of `wrangler` should delegate
|
|
108
|
+
* to a locally-installed version.
|
|
109
|
+
*/
|
|
110
|
+
function shouldDelegate() {
|
|
111
|
+
try {
|
|
112
|
+
// `require.resolve` will throw if it can't find
|
|
113
|
+
// a locally-installed version of `wrangler`
|
|
114
|
+
const delegatedPackageJson = require.resolve("wrangler/package.json", {
|
|
115
|
+
paths: [process.cwd()],
|
|
116
|
+
});
|
|
117
|
+
const thisPackageJson = path.resolve(__dirname, "..", "package.json");
|
|
118
|
+
// if it's the same path, then we're already a local install -- no need to delegate
|
|
119
|
+
return thisPackageJson !== delegatedPackageJson;
|
|
120
|
+
} catch (e) {
|
|
121
|
+
// there's no local version to delegate to -- `require.resolve` threw
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function main() {
|
|
127
|
+
wranglerProcess = shouldDelegate() ? runDelegatedWrangler() : runWrangler();
|
|
128
|
+
}
|
|
129
|
+
|
|
73
130
|
process.on("SIGINT", () => {
|
|
74
|
-
wranglerProcess
|
|
131
|
+
wranglerProcess?.kill();
|
|
75
132
|
});
|
|
76
133
|
process.on("SIGTERM", () => {
|
|
77
|
-
wranglerProcess
|
|
134
|
+
wranglerProcess?.kill();
|
|
78
135
|
});
|
|
79
136
|
|
|
80
137
|
void main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wrangler",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-ef9dac8",
|
|
4
4
|
"author": "wrangler@cloudflare.com",
|
|
5
5
|
"description": "Command-line interface for all things Cloudflare Workers",
|
|
6
6
|
"bin": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@esbuild-plugins/node-modules-polyfill": "^0.1.4",
|
|
42
42
|
"blake3-wasm": "^2.1.5",
|
|
43
43
|
"esbuild": "0.14.34",
|
|
44
|
-
"miniflare": "^2.5.
|
|
44
|
+
"miniflare": "^2.5.1",
|
|
45
45
|
"nanoid": "^3.3.3",
|
|
46
46
|
"path-to-regexp": "^6.2.0",
|
|
47
47
|
"selfsigned": "^2.0.1",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"clipboardy": "^3.0.0",
|
|
69
69
|
"cmd-shim": "^4.1.0",
|
|
70
70
|
"command-exists": "^1.2.9",
|
|
71
|
+
"concurrently": "^7.2.2",
|
|
71
72
|
"devtools-protocol": "^0.0.955664",
|
|
72
73
|
"dotenv": "^16.0.0",
|
|
73
74
|
"execa": "^6.1.0",
|
|
@@ -99,7 +100,7 @@
|
|
|
99
100
|
"timeago.js": "^4.0.2",
|
|
100
101
|
"tmp-promise": "^3.0.3",
|
|
101
102
|
"ts-dedent": "^2.2.0",
|
|
102
|
-
"undici": "^5.
|
|
103
|
+
"undici": "^5.5.1",
|
|
103
104
|
"update-check": "^1.5.4",
|
|
104
105
|
"ws": "^8.5.0",
|
|
105
106
|
"yargs": "^17.4.1"
|
|
@@ -107,7 +108,6 @@
|
|
|
107
108
|
"files": [
|
|
108
109
|
"src",
|
|
109
110
|
"bin",
|
|
110
|
-
"pages",
|
|
111
111
|
"miniflare-config-stubs",
|
|
112
112
|
"miniflare-dist",
|
|
113
113
|
"wrangler-dist",
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"check:type": "tsc",
|
|
123
123
|
"bundle": "node -r esbuild-register scripts/bundle.ts",
|
|
124
124
|
"build": "npm run clean && npm run bundle",
|
|
125
|
+
"dev": "npm run clean && concurrently -c black,blue 'npm run bundle -- --watch' 'npm run check:type -- --watch --preserveWatchOutput'",
|
|
125
126
|
"prepublishOnly": "SOURCEMAPS=false npm run build",
|
|
126
127
|
"start": "npm run bundle && NODE_OPTIONS=--enable-source-maps ./bin/wrangler.js",
|
|
127
128
|
"test": "jest --silent=false --verbose=true",
|
|
@@ -412,6 +412,67 @@ describe("normalizeAndValidateConfig()", () => {
|
|
|
412
412
|
});
|
|
413
413
|
});
|
|
414
414
|
|
|
415
|
+
describe("assets", () => {
|
|
416
|
+
it("should error if `assets` config is missing `bucket`", () => {
|
|
417
|
+
const expectedConfig: RawConfig = {
|
|
418
|
+
// @ts-expect-error we're intentionally passing an invalid configuration here
|
|
419
|
+
assets: {
|
|
420
|
+
include: ["INCLUDE_1", "INCLUDE_2"],
|
|
421
|
+
exclude: ["EXCLUDE_1", "EXCLUDE_2"],
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
const { config, diagnostics } = normalizeAndValidateConfig(
|
|
426
|
+
expectedConfig,
|
|
427
|
+
undefined,
|
|
428
|
+
{ env: undefined }
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
expect(config).toEqual(expect.objectContaining(expectedConfig));
|
|
432
|
+
expect(diagnostics.hasWarnings()).toBe(true);
|
|
433
|
+
expect(diagnostics.hasErrors()).toBe(true);
|
|
434
|
+
|
|
435
|
+
expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
|
|
436
|
+
"Processing wrangler configuration:
|
|
437
|
+
- \\"assets\\" fields are experimental and may change or break at any time."
|
|
438
|
+
`);
|
|
439
|
+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
|
|
440
|
+
"Processing wrangler configuration:
|
|
441
|
+
- \\"assets.bucket\\" is a required field."
|
|
442
|
+
`);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it("should error on invalid `assets` values", () => {
|
|
446
|
+
const expectedConfig = {
|
|
447
|
+
assets: {
|
|
448
|
+
bucket: "BUCKET",
|
|
449
|
+
include: [222, 333],
|
|
450
|
+
exclude: [444, 555],
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const { config, diagnostics } = normalizeAndValidateConfig(
|
|
455
|
+
expectedConfig as unknown as RawConfig,
|
|
456
|
+
undefined,
|
|
457
|
+
{ env: undefined }
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
expect(config).toEqual(expect.objectContaining(expectedConfig));
|
|
461
|
+
expect(diagnostics.hasWarnings()).toBe(true);
|
|
462
|
+
expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
|
|
463
|
+
"Processing wrangler configuration:
|
|
464
|
+
- \\"assets\\" fields are experimental and may change or break at any time."
|
|
465
|
+
`);
|
|
466
|
+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
|
|
467
|
+
"Processing wrangler configuration:
|
|
468
|
+
- Expected \\"assets.include.[0]\\" to be of type string but got 222.
|
|
469
|
+
- Expected \\"assets.include.[1]\\" to be of type string but got 333.
|
|
470
|
+
- Expected \\"assets.exclude.[0]\\" to be of type string but got 444.
|
|
471
|
+
- Expected \\"assets.exclude.[1]\\" to be of type string but got 555."
|
|
472
|
+
`);
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
415
476
|
it("should map `wasm_module` paths from relative to the config path to relative to the cwd", () => {
|
|
416
477
|
const expectedConfig: RawConfig = {
|
|
417
478
|
wasm_modules: {
|
|
@@ -403,6 +403,46 @@ describe("wrangler dev", () => {
|
|
|
403
403
|
});
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
+
describe("local upstream", () => {
|
|
407
|
+
it("should use dev.host from toml by default", async () => {
|
|
408
|
+
writeWranglerToml({
|
|
409
|
+
main: "index.js",
|
|
410
|
+
dev: {
|
|
411
|
+
host: `2.some-host.com`,
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
415
|
+
await runWrangler("dev --local");
|
|
416
|
+
expect((Dev as jest.Mock).mock.calls[0][0].localUpstream).toEqual(
|
|
417
|
+
"2.some-host.com"
|
|
418
|
+
);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it("should use route from toml by default", async () => {
|
|
422
|
+
writeWranglerToml({
|
|
423
|
+
main: "index.js",
|
|
424
|
+
route: "https://4.some-host.com/some/path/*",
|
|
425
|
+
});
|
|
426
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
427
|
+
await runWrangler("dev --local");
|
|
428
|
+
expect((Dev as jest.Mock).mock.calls[0][0].host).toEqual(
|
|
429
|
+
"4.some-host.com"
|
|
430
|
+
);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("should respect the option when provided", async () => {
|
|
434
|
+
writeWranglerToml({
|
|
435
|
+
main: "index.js",
|
|
436
|
+
route: `2.some-host.com`,
|
|
437
|
+
});
|
|
438
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
439
|
+
await runWrangler("dev --local-upstream some-host.com --local");
|
|
440
|
+
expect((Dev as jest.Mock).mock.calls[0][0].localUpstream).toEqual(
|
|
441
|
+
"some-host.com"
|
|
442
|
+
);
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
406
446
|
describe("custom builds", () => {
|
|
407
447
|
it("should run a custom build before starting `dev`", async () => {
|
|
408
448
|
writeWranglerToml({
|
|
@@ -799,7 +839,7 @@ describe("wrangler dev", () => {
|
|
|
799
839
|
});
|
|
800
840
|
});
|
|
801
841
|
|
|
802
|
-
describe("
|
|
842
|
+
describe("serve static assets", () => {
|
|
803
843
|
it("should error if --site is used with no value", async () => {
|
|
804
844
|
await expect(
|
|
805
845
|
runWrangler("dev --site")
|
|
@@ -839,7 +879,8 @@ describe("wrangler dev", () => {
|
|
|
839
879
|
--routes, --route Routes to upload [array]
|
|
840
880
|
--host Host to forward requests to, defaults to the zone of project [string]
|
|
841
881
|
--local-protocol Protocol to listen to requests on, defaults to http. [choices: \\"http\\", \\"https\\"]
|
|
842
|
-
--
|
|
882
|
+
--local-upstream Host to act as origin in local mode, defaults to dev.host or route [string]
|
|
883
|
+
--assets Static assets to be served [string]
|
|
843
884
|
--site Root folder of static assets for Workers Sites [string]
|
|
844
885
|
--site-include Array of .gitignore-style patterns that match file or directory names from the sites directory. Only matched items will be uploaded. [array]
|
|
845
886
|
--site-exclude Array of .gitignore-style patterns that match file or directory names from the sites directory. Matched items will not be uploaded. [array]
|
|
@@ -856,6 +897,119 @@ describe("wrangler dev", () => {
|
|
|
856
897
|
}
|
|
857
898
|
`);
|
|
858
899
|
});
|
|
900
|
+
|
|
901
|
+
it("should error if --assets and --site are used together", async () => {
|
|
902
|
+
writeWranglerToml({
|
|
903
|
+
main: "./index.js",
|
|
904
|
+
});
|
|
905
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
906
|
+
await expect(
|
|
907
|
+
runWrangler("dev --assets abc --site xyz")
|
|
908
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
909
|
+
`"Cannot use Assets and Workers Sites in the same Worker."`
|
|
910
|
+
);
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
it("should error if --assets and config.site are used together", async () => {
|
|
914
|
+
writeWranglerToml({
|
|
915
|
+
main: "./index.js",
|
|
916
|
+
site: {
|
|
917
|
+
bucket: "xyz",
|
|
918
|
+
},
|
|
919
|
+
});
|
|
920
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
921
|
+
await expect(
|
|
922
|
+
runWrangler("dev --assets abc")
|
|
923
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
924
|
+
`"Cannot use Assets and Workers Sites in the same Worker."`
|
|
925
|
+
);
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
it("should error if config.assets and --site are used together", async () => {
|
|
929
|
+
writeWranglerToml({
|
|
930
|
+
main: "./index.js",
|
|
931
|
+
assets: "abc",
|
|
932
|
+
});
|
|
933
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
934
|
+
await expect(
|
|
935
|
+
runWrangler("dev --site xyz")
|
|
936
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
937
|
+
`"Cannot use Assets and Workers Sites in the same Worker."`
|
|
938
|
+
);
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
it("should error if config.assets and config.site are used together", async () => {
|
|
942
|
+
writeWranglerToml({
|
|
943
|
+
main: "./index.js",
|
|
944
|
+
assets: "abc",
|
|
945
|
+
site: {
|
|
946
|
+
bucket: "xyz",
|
|
947
|
+
},
|
|
948
|
+
});
|
|
949
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
950
|
+
await expect(
|
|
951
|
+
runWrangler("dev --assets abc")
|
|
952
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
953
|
+
`"Cannot use Assets and Workers Sites in the same Worker."`
|
|
954
|
+
);
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
it("should indicate whether Sites is being used", async () => {
|
|
958
|
+
writeWranglerToml({
|
|
959
|
+
main: "index.js",
|
|
960
|
+
});
|
|
961
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
962
|
+
|
|
963
|
+
await runWrangler("dev");
|
|
964
|
+
expect((Dev as jest.Mock).mock.calls[0][0].isWorkersSite).toEqual(false);
|
|
965
|
+
|
|
966
|
+
await runWrangler("dev --site abc");
|
|
967
|
+
expect((Dev as jest.Mock).mock.calls[1][0].isWorkersSite).toEqual(true);
|
|
968
|
+
|
|
969
|
+
await runWrangler("dev --assets abc");
|
|
970
|
+
expect((Dev as jest.Mock).mock.calls[2][0].isWorkersSite).toEqual(false);
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
it("should warn if --assets is used", async () => {
|
|
974
|
+
writeWranglerToml({
|
|
975
|
+
main: "./index.js",
|
|
976
|
+
});
|
|
977
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
978
|
+
|
|
979
|
+
await runWrangler('dev --assets "./assets"');
|
|
980
|
+
expect(std).toMatchInlineSnapshot(`
|
|
981
|
+
Object {
|
|
982
|
+
"debug": "",
|
|
983
|
+
"err": "",
|
|
984
|
+
"out": "",
|
|
985
|
+
"warn": "[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mThe --assets argument is experimental and may change or break at any time[0m
|
|
986
|
+
|
|
987
|
+
",
|
|
988
|
+
}
|
|
989
|
+
`);
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
it("should warn if config.assets is used", async () => {
|
|
993
|
+
writeWranglerToml({
|
|
994
|
+
main: "./index.js",
|
|
995
|
+
assets: "./assets",
|
|
996
|
+
});
|
|
997
|
+
fs.writeFileSync("index.js", `export default {};`);
|
|
998
|
+
|
|
999
|
+
await runWrangler("dev");
|
|
1000
|
+
expect(std).toMatchInlineSnapshot(`
|
|
1001
|
+
Object {
|
|
1002
|
+
"debug": "",
|
|
1003
|
+
"err": "",
|
|
1004
|
+
"out": "",
|
|
1005
|
+
"warn": "[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mProcessing wrangler.toml configuration:[0m
|
|
1006
|
+
|
|
1007
|
+
- \\"assets\\" fields are experimental and may change or break at any time.
|
|
1008
|
+
|
|
1009
|
+
",
|
|
1010
|
+
}
|
|
1011
|
+
`);
|
|
1012
|
+
});
|
|
859
1013
|
});
|
|
860
1014
|
|
|
861
1015
|
describe("--inspect", () => {
|
|
@@ -179,7 +179,7 @@ export function unsetAllMocks() {
|
|
|
179
179
|
* special-case mocking it here.
|
|
180
180
|
*/
|
|
181
181
|
|
|
182
|
-
const kvGetMocks = new Map<string, string>();
|
|
182
|
+
const kvGetMocks = new Map<string, string | Buffer>();
|
|
183
183
|
|
|
184
184
|
/**
|
|
185
185
|
* @mocked typeof fetchKVGetValue
|
|
@@ -201,7 +201,7 @@ export function setMockFetchKVGetValue(
|
|
|
201
201
|
accountId: string,
|
|
202
202
|
namespaceId: string,
|
|
203
203
|
key: string,
|
|
204
|
-
value: string
|
|
204
|
+
value: string | Buffer
|
|
205
205
|
) {
|
|
206
206
|
kvGetMocks.set(`${accountId}/${namespaceId}/${key}`, value);
|
|
207
207
|
}
|
|
@@ -28,7 +28,9 @@ const std = {
|
|
|
28
28
|
|
|
29
29
|
function normalizeOutput(spy: jest.SpyInstance): string {
|
|
30
30
|
return normalizeErrorMarkers(
|
|
31
|
-
|
|
31
|
+
replaceByte(
|
|
32
|
+
stripTrailingWhitespace(normalizeSlashes(stripTimings(captureCalls(spy))))
|
|
33
|
+
)
|
|
32
34
|
);
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -85,3 +87,11 @@ export function stripTimings(stdout: string): string {
|
|
|
85
87
|
export function stripTrailingWhitespace(str: string): string {
|
|
86
88
|
return str.replace(/[^\S\n]+\n/g, "\n");
|
|
87
89
|
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Removing leading kilobit (tenth of a byte) from test output due to
|
|
93
|
+
* variation causing every few tests the value to change by ± .01
|
|
94
|
+
*/
|
|
95
|
+
function replaceByte(stdout: string): string {
|
|
96
|
+
return stdout.replaceAll(/.[0-9][0-9] KiB/g, "xx KiB");
|
|
97
|
+
}
|
|
@@ -20,13 +20,22 @@ export interface ConfirmExpectation {
|
|
|
20
20
|
*/
|
|
21
21
|
export function mockConfirm(...expectations: ConfirmExpectation[]) {
|
|
22
22
|
(confirm as jest.Mock).mockImplementation((text: string) => {
|
|
23
|
-
for (const
|
|
24
|
-
if (normalizeSlashes(text) === normalizeSlashes(
|
|
25
|
-
|
|
23
|
+
for (const expectation of expectations) {
|
|
24
|
+
if (normalizeSlashes(text) === normalizeSlashes(expectation.text)) {
|
|
25
|
+
expectations = expectations.filter((e) => e !== expectation);
|
|
26
|
+
return Promise.resolve(expectation.result);
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
throw new Error(`Unexpected confirmation message: ${text}`);
|
|
29
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
|
+
};
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
export function clearConfirmMocks() {
|
|
@@ -63,18 +72,23 @@ export interface PromptExpectation {
|
|
|
63
72
|
export function mockPrompt(...expectations: PromptExpectation[]) {
|
|
64
73
|
(prompt as jest.Mock).mockImplementation(
|
|
65
74
|
(text: string, type: "text" | "password") => {
|
|
66
|
-
for (const {
|
|
67
|
-
text
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
} of expectations) {
|
|
71
|
-
if (text === expectedText && type == expectedType) {
|
|
72
|
-
return Promise.resolve(result);
|
|
75
|
+
for (const expectation of expectations) {
|
|
76
|
+
if (text === expectation.text && type == expectation.type) {
|
|
77
|
+
expectations = expectations.filter((e) => e !== expectation);
|
|
78
|
+
return Promise.resolve(expectation.result);
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
throw new Error(`Unexpected confirmation message: ${text}`);
|
|
76
82
|
}
|
|
77
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
92
|
}
|
|
79
93
|
|
|
80
94
|
export function clearPromptMocks() {
|
|
@@ -108,13 +122,22 @@ export interface SelectExpectation {
|
|
|
108
122
|
*/
|
|
109
123
|
export function mockSelect(...expectations: SelectExpectation[]) {
|
|
110
124
|
(select as jest.Mock).mockImplementation((text: string) => {
|
|
111
|
-
for (const
|
|
112
|
-
if (normalizeSlashes(text) === normalizeSlashes(
|
|
113
|
-
|
|
125
|
+
for (const expectation of expectations) {
|
|
126
|
+
if (normalizeSlashes(text) === normalizeSlashes(expectation.text)) {
|
|
127
|
+
expectations = expectations.filter((e) => e !== expectation);
|
|
128
|
+
return Promise.resolve(expectation.result);
|
|
114
129
|
}
|
|
115
130
|
}
|
|
116
131
|
throw new Error(`Unexpected select message: ${text}`);
|
|
117
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
|
+
};
|
|
118
141
|
}
|
|
119
142
|
|
|
120
143
|
export function clearSelectMocks() {
|
|
@@ -8,9 +8,14 @@ export function useMockIsTTY() {
|
|
|
8
8
|
/**
|
|
9
9
|
* Explicitly set `process.stdout.isTTY` to a given value
|
|
10
10
|
*/
|
|
11
|
-
const setIsTTY = (isTTY: boolean) => {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const setIsTTY = (isTTY: boolean | { stdin: boolean; stdout: boolean }) => {
|
|
12
|
+
if (typeof isTTY === "boolean") {
|
|
13
|
+
process.stdout.isTTY = isTTY;
|
|
14
|
+
process.stdin.isTTY = isTTY;
|
|
15
|
+
} else {
|
|
16
|
+
process.stdin.isTTY = isTTY.stdin;
|
|
17
|
+
process.stdout.isTTY = isTTY.stdout;
|
|
18
|
+
}
|
|
14
19
|
};
|
|
15
20
|
|
|
16
21
|
beforeEach(() => {
|
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import fetchMock from "jest-fetch-mock";
|
|
2
2
|
import { Request } from "undici";
|
|
3
|
-
import { getCloudflareApiBaseUrl } from "../../cfetch";
|
|
4
3
|
import openInBrowser from "../../open-in-browser";
|
|
4
|
+
import {
|
|
5
|
+
createFetchResult,
|
|
6
|
+
setMockRawResponse,
|
|
7
|
+
setMockResponse,
|
|
8
|
+
} from "./mock-cfetch";
|
|
5
9
|
import { mockHttpServer } from "./mock-http-server";
|
|
6
10
|
|
|
11
|
+
export function mockGetMemberships(
|
|
12
|
+
accounts: { id: string; account: { id: string; name: string } }[]
|
|
13
|
+
) {
|
|
14
|
+
setMockResponse("/memberships", "GET", () => {
|
|
15
|
+
return accounts;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function mockGetMembershipsFail() {
|
|
20
|
+
setMockRawResponse("/memberships", () => {
|
|
21
|
+
return createFetchResult([], false);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
7
25
|
// the response to send when wrangler wants an oauth grant
|
|
8
26
|
let oauthGrantResponse: GrantResponseOptions | "timeout" = {};
|
|
9
27
|
|
|
@@ -86,28 +104,6 @@ export const mockOAuthFlow = () => {
|
|
|
86
104
|
return outcome;
|
|
87
105
|
};
|
|
88
106
|
|
|
89
|
-
const mockGetMemberships = (args: {
|
|
90
|
-
success: boolean;
|
|
91
|
-
result: { id: string; account: { id: string; name: string } }[];
|
|
92
|
-
}) => {
|
|
93
|
-
const outcome = {
|
|
94
|
-
actual: new Request("https://example.org"),
|
|
95
|
-
expected: new Request(`${getCloudflareApiBaseUrl()}/memberships`, {
|
|
96
|
-
method: "GET",
|
|
97
|
-
}),
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
fetchMock.mockIf(outcome.expected.url, async (req) => {
|
|
101
|
-
outcome.actual = req;
|
|
102
|
-
return {
|
|
103
|
-
status: 200,
|
|
104
|
-
body: JSON.stringify(args),
|
|
105
|
-
};
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
return outcome;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
107
|
const mockGrantAccessToken = ({
|
|
112
108
|
respondWith,
|
|
113
109
|
}: {
|
|
@@ -173,7 +169,6 @@ export const mockOAuthFlow = () => {
|
|
|
173
169
|
};
|
|
174
170
|
|
|
175
171
|
return {
|
|
176
|
-
mockGetMemberships,
|
|
177
172
|
mockGrantAccessToken,
|
|
178
173
|
mockGrantAuthorization,
|
|
179
174
|
mockOAuthServerCallback,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* We use this module to mock process methods (write only for now),
|
|
3
|
+
* and optionally assert on the values they're called with in our tests.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
let writeSpy: jest.SpyInstance;
|
|
7
|
+
|
|
8
|
+
function captureLastWriteCall(spy: jest.SpyInstance): Buffer {
|
|
9
|
+
const calls = spy.mock.calls;
|
|
10
|
+
if (calls.length > 1) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"Unexpected calls to `stdout.write()`: " + JSON.stringify(calls)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
const buffer = calls[0]?.[0] ?? Buffer.alloc(0);
|
|
16
|
+
if (buffer instanceof Buffer) {
|
|
17
|
+
return buffer;
|
|
18
|
+
} else {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Unexpected non-Buffer passed to \`stdout.write()\`: "${JSON.stringify(
|
|
21
|
+
buffer
|
|
22
|
+
)}"`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function mockProcess() {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
writeSpy = jest.spyOn(process.stdout, "write").mockImplementation();
|
|
30
|
+
});
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
writeSpy.mockRestore();
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
get write() {
|
|
36
|
+
return captureLastWriteCall(writeSpy);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|