@@ -5,6 +5,7 @@ import {sleep} from '@shopify/cli-kit/node/system'
55import { renderSingleTask } from '@shopify/cli-kit/node/ui'
66import { describe , test , expect , vi , beforeEach } from 'vitest'
77import { outputContent } from '@shopify/cli-kit/node/output'
8+ import { AbortController } from '@shopify/cli-kit/node/abort'
89
910vi . mock ( './format-bulk-operation-status.js' )
1011vi . mock ( '@shopify/cli-kit/node/api/admin' )
@@ -14,6 +15,7 @@ vi.mock('@shopify/cli-kit/node/ui')
1415describe ( 'watchBulkOperation' , ( ) => {
1516 const mockAdminSession = { token : 'test-token' , storeFqdn : 'test.myshopify.com' }
1617 const operationId = 'gid://shopify/BulkOperation/123'
18+ let abortController : AbortController
1719
1820 const runningOperation = {
1921 id : operationId ,
@@ -30,8 +32,13 @@ describe('watchBulkOperation', () => {
3032 }
3133
3234 beforeEach ( ( ) => {
35+ abortController = new AbortController ( )
3336 vi . mocked ( sleep ) . mockResolvedValue ( )
3437 vi . mocked ( formatBulkOperationStatus ) . mockReturnValue ( outputContent `formatted status` )
38+ vi . mocked ( renderSingleTask ) . mockImplementation ( async ( { task, onAbort} ) => {
39+ if ( onAbort ) onAbort ( )
40+ return task ( ( ) => { } )
41+ } )
3542 } )
3643
3744 test ( 'polls until operation completes and returns the final operation' , async ( ) => {
@@ -40,11 +47,7 @@ describe('watchBulkOperation', () => {
4047 . mockResolvedValueOnce ( { bulkOperation : runningOperation } )
4148 . mockResolvedValueOnce ( { bulkOperation : completedOperation } )
4249
43- vi . mocked ( renderSingleTask ) . mockImplementation ( async ( { task} ) => {
44- return task ( ( ) => { } )
45- } )
46-
47- const result = await watchBulkOperation ( mockAdminSession , operationId )
50+ const result = await watchBulkOperation ( mockAdminSession , operationId , abortController . signal , ( ) => { } )
4851
4952 expect ( result ) . toEqual ( completedOperation )
5053 expect ( adminRequestDoc ) . toHaveBeenCalledTimes ( 3 )
@@ -65,11 +68,7 @@ describe('watchBulkOperation', () => {
6568 . mockResolvedValueOnce ( { bulkOperation : runningOperation } )
6669 . mockResolvedValueOnce ( { bulkOperation : terminalOperation } )
6770
68- vi . mocked ( renderSingleTask ) . mockImplementation ( async ( { task} ) => {
69- return task ( ( ) => { } )
70- } )
71-
72- const result = await watchBulkOperation ( mockAdminSession , operationId )
71+ const result = await watchBulkOperation ( mockAdminSession , operationId , abortController . signal , ( ) => { } )
7372
7473 expect ( result ) . toEqual ( terminalOperation )
7574 expect ( adminRequestDoc ) . toHaveBeenCalledTimes ( 3 )
@@ -97,7 +96,7 @@ describe('watchBulkOperation', () => {
9796 return task ( mockUpdateStatus )
9897 } )
9998
100- await watchBulkOperation ( mockAdminSession , operationId )
99+ await watchBulkOperation ( mockAdminSession , operationId , abortController . signal , ( ) => { } )
101100
102101 expect ( mockUpdateStatus ) . toHaveBeenNthCalledWith ( 1 , outputContent `processed 10 objects` )
103102 expect ( mockUpdateStatus ) . toHaveBeenNthCalledWith ( 2 , outputContent `processed 20 objects` )
@@ -107,10 +106,34 @@ describe('watchBulkOperation', () => {
107106 test ( 'throws when operation not found' , async ( ) => {
108107 vi . mocked ( adminRequestDoc ) . mockResolvedValue ( { bulkOperation : null } )
109108
110- vi . mocked ( renderSingleTask ) . mockImplementation ( async ( { task} ) => {
111- return task ( ( ) => { } )
109+ await expect ( watchBulkOperation ( mockAdminSession , operationId , abortController . signal , ( ) => { } ) ) . rejects . toThrow (
110+ 'bulk operation not found' ,
111+ )
112+ } )
113+
114+ describe ( 'when signal is aborted during polling' , ( ) => {
115+ beforeEach ( ( ) => {
116+ let callCount = 0
117+ vi . mocked ( adminRequestDoc ) . mockImplementation ( async ( ) => {
118+ callCount ++
119+ if ( callCount === 2 ) {
120+ abortController . abort ( )
121+ }
122+ return { bulkOperation : runningOperation }
123+ } )
112124 } )
113125
114- await expect ( watchBulkOperation ( mockAdminSession , operationId ) ) . rejects . toThrow ( 'bulk operation not found' )
126+ test ( 'returns current state of the operation, even if it is not terminal' , async ( ) => {
127+ const result = await watchBulkOperation ( mockAdminSession , operationId , abortController . signal , ( ) => { } )
128+
129+ expect ( result . status ) . toBe ( 'RUNNING' )
130+ expect ( result ) . toEqual ( runningOperation )
131+ } )
132+
133+ test ( 'calls the onAbort callback' , async ( ) => {
134+ const onAbort = vi . fn ( )
135+ await watchBulkOperation ( mockAdminSession , operationId , abortController . signal , onAbort )
136+ expect ( onAbort ) . toHaveBeenCalled ( )
137+ } )
115138 } )
116139} )
0 commit comments