1
1
import { http , HttpResponse } from "msw" ;
2
2
import { mockAccountId , mockApiToken } from "./helpers/mock-account-id" ;
3
3
import { mockConsoleMethods } from "./helpers/mock-console" ;
4
- import { clearDialogs , mockPrompt , mockSelect } from "./helpers/mock-dialogs" ;
4
+ import {
5
+ clearDialogs ,
6
+ mockConfirm ,
7
+ mockPrompt ,
8
+ mockSelect ,
9
+ } from "./helpers/mock-dialogs" ;
5
10
import { useMockIsTTY } from "./helpers/mock-istty" ;
6
11
import {
7
12
mockCreateKVNamespace ,
@@ -19,6 +24,7 @@ import { runInTempDir } from "./helpers/run-in-tmp";
19
24
import { runWrangler } from "./helpers/run-wrangler" ;
20
25
import { writeWorkerSource } from "./helpers/write-worker-source" ;
21
26
import { writeWranglerConfig } from "./helpers/write-wrangler-config" ;
27
+ import type { DatabaseInfo } from "../d1/types" ;
22
28
import type { Settings } from "../deployment-bundle/bindings" ;
23
29
24
30
describe ( "--x-provision" , ( ) => {
@@ -86,7 +92,7 @@ describe("--x-provision", () => {
86
92
] ,
87
93
} ) ;
88
94
89
- await expect ( runWrangler ( "deploy --x-provision" ) ) . resolves . toBeUndefined ( ) ;
95
+ await runWrangler ( "deploy --x-provision" ) ;
90
96
expect ( std . out ) . toMatchInlineSnapshot ( `
91
97
"Total Upload: xx KiB / gzip: xx KiB
92
98
Worker Startup Time: 100 ms
@@ -479,6 +485,337 @@ describe("--x-provision", () => {
479
485
expect ( std . err ) . toMatchInlineSnapshot ( `""` ) ;
480
486
expect ( std . warn ) . toMatchInlineSnapshot ( `""` ) ;
481
487
} ) ;
488
+
489
+ it ( "can prefill d1 database name from config file if provided" , async ( ) => {
490
+ writeWranglerConfig ( {
491
+ main : "index.js" ,
492
+ d1_databases : [ { binding : "D1" , database_name : "prefilled-d1-name" } ] ,
493
+ } ) ;
494
+ mockGetSettings ( ) ;
495
+ msw . use (
496
+ http . get ( "*/accounts/:accountId/d1/database" , async ( ) => {
497
+ return HttpResponse . json (
498
+ createFetchResult ( [
499
+ {
500
+ name : "db-name" ,
501
+ uuid : "existing-d1-id" ,
502
+ } ,
503
+ ] )
504
+ ) ;
505
+ } )
506
+ ) ;
507
+
508
+ // no name prompt
509
+ mockCreateD1Database ( {
510
+ assertName : "prefilled-d1-name" ,
511
+ resultId : "new-d1-id" ,
512
+ } ) ;
513
+
514
+ mockConfirm ( {
515
+ text : `Would you like to create a new D1 Database named "prefilled-d1-name"?` ,
516
+ result : true ,
517
+ } ) ;
518
+ mockUploadWorkerRequest ( {
519
+ expectedBindings : [
520
+ {
521
+ name : "D1" ,
522
+ type : "d1" ,
523
+ id : "new-d1-id" ,
524
+ } ,
525
+ ] ,
526
+ } ) ;
527
+
528
+ await runWrangler ( "deploy --x-provision" ) ;
529
+
530
+ expect ( std . out ) . toMatchInlineSnapshot ( `
531
+ "Total Upload: xx KiB / gzip: xx KiB
532
+
533
+ The following bindings need to be provisioned:
534
+ - D1 Databases:
535
+ - D1
536
+
537
+ Provisioning D1 (D1 Database)...
538
+ Resource name found in config: prefilled-d1-name
539
+ No pre-existing resource found with that name
540
+ 🌀 Creating new D1 Database \\"prefilled-d1-name\\"...
541
+ ✨ D1 provisioned with prefilled-d1-name
542
+
543
+ --------------------------------------
544
+
545
+ 🎉 All resources provisioned, continuing with deployment...
546
+
547
+ Worker Startup Time: 100 ms
548
+ Your worker has access to the following bindings:
549
+ - D1 Databases:
550
+ - D1: prefilled-d1-name (new-d1-id)
551
+ Uploaded test-name (TIMINGS)
552
+ Deployed test-name triggers (TIMINGS)
553
+ https://test-name.test-sub-domain.workers.dev
554
+ Current Version ID: Galaxy-Class"
555
+ ` ) ;
556
+ expect ( std . err ) . toMatchInlineSnapshot ( `""` ) ;
557
+ expect ( std . warn ) . toMatchInlineSnapshot ( `""` ) ;
558
+ } ) ;
559
+
560
+ it ( "can inherit d1 binding when the database name is provided" , async ( ) => {
561
+ writeWranglerConfig ( {
562
+ main : "index.js" ,
563
+ d1_databases : [ { binding : "D1" , database_name : "prefilled-d1-name" } ] ,
564
+ } ) ;
565
+ mockGetSettings ( {
566
+ result : {
567
+ bindings : [
568
+ {
569
+ type : "d1" ,
570
+ name : "D1" ,
571
+ id : "d1-id" ,
572
+ } ,
573
+ ] ,
574
+ } ,
575
+ } ) ;
576
+ mockGetD1Database ( "d1-id" , { name : "prefilled-d1-name" } ) ;
577
+ mockUploadWorkerRequest ( {
578
+ expectedBindings : [
579
+ {
580
+ name : "D1" ,
581
+ type : "inherit" ,
582
+ } ,
583
+ ] ,
584
+ } ) ;
585
+
586
+ await runWrangler ( "deploy --x-provision" ) ;
587
+ expect ( std . out ) . toMatchInlineSnapshot ( `
588
+ "Total Upload: xx KiB / gzip: xx KiB
589
+ Worker Startup Time: 100 ms
590
+ Your worker has access to the following bindings:
591
+ - D1 Databases:
592
+ - D1: prefilled-d1-name
593
+ Uploaded test-name (TIMINGS)
594
+ Deployed test-name triggers (TIMINGS)
595
+ https://test-name.test-sub-domain.workers.dev
596
+ Current Version ID: Galaxy-Class"
597
+ ` ) ;
598
+ } ) ;
599
+
600
+ it ( "will not inherit d1 binding when the database name is provided but has changed" , async ( ) => {
601
+ // first deploy used old-d1-name/old-d1-id
602
+ // now we provide a different database_name that doesn't match
603
+ writeWranglerConfig ( {
604
+ main : "index.js" ,
605
+ d1_databases : [ { binding : "D1" , database_name : "new-d1-name" } ] ,
606
+ } ) ;
607
+ mockGetSettings ( {
608
+ result : {
609
+ bindings : [
610
+ {
611
+ type : "d1" ,
612
+ name : "D1" ,
613
+ id : "old-d1-id" ,
614
+ } ,
615
+ ] ,
616
+ } ,
617
+ } ) ;
618
+ msw . use (
619
+ http . get ( "*/accounts/:accountId/d1/database" , async ( ) => {
620
+ return HttpResponse . json (
621
+ createFetchResult ( [
622
+ {
623
+ name : "old-d1-name" ,
624
+ uuid : "old-d1-id" ,
625
+ } ,
626
+ ] )
627
+ ) ;
628
+ } )
629
+ ) ;
630
+
631
+ mockGetD1Database ( "old-d1-id" , { name : "old-d1-name" } ) ;
632
+
633
+ // no name prompt
634
+ mockCreateD1Database ( {
635
+ assertName : "new-d1-name" ,
636
+ resultId : "new-d1-id" ,
637
+ } ) ;
638
+
639
+ mockConfirm ( {
640
+ text : `Would you like to create a new D1 Database named "new-d1-name"?` ,
641
+ result : true ,
642
+ } ) ;
643
+ mockUploadWorkerRequest ( {
644
+ expectedBindings : [
645
+ {
646
+ name : "D1" ,
647
+ type : "d1" ,
648
+ id : "new-d1-id" ,
649
+ } ,
650
+ ] ,
651
+ } ) ;
652
+
653
+ await runWrangler ( "deploy --x-provision" ) ;
654
+
655
+ expect ( std . out ) . toMatchInlineSnapshot ( `
656
+ "Total Upload: xx KiB / gzip: xx KiB
657
+
658
+ The following bindings need to be provisioned:
659
+ - D1 Databases:
660
+ - D1
661
+
662
+ Provisioning D1 (D1 Database)...
663
+ Resource name found in config: new-d1-name
664
+ No pre-existing resource found with that name
665
+ 🌀 Creating new D1 Database \\"new-d1-name\\"...
666
+ ✨ D1 provisioned with new-d1-name
667
+
668
+ --------------------------------------
669
+
670
+ 🎉 All resources provisioned, continuing with deployment...
671
+
672
+ Worker Startup Time: 100 ms
673
+ Your worker has access to the following bindings:
674
+ - D1 Databases:
675
+ - D1: new-d1-name (new-d1-id)
676
+ Uploaded test-name (TIMINGS)
677
+ Deployed test-name triggers (TIMINGS)
678
+ https://test-name.test-sub-domain.workers.dev
679
+ Current Version ID: Galaxy-Class"
680
+ ` ) ;
681
+ expect ( std . err ) . toMatchInlineSnapshot ( `""` ) ;
682
+ expect ( std . warn ) . toMatchInlineSnapshot ( `""` ) ;
683
+ } ) ;
684
+
685
+ it ( "can prefill r2 bucket name from config file if provided" , async ( ) => {
686
+ writeWranglerConfig ( {
687
+ main : "index.js" ,
688
+ r2_buckets : [
689
+ {
690
+ binding : "BUCKET" ,
691
+ bucket_name : "prefilled-r2-name" ,
692
+ // note it will also respect jurisdiction if provided, but wont prompt for it
693
+ jurisdiction : "eu" ,
694
+ } ,
695
+ ] ,
696
+ } ) ;
697
+ mockGetSettings ( ) ;
698
+ msw . use (
699
+ http . get ( "*/accounts/:accountId/r2/buckets" , async ( ) => {
700
+ return HttpResponse . json (
701
+ createFetchResult ( {
702
+ buckets : [
703
+ {
704
+ name : "existing-bucket-name" ,
705
+ } ,
706
+ ] ,
707
+ } )
708
+ ) ;
709
+ } )
710
+ ) ;
711
+ mockGetR2Bucket ( "prefilled-r2-name" , true ) ;
712
+ // no name prompt
713
+ mockCreateR2Bucket ( {
714
+ assertBucketName : "prefilled-r2-name" ,
715
+ assertJurisdiction : "eu" ,
716
+ } ) ;
717
+
718
+ mockConfirm ( {
719
+ text : `Would you like to create a new R2 Bucket named "prefilled-r2-name"?` ,
720
+ result : true ,
721
+ } ) ;
722
+ mockUploadWorkerRequest ( {
723
+ expectedBindings : [
724
+ {
725
+ name : "BUCKET" ,
726
+ type : "r2_bucket" ,
727
+ bucket_name : "prefilled-r2-name" ,
728
+ jurisdiction : "eu" ,
729
+ } ,
730
+ ] ,
731
+ } ) ;
732
+
733
+ await runWrangler ( "deploy --x-provision" ) ;
734
+
735
+ expect ( std . out ) . toMatchInlineSnapshot ( `
736
+ "Total Upload: xx KiB / gzip: xx KiB
737
+
738
+ The following bindings need to be provisioned:
739
+ - R2 Buckets:
740
+ - BUCKET
741
+
742
+ Provisioning BUCKET (R2 Bucket)...
743
+ Resource name found in config: prefilled-r2-name
744
+ No pre-existing resource found with that name
745
+ 🌀 Creating new R2 Bucket \\"prefilled-r2-name\\"...
746
+ ✨ BUCKET provisioned with prefilled-r2-name
747
+
748
+ --------------------------------------
749
+
750
+ 🎉 All resources provisioned, continuing with deployment...
751
+
752
+ Worker Startup Time: 100 ms
753
+ Your worker has access to the following bindings:
754
+ - R2 Buckets:
755
+ - BUCKET: prefilled-r2-name (eu)
756
+ Uploaded test-name (TIMINGS)
757
+ Deployed test-name triggers (TIMINGS)
758
+ https://test-name.test-sub-domain.workers.dev
759
+ Current Version ID: Galaxy-Class"
760
+ ` ) ;
761
+ expect ( std . err ) . toMatchInlineSnapshot ( `""` ) ;
762
+ expect ( std . warn ) . toMatchInlineSnapshot ( `""` ) ;
763
+ } ) ;
764
+
765
+ // to maintain current behaviour
766
+ it ( "wont prompt to provision if an r2 bucket name belongs to an existing bucket" , async ( ) => {
767
+ writeWranglerConfig ( {
768
+ main : "index.js" ,
769
+ r2_buckets : [
770
+ {
771
+ binding : "BUCKET" ,
772
+ bucket_name : "existing-bucket-name" ,
773
+ jurisdiction : "eu" ,
774
+ } ,
775
+ ] ,
776
+ } ) ;
777
+ mockGetSettings ( ) ;
778
+ msw . use (
779
+ http . get ( "*/accounts/:accountId/r2/buckets" , async ( ) => {
780
+ return HttpResponse . json (
781
+ createFetchResult ( {
782
+ buckets : [
783
+ {
784
+ name : "existing-bucket-name" ,
785
+ } ,
786
+ ] ,
787
+ } )
788
+ ) ;
789
+ } )
790
+ ) ;
791
+ mockGetR2Bucket ( "existing-bucket-name" , false ) ;
792
+ mockUploadWorkerRequest ( {
793
+ expectedBindings : [
794
+ {
795
+ name : "BUCKET" ,
796
+ type : "r2_bucket" ,
797
+ bucket_name : "existing-bucket-name" ,
798
+ jurisdiction : "eu" ,
799
+ } ,
800
+ ] ,
801
+ } ) ;
802
+
803
+ await runWrangler ( "deploy --x-provision" ) ;
804
+
805
+ expect ( std . out ) . toMatchInlineSnapshot ( `
806
+ "Total Upload: xx KiB / gzip: xx KiB
807
+ Worker Startup Time: 100 ms
808
+ Your worker has access to the following bindings:
809
+ - R2 Buckets:
810
+ - BUCKET: existing-bucket-name (eu)
811
+ Uploaded test-name (TIMINGS)
812
+ Deployed test-name triggers (TIMINGS)
813
+ https://test-name.test-sub-domain.workers.dev
814
+ Current Version ID: Galaxy-Class"
815
+ ` ) ;
816
+ expect ( std . err ) . toMatchInlineSnapshot ( `""` ) ;
817
+ expect ( std . warn ) . toMatchInlineSnapshot ( `""` ) ;
818
+ } ) ;
482
819
} ) ;
483
820
484
821
it ( "should error if used with a service environment" , async ( ) => {
@@ -555,6 +892,7 @@ function mockCreateD1Database(
555
892
function mockCreateR2Bucket (
556
893
options : {
557
894
assertBucketName ?: string ;
895
+ assertJurisdiction ?: string ;
558
896
} = { }
559
897
) {
560
898
msw . use (
@@ -563,11 +901,53 @@ function mockCreateR2Bucket(
563
901
async ( { request } ) => {
564
902
if ( options . assertBucketName ) {
565
903
const requestBody = await request . json ( ) ;
566
- expect ( requestBody ) . toEqual ( { name : options . assertBucketName } ) ;
904
+ expect ( requestBody ) . toMatchObject ( { name : options . assertBucketName } ) ;
905
+ }
906
+ if ( options . assertJurisdiction ) {
907
+ expect ( request . headers . get ( "cf-r2-jurisdiction" ) ) . toEqual (
908
+ options . assertJurisdiction
909
+ ) ;
910
+ }
911
+ return HttpResponse . json ( createFetchResult ( { } ) ) ;
912
+ } ,
913
+ { once : true }
914
+ )
915
+ ) ;
916
+ }
917
+
918
+ function mockGetR2Bucket ( bucketName : string , missing : boolean = false ) {
919
+ msw . use (
920
+ http . get (
921
+ "*/accounts/:accountId/r2/buckets/:bucketName" ,
922
+ async ( { params } ) => {
923
+ const { bucketName : bucketParam } = params ;
924
+ expect ( bucketParam ) . toEqual ( bucketName ) ;
925
+ if ( missing ) {
926
+ return HttpResponse . json (
927
+ createFetchResult ( null , false , [
928
+ { code : 10006 , message : "bucket not found" } ,
929
+ ] )
930
+ ) ;
567
931
}
568
932
return HttpResponse . json ( createFetchResult ( { } ) ) ;
569
933
} ,
570
934
{ once : true }
571
935
)
572
936
) ;
573
937
}
938
+
939
+ function mockGetD1Database (
940
+ databaseId : string ,
941
+ databaseInfo : Partial < DatabaseInfo >
942
+ ) {
943
+ msw . use (
944
+ http . get (
945
+ `*/accounts/:accountId/d1/database/:database_id` ,
946
+ ( { params } ) => {
947
+ expect ( params . database_id ) . toEqual ( databaseId ) ;
948
+ return HttpResponse . json ( createFetchResult ( databaseInfo ) ) ;
949
+ } ,
950
+ { once : true }
951
+ )
952
+ ) ;
953
+ }
0 commit comments