@@ -6,40 +6,45 @@ const baseInput: StepListInput = {
66 createReplicationRule : true ,
77 sourceAccountName : 'src-account' ,
88 sourceBucketName : 'src-bucket' ,
9+ targetBucketName : 'target-bucket' ,
910 destinationAccountName : 'dest-account' ,
1011} ;
1112
1213describe ( 'buildStepViews' , ( ) => {
13- it ( 'lists the 10 canonical steps in order when both create- source- account and create- replication-rule apply ' , ( ) => {
14+ it ( 'lists the full provisioning sequence in order when the user creates a new source account and a replication rule ' , ( ) => {
1415 const views = buildStepViews ( baseInput , [ ] ) ;
1516 expect ( views . map ( ( v ) => v . id ) ) . toEqual ( [
1617 'import-destination-certificate' ,
1718 'create-source-account' ,
1819 'create-source-bucket' ,
19- 'create-destination- account' ,
20+ 'create-account' ,
2021 'create-user' ,
2122 'create-access-key' ,
2223 'create-policy' ,
23- 'attach-policy' ,
24+ 'create-role' ,
25+ 'attach-role-policy' ,
26+ 'create-bucket' ,
2427 'create-location' ,
2528 'create-replication-rule' ,
2629 ] ) ;
2730 } ) ;
2831
29- it ( 'numbers steps starting at 1 and interpolates source/ destination names' , ( ) => {
32+ it ( 'numbers the steps and shows the chosen source and destination account names' , ( ) => {
3033 const [ first , sourceAcc , sourceBkt , destAcc ] = buildStepViews ( baseInput , [ ] ) ;
3134 expect ( first ) . toMatchObject ( { step : 1 , label : 'Import Destination Certificate' } ) ;
3235 expect ( sourceAcc ) . toMatchObject ( { step : 2 , label : 'Create Account on Source: src-account' } ) ;
3336 expect ( sourceBkt ) . toMatchObject ( { step : 3 , label : 'Create Bucket on Source: src-bucket' } ) ;
3437 expect ( destAcc ) . toMatchObject ( { step : 4 , label : 'Create Account on Destination: dest-account' } ) ;
3538 } ) ;
3639
37- it ( 'uses ISV wording verbatim for the reused actions ' , ( ) => {
40+ it ( 'labels the destination IAM chain and the target bucket per the ARTESCA CRR procedure ' , ( ) => {
3841 const labels = buildStepViews ( baseInput , [ ] ) . map ( ( v ) => v . label ) ;
3942 expect ( labels ) . toContain ( 'Create IAM User' ) ;
4043 expect ( labels ) . toContain ( 'Generate Access Key' ) ;
4144 expect ( labels ) . toContain ( 'Create Policy' ) ;
42- expect ( labels ) . toContain ( 'Attach Policy to User' ) ;
45+ expect ( labels ) . toContain ( 'Create IAM Role' ) ;
46+ expect ( labels ) . toContain ( 'Attach Policy to Role' ) ;
47+ expect ( labels ) . toContain ( 'Create Target Bucket: target-bucket' ) ;
4348 expect ( labels ) . toContain ( 'Create Location' ) ;
4449 expect ( labels ) . toContain ( 'Create Replication Rule' ) ;
4550 } ) ;
@@ -49,28 +54,33 @@ describe('buildStepViews', () => {
4954 expect ( views . find ( ( v ) => v . id === 'create-source-account' ) ) . toBeUndefined ( ) ;
5055 } ) ;
5156
52- it ( 'drops the two replication-only steps when the wizard did not opt into replication rule creation' , ( ) => {
57+ it ( 'drops the replication-only steps when the wizard did not opt into replication rule creation' , ( ) => {
5358 const views = buildStepViews ( { ...baseInput , createReplicationRule : false } , [ ] ) ;
5459 expect ( views . find ( ( v ) => v . id === 'create-source-bucket' ) ) . toBeUndefined ( ) ;
60+ expect ( views . find ( ( v ) => v . id === 'create-bucket' ) ) . toBeUndefined ( ) ;
5561 expect ( views . find ( ( v ) => v . id === 'create-replication-rule' ) ) . toBeUndefined ( ) ;
5662 } ) ;
5763
58- it ( 'never surfaces authenticate, create-role, attach-role-policy or create-bucket-on-destination ' , ( ) => {
64+ it ( 'never surfaces the backend authenticate step (it is covered by the Verify wizard step) ' , ( ) => {
5965 const ids = buildStepViews ( baseInput , [ ] ) . map ( ( v ) => v . id ) as string [ ] ;
60- for ( const id of [ 'authenticate' , 'create-role' , 'attach-role-policy' , 'create-bucket' ] ) {
61- expect ( ids ) . not . toContain ( id ) ;
66+ expect ( ids ) . not . toContain ( 'authenticate' ) ;
67+ } ) ;
68+
69+ it ( 'surfaces the destination role, policy attachment and target bucket steps the CRR procedure requires' , ( ) => {
70+ const ids = buildStepViews ( baseInput , [ ] ) . map ( ( v ) => v . id ) as string [ ] ;
71+ for ( const id of [ 'create-role' , 'attach-role-policy' , 'create-bucket' ] ) {
72+ expect ( ids ) . toContain ( id ) ;
6273 }
6374 } ) ;
6475
65- it ( 'leaves every step pending until a matching event lands ' , ( ) => {
76+ it ( 'shows every step as pending before the setup runs ' , ( ) => {
6677 const views = buildStepViews ( baseInput , [ ] ) ;
6778 expect ( views . every ( ( v ) => v . state === 'pending' ) ) . toBe ( true ) ;
6879 } ) ;
6980
70- it ( 'marks a step succeeded on step.completed and failed on step.failed with its error message ' , ( ) => {
81+ it ( 'marks a step done once it completes and shows the reason when one fails ' , ( ) => {
7182 const events : SetupEvent [ ] = [
72- { event : 'step.completed' , step : 'import-destination-certificate' , at : 't' } ,
73- { event : 'step.completed' , step : 'create-source-account' , at : 't' } ,
83+ { event : 'step.completed' , step : 'create-account' , at : 't' } ,
7484 {
7585 event : 'step.failed' ,
7686 step : 'create-user' ,
@@ -79,23 +89,23 @@ describe('buildStepViews', () => {
7989 } ,
8090 ] ;
8191 const views = buildStepViews ( baseInput , events ) ;
82- expect ( views . find ( ( v ) => v . id === 'import-destination-certificate ' ) ?. state ) . toBe ( 'succeeded' ) ;
92+ expect ( views . find ( ( v ) => v . id === 'create-account ' ) ?. state ) . toBe ( 'succeeded' ) ;
8393 const failed = views . find ( ( v ) => v . id === 'create-user' ) ;
8494 expect ( failed ?. state ) . toBe ( 'failed' ) ;
8595 expect ( failed ?. errorMessage ) . toBe ( 'IAM refused CreateUser: entity already exists' ) ;
8696 } ) ;
8797} ) ;
8898
89- describe ( 'buildStepViews with a globalErrorMessage ' , ( ) => {
90- it ( 'marks the first pending step as failed with the global error message when no step-level failure landed ' , ( ) => {
99+ describe ( 'when the whole setup fails without pinpointing a step ' , ( ) => {
100+ it ( 'blames the first step still waiting to run and shows why ' , ( ) => {
91101 const views = buildStepViews ( baseInput , [ ] , { globalErrorMessage : 'network exploded' } ) ;
92102 const firstPending = views [ 0 ] ;
93103 expect ( firstPending . state ) . toBe ( 'failed' ) ;
94104 expect ( firstPending . errorMessage ) . toBe ( 'network exploded' ) ;
95105 for ( const v of views . slice ( 1 ) ) expect ( v . state ) . toBe ( 'pending' ) ;
96106 } ) ;
97107
98- it ( 'marks the first still-pending step as failed after some steps already succeeded' , ( ) => {
108+ it ( 'blames the first unfinished step once earlier ones have already succeeded' , ( ) => {
99109 const events : SetupEvent [ ] = [
100110 { event : 'step.completed' , step : 'import-destination-certificate' , at : 't' } ,
101111 { event : 'step.completed' , step : 'create-source-account' , at : 't' } ,
@@ -107,7 +117,7 @@ describe('buildStepViews with a globalErrorMessage', () => {
107117 expect ( views [ 2 ] . errorMessage ) . toBe ( 'stream ended without a terminal event' ) ;
108118 } ) ;
109119
110- it ( 'leaves the step-level failure in place when both a step.failed and a global error are present ' , ( ) => {
120+ it ( 'keeps a specific step failure visible rather than replacing it with the generic error' , ( ) => {
111121 const events : SetupEvent [ ] = [
112122 {
113123 event : 'step.failed' ,
0 commit comments