@@ -141,82 +141,97 @@ describe("version-mutations", () => {
141141 } ) ;
142142
143143 describe ( "submitForReview" , ( ) => {
144- it ( "creates submission when no draft exists, adds item, then confirms" , async ( ) => {
144+ /** Mock findUnresolvedSubmission returning no results. */
145+ function mockNoUnresolved ( ) {
146+ mockAscFetch . mockResolvedValueOnce ( { data : [ ] } ) ; // no UNRESOLVED_ISSUES
147+ }
148+
149+ it ( "creates submission when no unresolved or draft exists" , async ( ) => {
150+ mockNoUnresolved ( ) ;
145151 mockAscFetch
146- . mockResolvedValueOnce ( { data : [ ] } ) // find drafts: none
152+ . mockResolvedValueOnce ( { data : [ ] } ) // findOrCreate: no READY_FOR_REVIEW drafts
147153 . mockResolvedValueOnce ( { data : { id : "sub-1" } } ) // create submission
148154 . mockResolvedValueOnce ( { } ) // add item
149155 . mockResolvedValueOnce ( { } ) ; // confirm
150156
151157 await submitForReview ( "app-1" , "ver-1" , "MAC_OS" ) ;
152158
153- // Step 1: check for existing drafts
154- expect ( mockAscFetch . mock . calls [ 0 ] [ 0 ] ) . toContain ( "/v1/apps/app-1/reviewSubmissions" ) ;
155-
156- // Step 1b: create new submission (no draft found)
157159 expect ( mockAscFetch ) . toHaveBeenCalledWith (
158160 "/v1/reviewSubmissions" ,
159161 expect . objectContaining ( { method : "POST" } ) ,
160162 ) ;
161- const createBody = JSON . parse ( mockAscFetch . mock . calls [ 1 ] [ 1 ] . body ) ;
162- expect ( createBody . data . type ) . toBe ( "reviewSubmissions" ) ;
163- expect ( createBody . data . attributes . platform ) . toBe ( "MAC_OS" ) ;
164- expect ( createBody . data . relationships . app . data . id ) . toBe ( "app-1" ) ;
165-
166- // Step 2: add version as item
167163 expect ( mockAscFetch ) . toHaveBeenCalledWith (
168164 "/v1/reviewSubmissionItems" ,
169165 expect . objectContaining ( { method : "POST" } ) ,
170166 ) ;
171- const itemBody = JSON . parse ( mockAscFetch . mock . calls [ 2 ] [ 1 ] . body ) ;
172- expect ( itemBody . data . relationships . reviewSubmission . data . id ) . toBe ( "sub-1" ) ;
173- expect ( itemBody . data . relationships . appStoreVersion . data . id ) . toBe ( "ver-1" ) ;
174167
175- // Step 3: confirm submission
176- const confirmBody = JSON . parse ( mockAscFetch . mock . calls [ 3 ] [ 1 ] . body ) ;
177- expect ( confirmBody . data . attributes . submitted ) . toBe ( true ) ;
168+ const lastCall = mockAscFetch . mock . calls [ mockAscFetch . mock . calls . length - 1 ] ;
169+ const body = JSON . parse ( lastCall [ 1 ] . body ) ;
170+ expect ( body . data . attributes . submitted ) . toBe ( true ) ;
178171 } ) ;
179172
180- it ( "reuses an existing draft submission instead of creating a new one" , async ( ) => {
173+ it ( "resubmits UNRESOLVED_ISSUES submission directly after rejection" , async ( ) => {
174+ mockAscFetch
175+ . mockResolvedValueOnce ( { data : [
176+ { id : "rejected-sub" , attributes : { state : "UNRESOLVED_ISSUES" } } ,
177+ ] } )
178+ . mockResolvedValueOnce ( { } ) ; // confirm
179+
180+ await submitForReview ( "app-1" , "ver-1" , "IOS" ) ;
181+
182+ // Should confirm the UNRESOLVED_ISSUES submission directly
183+ const confirmCall = mockAscFetch . mock . calls [ 1 ] ;
184+ expect ( confirmCall [ 0 ] ) . toBe ( "/v1/reviewSubmissions/rejected-sub" ) ;
185+ const body = JSON . parse ( confirmCall [ 1 ] . body ) ;
186+ expect ( body . data . attributes . submitted ) . toBe ( true ) ;
187+
188+ // Should NOT create a new submission or add items
189+ expect ( mockAscFetch ) . toHaveBeenCalledTimes ( 2 ) ;
190+ } ) ;
191+
192+ it ( "reuses an existing READY_FOR_REVIEW draft in normal flow" , async ( ) => {
193+ mockNoUnresolved ( ) ;
181194 mockAscFetch
182195 . mockResolvedValueOnce ( { data : [
183196 { id : "existing-sub" , attributes : { state : "READY_FOR_REVIEW" } } ,
184- ] } ) // find drafts: one exists
197+ ] } )
185198 . mockResolvedValueOnce ( { } ) // add item
186199 . mockResolvedValueOnce ( { } ) ; // confirm
187200
188201 await submitForReview ( "app-1" , "ver-1" , "IOS" ) ;
189202
190- // Should NOT create a new submission – only 3 calls total
191- expect ( mockAscFetch ) . toHaveBeenCalledTimes ( 3 ) ;
192-
193- // Item should reference the existing submission
194- const itemBody = JSON . parse ( mockAscFetch . mock . calls [ 1 ] [ 1 ] . body ) ;
203+ const addItemCall = mockAscFetch . mock . calls . find (
204+ ( c : unknown [ ] ) => c [ 0 ] === "/v1/reviewSubmissionItems" && ( c [ 1 ] as Record < string , string > ) ?. method === "POST" ,
205+ ) ! ;
206+ const itemBody = JSON . parse ( ( addItemCall [ 1 ] as Record < string , string > ) . body ) ;
195207 expect ( itemBody . data . relationships . reviewSubmission . data . id ) . toBe ( "existing-sub" ) ;
196208 } ) ;
197209
198- it ( "throws when step 2 (add item) fails" , async ( ) => {
210+ it ( "throws when add item fails" , async ( ) => {
211+ mockNoUnresolved ( ) ;
199212 mockAscFetch
200- . mockResolvedValueOnce ( { data : [ ] } ) // find drafts : none
213+ . mockResolvedValueOnce ( { data : [ ] } ) // findOrCreate : none
201214 . mockResolvedValueOnce ( { data : { id : "sub-1" } } ) // create
202- . mockRejectedValueOnce ( new Error ( "add item failed" ) ) ; // add item fails
215+ . mockRejectedValueOnce ( new Error ( "add item failed" ) ) ;
203216
204217 await expect ( submitForReview ( "app-1" , "ver-1" , "IOS" ) ) . rejects . toThrow ( "add item failed" ) ;
205218 } ) ;
206219
207- it ( "throws when step 3 (confirm) fails" , async ( ) => {
220+ it ( "throws when confirm fails" , async ( ) => {
221+ mockNoUnresolved ( ) ;
208222 mockAscFetch
209- . mockResolvedValueOnce ( { data : [ ] } ) // find drafts : none
223+ . mockResolvedValueOnce ( { data : [ ] } ) // findOrCreate : none
210224 . mockResolvedValueOnce ( { data : { id : "sub-1" } } ) // create
211225 . mockResolvedValueOnce ( { } ) // add item
212- . mockRejectedValueOnce ( new Error ( "confirm failed" ) ) ; // confirm fails
226+ . mockRejectedValueOnce ( new Error ( "confirm failed" ) ) ;
213227
214228 await expect ( submitForReview ( "app-1" , "ver-1" , "IOS" ) ) . rejects . toThrow ( "confirm failed" ) ;
215229 } ) ;
216230
217- it ( "falls through to create when listing drafts fails" , async ( ) => {
231+ it ( "falls through to normal flow when unresolved search fails" , async ( ) => {
218232 mockAscFetch
219- . mockRejectedValueOnce ( new Error ( "list failed" ) ) // find drafts fails
233+ . mockRejectedValueOnce ( new Error ( "list failed" ) ) // unresolved search fails
234+ . mockResolvedValueOnce ( { data : [ ] } ) // findOrCreate: none
220235 . mockResolvedValueOnce ( { data : { id : "sub-1" } } ) // create
221236 . mockResolvedValueOnce ( { } ) // add item
222237 . mockResolvedValueOnce ( { } ) ; // confirm
0 commit comments