wrangler 2.0.2 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,7 @@ import {
12
12
  unsetMockFetchKVGetValues,
13
13
  } from "./helpers/mock-cfetch";
14
14
  import { mockConsoleMethods, normalizeSlashes } from "./helpers/mock-console";
15
+ import { mockConfirm } from "./helpers/mock-dialogs";
15
16
  import { useMockIsTTY } from "./helpers/mock-istty";
16
17
  import { mockKeyListRequest } from "./helpers/mock-kv";
17
18
  import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
@@ -645,6 +646,136 @@ describe("publish", () => {
645
646
  await runWrangler("publish ./index --env dev --legacy-env false");
646
647
  });
647
648
 
649
+ describe("custom domains", () => {
650
+ it("should publish routes marked with 'custom_domain' as seperate custom domains", async () => {
651
+ writeWranglerToml({
652
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
653
+ });
654
+ writeWorkerSource();
655
+ mockUpdateWorkerRequest({ enabled: false });
656
+ mockUploadWorkerRequest({ expectedType: "esm" });
657
+ mockPublishCustomDomainsRequest({
658
+ publishFlags: {
659
+ override_scope: true,
660
+ override_existing_origin: false,
661
+ override_existing_dns_record: false,
662
+ },
663
+ domains: [{ hostname: "api.example.com" }],
664
+ });
665
+ await runWrangler("publish ./index");
666
+ expect(std.out).toContain("api.example.com (custom domain)");
667
+ });
668
+
669
+ it("should allow retrying if publish fails with a conflicting custom domain error", async () => {
670
+ writeWranglerToml({
671
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
672
+ });
673
+ writeWorkerSource();
674
+ mockUpdateWorkerRequest({ enabled: false });
675
+ mockUploadWorkerRequest({ expectedType: "esm" });
676
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
677
+ originConflicts: true,
678
+ domains: [{ hostname: "api.example.com" }],
679
+ });
680
+ mockConfirm({
681
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
682
+ result: true,
683
+ });
684
+ await runWrangler("publish ./index");
685
+ expect(std.out).toContain("api.example.com (custom domain)");
686
+ });
687
+
688
+ it("should allow retrying if publish fails with a conflicting DNS record error", async () => {
689
+ writeWranglerToml({
690
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
691
+ });
692
+ writeWorkerSource();
693
+ mockUpdateWorkerRequest({ enabled: false });
694
+ mockUploadWorkerRequest({ expectedType: "esm" });
695
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
696
+ dnsRecordConflicts: true,
697
+ domains: [{ hostname: "api.example.com" }],
698
+ });
699
+ mockConfirm({
700
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
701
+ result: true,
702
+ });
703
+ await runWrangler("publish ./index");
704
+ expect(std.out).toContain("api.example.com (custom domain)");
705
+ });
706
+
707
+ it("should allow retrying for conflicting custom domains and then again for conflicting dns", async () => {
708
+ writeWranglerToml({
709
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
710
+ });
711
+ writeWorkerSource();
712
+ mockUpdateWorkerRequest({ enabled: false });
713
+ mockUploadWorkerRequest({ expectedType: "esm" });
714
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
715
+ originConflicts: true,
716
+ dnsRecordConflicts: true,
717
+ domains: [{ hostname: "api.example.com" }],
718
+ });
719
+ mockConfirm(
720
+ {
721
+ text: `Custom Domains already exist for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
722
+ result: true,
723
+ },
724
+ {
725
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
726
+ result: true,
727
+ }
728
+ );
729
+ await runWrangler("publish ./index");
730
+ expect(std.out).toContain("api.example.com (custom domain)");
731
+ });
732
+
733
+ it("should throw if an invalid custom domain is requested", async () => {
734
+ writeWranglerToml({
735
+ routes: [{ pattern: "*.example.com", custom_domain: true }],
736
+ });
737
+ writeWorkerSource();
738
+ await expect(
739
+ runWrangler("publish ./index")
740
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
741
+ `"Cannot use \\"*.example.com\\" as a Custom Domain; wildcard operators (*) are not allowed"`
742
+ );
743
+
744
+ writeWranglerToml({
745
+ routes: [
746
+ { pattern: "api.example.com/at/a/path", custom_domain: true },
747
+ ],
748
+ });
749
+ writeWorkerSource();
750
+ await expect(
751
+ runWrangler("publish ./index")
752
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
753
+ `"Cannot use \\"api.example.com/at/a/path\\" as a Custom Domain; paths are not allowed"`
754
+ );
755
+ });
756
+
757
+ it("should not retry publish on error if user does not confirm", async () => {
758
+ writeWranglerToml({
759
+ routes: [{ pattern: "api.example.com", custom_domain: true }],
760
+ });
761
+ writeWorkerSource();
762
+ mockUpdateWorkerRequest({ enabled: false });
763
+ mockUploadWorkerRequest({ expectedType: "esm" });
764
+ mockPublishCustomDomainsRequestConflictWithoutOverride({
765
+ dnsRecordConflicts: true,
766
+ domains: [{ hostname: "api.example.com" }],
767
+ });
768
+ mockConfirm({
769
+ text: `You already have conflicting DNS records for these domains: "api.example.com"\nUpdate them to point to this script instead?`,
770
+ result: false,
771
+ });
772
+ await runWrangler("publish ./index");
773
+ expect(std.out).toContain(
774
+ 'Publishing to Custom Domain "api.example.com" was skipped, fix conflict and try again'
775
+ );
776
+ });
777
+ });
778
+
648
779
  it.todo("should error if it's a workers.dev route");
649
780
  });
650
781
 
@@ -906,6 +1037,7 @@ export default {};`
906
1037
  "default",
907
1038
  ]
908
1039
  `);
1040
+
909
1041
  expect(std).toMatchInlineSnapshot(`
910
1042
  Object {
911
1043
  "debug": "",
@@ -926,7 +1058,7 @@ export const def = "show me the money";
926
1058
  addEventListener('fetch', event => {});`
927
1059
  );
928
1060
 
929
- await runWrangler("publish index.js --dry-run --outdir out --minify");
1061
+ await runWrangler("publish index.js --dry-run --outdir out");
930
1062
 
931
1063
  expect(
932
1064
  (
@@ -2548,18 +2680,66 @@ addEventListener('fetch', event => {});`
2548
2680
  },
2549
2681
  });
2550
2682
 
2551
- await expect(
2552
- runWrangler("publish index.js")
2553
- ).rejects.toThrowErrorMatchingInlineSnapshot(
2554
- `"Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\""`
2555
- );
2683
+ await expect(runWrangler("publish index.js")).rejects
2684
+ .toThrowErrorMatchingInlineSnapshot(`
2685
+ "The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2686
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build."
2687
+ `);
2556
2688
  expect(std.out).toMatchInlineSnapshot(`
2557
2689
  "Running custom build: node -e \\"console.log('custom build');\\"
2558
2690
 
2559
2691
  If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2560
2692
  `);
2561
2693
  expect(std.err).toMatchInlineSnapshot(`
2562
- "X [ERROR] Could not resolve \\"index.js\\" after running custom build: node -e \\"console.log('custom build');\\"
2694
+ "X [ERROR] The expected output file at \\"index.js\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2695
+
2696
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
2697
+
2698
+ "
2699
+ `);
2700
+ expect(std.warn).toMatchInlineSnapshot(`""`);
2701
+ });
2702
+
2703
+ it("should throw an error if the entry is a directory after the build finishes", async () => {
2704
+ writeWranglerToml({
2705
+ main: "./",
2706
+ build: {
2707
+ command: `node -e "console.log('custom build');"`,
2708
+ },
2709
+ });
2710
+
2711
+ fs.writeFileSync("./worker.js", "some content", "utf-8");
2712
+ fs.mkdirSync("./dist");
2713
+ fs.writeFileSync("./dist/index.ts", "some content", "utf-8");
2714
+
2715
+ await expect(runWrangler("publish")).rejects
2716
+ .toThrowErrorMatchingInlineSnapshot(`
2717
+ "The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2718
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
2719
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
2720
+
2721
+ Did you mean to set the main field to one of:
2722
+ \`\`\`
2723
+ main = \\"./worker.js\\"
2724
+ main = \\"./dist/index.ts\\"
2725
+ \`\`\`"
2726
+ `);
2727
+ expect(std.out).toMatchInlineSnapshot(`
2728
+ "Running custom build: node -e \\"console.log('custom build');\\"
2729
+
2730
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new."
2731
+ `);
2732
+ expect(std.err).toMatchInlineSnapshot(`
2733
+ "X [ERROR] The expected output file at \\".\\" was not found after running custom build: node -e \\"console.log('custom build');\\".
2734
+
2735
+ The \`main\` property in wrangler.toml should point to the file generated by the custom build.
2736
+ The provided entry-point path, \\".\\", points to a directory, rather than a file.
2737
+
2738
+ Did you mean to set the main field to one of:
2739
+ \`\`\`
2740
+ main = \\"./worker.js\\"
2741
+ main = \\"./dist/index.ts\\"
2742
+ \`\`\`
2563
2743
 
2564
2744
  "
2565
2745
  `);
@@ -3057,6 +3237,7 @@ addEventListener('fetch', event => {});`
3057
3237
  name: "DURABLE_OBJECT_TWO",
3058
3238
  class_name: "AnotherDurableObject",
3059
3239
  script_name: "another-durable-object-worker",
3240
+ environment: "staging",
3060
3241
  },
3061
3242
  ],
3062
3243
  },
@@ -3115,6 +3296,12 @@ addEventListener('fetch', event => {});`
3115
3296
  mockUploadWorkerRequest({
3116
3297
  expectedType: "sw",
3117
3298
  expectedBindings: [
3299
+ { json: 123, name: "ENV_VAR_ONE", type: "json" },
3300
+ {
3301
+ name: "ENV_VAR_TWO",
3302
+ text: "Hello, I'm an environment variable",
3303
+ type: "plain_text",
3304
+ },
3118
3305
  {
3119
3306
  name: "KV_NAMESPACE_ONE",
3120
3307
  namespace_id: "kv-ns-one-id",
@@ -3133,6 +3320,7 @@ addEventListener('fetch', event => {});`
3133
3320
  },
3134
3321
  {
3135
3322
  class_name: "AnotherDurableObject",
3323
+ environment: "staging",
3136
3324
  name: "DURABLE_OBJECT_TWO",
3137
3325
  script_name: "another-durable-object-worker",
3138
3326
  type: "durable_object_namespace",
@@ -3147,12 +3335,6 @@ addEventListener('fetch', event => {});`
3147
3335
  name: "R2_BUCKET_TWO",
3148
3336
  type: "r2_bucket",
3149
3337
  },
3150
- { json: 123, name: "ENV_VAR_ONE", type: "json" },
3151
- {
3152
- name: "ENV_VAR_TWO",
3153
- text: "Hello, I'm an environment variable",
3154
- type: "plain_text",
3155
- },
3156
3338
  {
3157
3339
  name: "WASM_MODULE_ONE",
3158
3340
  part: "WASM_MODULE_ONE",
@@ -4074,6 +4256,47 @@ addEventListener('fetch', event => {});`
4074
4256
  });
4075
4257
  });
4076
4258
 
4259
+ describe("[services]", () => {
4260
+ it("should support service bindings", async () => {
4261
+ writeWranglerToml({
4262
+ services: [
4263
+ {
4264
+ binding: "FOO",
4265
+ service: "foo-service",
4266
+ environment: "production",
4267
+ },
4268
+ ],
4269
+ });
4270
+ writeWorkerSource();
4271
+ mockSubDomainRequest();
4272
+ mockUploadWorkerRequest({
4273
+ expectedBindings: [
4274
+ {
4275
+ type: "service",
4276
+ name: "FOO",
4277
+ service: "foo-service",
4278
+ environment: "production",
4279
+ },
4280
+ ],
4281
+ });
4282
+
4283
+ await runWrangler("publish index.js");
4284
+ expect(std.out).toMatchInlineSnapshot(`
4285
+ "Uploaded test-name (TIMINGS)
4286
+ Published test-name (TIMINGS)
4287
+ test-name.test-sub-domain.workers.dev"
4288
+ `);
4289
+ expect(std.err).toMatchInlineSnapshot(`""`);
4290
+ expect(std.warn).toMatchInlineSnapshot(`
4291
+ "▲ [WARNING] Processing wrangler.toml configuration:
4292
+
4293
+ - \\"services\\" fields are experimental and may change or break at any time.
4294
+
4295
+ "
4296
+ `);
4297
+ });
4298
+ });
4299
+
4077
4300
  describe("[unsafe]", () => {
4078
4301
  it("should warn if using unsafe bindings", async () => {
4079
4302
  writeWranglerToml({
@@ -4576,8 +4799,16 @@ addEventListener('fetch', event => {});`
4576
4799
 
4577
4800
  describe("--dry-run", () => {
4578
4801
  it("should not publish the worker if --dry-run is specified", async () => {
4579
- writeWranglerToml();
4802
+ writeWranglerToml({
4803
+ // add a durable object with migrations
4804
+ // to make sure we _don't_ fetch migration status
4805
+ durable_objects: {
4806
+ bindings: [{ name: "NAME", class_name: "SomeClass" }],
4807
+ },
4808
+ migrations: [{ tag: "v1", new_classes: ["SomeClass"] }],
4809
+ });
4580
4810
  writeWorkerSource();
4811
+ process.env.CLOUDFLARE_ACCOUNT_ID = "";
4581
4812
  await runWrangler("publish index.js --dry-run");
4582
4813
  expect(std).toMatchInlineSnapshot(`
4583
4814
  Object {
@@ -4607,6 +4838,27 @@ addEventListener('fetch', event => {});`
4607
4838
  `);
4608
4839
  });
4609
4840
 
4841
+ it("should recommend node compatibility mode when using node builtins and node-compat isn't enabled", async () => {
4842
+ writeWranglerToml();
4843
+ fs.writeFileSync(
4844
+ "index.js",
4845
+ `
4846
+ import path from 'path';
4847
+ console.log(path.join("some/path/to", "a/file.txt"));
4848
+ export default {}
4849
+ `
4850
+ );
4851
+ let err: Error | undefined;
4852
+ try {
4853
+ await runWrangler("publish index.js --dry-run"); // expecting this to throw, as node compatibility isn't enabled
4854
+ } catch (e) {
4855
+ err = e as Error;
4856
+ }
4857
+ expect(err?.message).toMatch(
4858
+ `Detected a Node builtin module import while Node compatibility is disabled.\nAdd node_compat = true to your wrangler.toml file to enable Node compatibility.`
4859
+ );
4860
+ });
4861
+
4610
4862
  it("should polyfill node builtins when enabled", async () => {
4611
4863
  writeWranglerToml();
4612
4864
  fs.writeFileSync(
@@ -4801,6 +5053,102 @@ function mockPublishRoutesRequest({
4801
5053
  );
4802
5054
  }
4803
5055
 
5056
+ function mockPublishCustomDomainsRequest({
5057
+ publishFlags,
5058
+ domains = [],
5059
+ env = undefined,
5060
+ legacyEnv = false,
5061
+ }: {
5062
+ publishFlags: {
5063
+ override_scope: boolean;
5064
+ override_existing_origin: boolean;
5065
+ override_existing_dns_record: boolean;
5066
+ };
5067
+ domains: Array<
5068
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5069
+ >;
5070
+ env?: string | undefined;
5071
+ legacyEnv?: boolean | undefined;
5072
+ }) {
5073
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5074
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5075
+
5076
+ setMockResponse(
5077
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5078
+ "PUT",
5079
+ ([_url, accountId, scriptName, envName], { body }) => {
5080
+ expect(accountId).toEqual("some-account-id");
5081
+ expect(scriptName).toEqual(
5082
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5083
+ );
5084
+ if (!legacyEnv) {
5085
+ expect(envName).toEqual(env);
5086
+ }
5087
+
5088
+ expect(JSON.parse(body as string)).toEqual({
5089
+ ...publishFlags,
5090
+ origins: domains,
5091
+ });
5092
+
5093
+ return null;
5094
+ }
5095
+ );
5096
+ }
5097
+
5098
+ function mockPublishCustomDomainsRequestConflictWithoutOverride({
5099
+ domains = [],
5100
+ originConflicts = false,
5101
+ dnsRecordConflicts = false,
5102
+ env = undefined,
5103
+ legacyEnv = false,
5104
+ }: {
5105
+ originConflicts?: boolean;
5106
+ dnsRecordConflicts?: boolean;
5107
+ domains: Array<
5108
+ { hostname: string } & ({ zone_id?: string } | { zone_name?: string })
5109
+ >;
5110
+ env?: string | undefined;
5111
+ legacyEnv?: boolean | undefined;
5112
+ }) {
5113
+ const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
5114
+ const environment = env && !legacyEnv ? "/environments/:envName" : "";
5115
+
5116
+ setMockRawResponse(
5117
+ `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/domains`,
5118
+ "PUT",
5119
+ ([_url, accountId, scriptName, envName], { body }) => {
5120
+ expect(accountId).toEqual("some-account-id");
5121
+ expect(scriptName).toEqual(
5122
+ legacyEnv && env ? `test-name-${env}` : "test-name"
5123
+ );
5124
+ if (!legacyEnv) {
5125
+ expect(envName).toEqual(env);
5126
+ }
5127
+
5128
+ const parsed = JSON.parse(body as string);
5129
+ expect(parsed.origins).toEqual(domains);
5130
+
5131
+ if (originConflicts && !parsed.override_existing_origin) {
5132
+ return createFetchResult(null, false, [
5133
+ {
5134
+ code: 100116,
5135
+ message: `Cannot create Custom Domain "${domains[0].hostname}": Custom Domain already exists and points to a different script; retry and use option "override_existing_origin" to override`,
5136
+ },
5137
+ ]);
5138
+ }
5139
+ if (dnsRecordConflicts && !parsed.override_existing_dns_record) {
5140
+ return createFetchResult(null, false, [
5141
+ {
5142
+ code: 100117,
5143
+ message: `Cannot create Custom Domain "${domains[0].hostname}": a DNS record already exists for this origin; retry and use option "override_existing_dns_record" to override`,
5144
+ },
5145
+ ]);
5146
+ }
5147
+ return createFetchResult(null, true);
5148
+ }
5149
+ );
5150
+ }
5151
+
4804
5152
  /** Create a mock handler for the request to get a list of all KV namespaces. */
4805
5153
  function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
4806
5154
  setMockResponse(
@@ -17,6 +17,33 @@ describe("wrangler", () => {
17
17
 
18
18
  describe("r2", () => {
19
19
  describe("bucket", () => {
20
+ it("should show the correct help when an invalid command is passed", async () => {
21
+ await expect(() =>
22
+ runWrangler("r2 bucket foo")
23
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown argument: foo"`);
24
+ expect(std.err).toMatchInlineSnapshot(`
25
+ "X [ERROR] Unknown argument: foo
26
+
27
+ "
28
+ `);
29
+ expect(std.out).toMatchInlineSnapshot(`
30
+ "
31
+ wrangler r2 bucket
32
+
33
+ Manage R2 buckets
34
+
35
+ Commands:
36
+ wrangler r2 bucket create <name> Create a new R2 bucket
37
+ wrangler r2 bucket list List R2 buckets
38
+ wrangler r2 bucket delete <name> Delete an R2 bucket
39
+
40
+ Flags:
41
+ -c, --config Path to .toml configuration file [string]
42
+ -h, --help Show help [boolean]
43
+ -v, --version Show version number [boolean]"
44
+ `);
45
+ });
46
+
20
47
  describe("list", () => {
21
48
  function mockListRequest(buckets: R2BucketInfo[]) {
22
49
  const requests = { count: 0 };
@@ -69,10 +96,7 @@ describe("wrangler", () => {
69
96
  );
70
97
  expect(std.out).toMatchInlineSnapshot(`
71
98
  "
72
- "
73
- `);
74
- expect(std.err).toMatchInlineSnapshot(`
75
- "wrangler r2 bucket create <name>
99
+ wrangler r2 bucket create <name>
76
100
 
77
101
  Create a new R2 bucket
78
102
 
@@ -80,11 +104,12 @@ describe("wrangler", () => {
80
104
  name The name of the new bucket [string] [required]
81
105
 
82
106
  Flags:
83
- -c, --config Path to .toml configuration file [string]
84
- -h, --help Show help [boolean]
85
- -v, --version Show version number [boolean]
86
- --legacy-env Use legacy environments [boolean]
87
- X [ERROR] Not enough non-option arguments: got 0, need at least 1
107
+ -c, --config Path to .toml configuration file [string]
108
+ -h, --help Show help [boolean]
109
+ -v, --version Show version number [boolean]"
110
+ `);
111
+ expect(std.err).toMatchInlineSnapshot(`
112
+ "X [ERROR] Not enough non-option arguments: got 0, need at least 1
88
113
 
89
114
  "
90
115
  `);
@@ -98,10 +123,7 @@ describe("wrangler", () => {
98
123
  );
99
124
  expect(std.out).toMatchInlineSnapshot(`
100
125
  "
101
- "
102
- `);
103
- expect(std.err).toMatchInlineSnapshot(`
104
- "wrangler r2 bucket create <name>
126
+ wrangler r2 bucket create <name>
105
127
 
106
128
  Create a new R2 bucket
107
129
 
@@ -109,11 +131,12 @@ describe("wrangler", () => {
109
131
  name The name of the new bucket [string] [required]
110
132
 
111
133
  Flags:
112
- -c, --config Path to .toml configuration file [string]
113
- -h, --help Show help [boolean]
114
- -v, --version Show version number [boolean]
115
- --legacy-env Use legacy environments [boolean]
116
- X [ERROR] Unknown arguments: def, ghi
134
+ -c, --config Path to .toml configuration file [string]
135
+ -h, --help Show help [boolean]
136
+ -v, --version Show version number [boolean]"
137
+ `);
138
+ expect(std.err).toMatchInlineSnapshot(`
139
+ "X [ERROR] Unknown arguments: def, ghi
117
140
 
118
141
  "
119
142
  `);
@@ -153,10 +176,7 @@ describe("wrangler", () => {
153
176
  );
154
177
  expect(std.out).toMatchInlineSnapshot(`
155
178
  "
156
- "
157
- `);
158
- expect(std.err).toMatchInlineSnapshot(`
159
- "wrangler r2 bucket delete <name>
179
+ wrangler r2 bucket delete <name>
160
180
 
161
181
  Delete an R2 bucket
162
182
 
@@ -164,11 +184,12 @@ describe("wrangler", () => {
164
184
  name The name of the bucket to delete [string] [required]
165
185
 
166
186
  Flags:
167
- -c, --config Path to .toml configuration file [string]
168
- -h, --help Show help [boolean]
169
- -v, --version Show version number [boolean]
170
- --legacy-env Use legacy environments [boolean]
171
- X [ERROR] Not enough non-option arguments: got 0, need at least 1
187
+ -c, --config Path to .toml configuration file [string]
188
+ -h, --help Show help [boolean]
189
+ -v, --version Show version number [boolean]"
190
+ `);
191
+ expect(std.err).toMatchInlineSnapshot(`
192
+ "X [ERROR] Not enough non-option arguments: got 0, need at least 1
172
193
 
173
194
  "
174
195
  `);
@@ -182,10 +203,7 @@ describe("wrangler", () => {
182
203
  );
183
204
  expect(std.out).toMatchInlineSnapshot(`
184
205
  "
185
- "
186
- `);
187
- expect(std.err).toMatchInlineSnapshot(`
188
- "wrangler r2 bucket delete <name>
206
+ wrangler r2 bucket delete <name>
189
207
 
190
208
  Delete an R2 bucket
191
209
 
@@ -193,11 +211,12 @@ describe("wrangler", () => {
193
211
  name The name of the bucket to delete [string] [required]
194
212
 
195
213
  Flags:
196
- -c, --config Path to .toml configuration file [string]
197
- -h, --help Show help [boolean]
198
- -v, --version Show version number [boolean]
199
- --legacy-env Use legacy environments [boolean]
200
- X [ERROR] Unknown arguments: def, ghi
214
+ -c, --config Path to .toml configuration file [string]
215
+ -h, --help Show help [boolean]
216
+ -v, --version Show version number [boolean]"
217
+ `);
218
+ expect(std.err).toMatchInlineSnapshot(`
219
+ "X [ERROR] Unknown arguments: def, ghi
201
220
 
202
221
  "
203
222
  `);
@@ -60,6 +60,22 @@ describe("wrangler secret", () => {
60
60
  describe("interactive", () => {
61
61
  useMockStdin({ isTTY: true });
62
62
 
63
+ it("should trim stdin secret value", async () => {
64
+ mockPrompt({
65
+ text: "Enter a secret value:",
66
+ type: "password",
67
+ result: `hunter2
68
+ `,
69
+ });
70
+
71
+ mockPutRequest({ name: `secret-name`, text: `hunter2` });
72
+ await runWrangler("secret put secret-name --name script-name");
73
+ expect(std.out).toMatchInlineSnapshot(`
74
+ "🌀 Creating the secret for script script-name
75
+ ✨ Success! Uploaded secret secret-name"
76
+ `);
77
+ });
78
+
63
79
  it("should create a secret", async () => {
64
80
  mockPrompt({
65
81
  text: "Enter a secret value:",
@@ -146,6 +162,25 @@ describe("wrangler secret", () => {
146
162
  describe("non-interactive", () => {
147
163
  const mockStdIn = useMockStdin({ isTTY: false });
148
164
 
165
+ it("should trim stdin secret value, from piped input", async () => {
166
+ mockPutRequest({ name: "the-key", text: "the-secret" });
167
+ // Pipe the secret in as three chunks to test that we reconstitute it correctly.
168
+ mockStdIn.send(
169
+ `the`,
170
+ `-`,
171
+ `secret
172
+ ` // whitespace & newline being removed
173
+ );
174
+ await runWrangler("secret put the-key --name script-name");
175
+
176
+ expect(std.out).toMatchInlineSnapshot(`
177
+ "🌀 Creating the secret for script script-name
178
+ ✨ Success! Uploaded secret the-key"
179
+ `);
180
+ expect(std.warn).toMatchInlineSnapshot(`""`);
181
+ expect(std.err).toMatchInlineSnapshot(`""`);
182
+ });
183
+
149
184
  it("should create a secret, from piped input", async () => {
150
185
  mockPutRequest({ name: "the-key", text: "the-secret" });
151
186
  // Pipe the secret in as three chunks to test that we reconstitute it correctly.