@@ -4,6 +4,8 @@ import {runBulkOperationMutation} from './run-mutation.js'
44import { AppLinkedInterface } from '../../models/app/app.js'
55import { renderSuccess , renderWarning } from '@shopify/cli-kit/node/ui'
66import { ensureAuthenticatedAdmin } from '@shopify/cli-kit/node/session'
7+ import { inTemporaryDirectory , writeFile } from '@shopify/cli-kit/node/fs'
8+ import { joinPath } from '@shopify/cli-kit/node/path'
79import { describe , test , expect , vi , beforeEach } from 'vitest'
810
911vi . mock ( './run-query.js' )
@@ -50,7 +52,6 @@ describe('executeBulkOperation', () => {
5052 expect ( runBulkOperationQuery ) . toHaveBeenCalledWith ( {
5153 adminSession : mockAdminSession ,
5254 query,
53- variables : undefined ,
5455 } )
5556 expect ( runBulkOperationMutation ) . not . toHaveBeenCalled ( )
5657 } )
@@ -72,7 +73,6 @@ describe('executeBulkOperation', () => {
7273 expect ( runBulkOperationQuery ) . toHaveBeenCalledWith ( {
7374 adminSession : mockAdminSession ,
7475 query,
75- variables : undefined ,
7676 } )
7777 expect ( runBulkOperationMutation ) . not . toHaveBeenCalled ( )
7878 } )
@@ -94,7 +94,7 @@ describe('executeBulkOperation', () => {
9494 expect ( runBulkOperationMutation ) . toHaveBeenCalledWith ( {
9595 adminSession : mockAdminSession ,
9696 query : mutation ,
97- variables : undefined ,
97+ variablesJsonl : undefined ,
9898 } )
9999 expect ( runBulkOperationQuery ) . not . toHaveBeenCalled ( )
100100 } )
@@ -118,7 +118,7 @@ describe('executeBulkOperation', () => {
118118 expect ( runBulkOperationMutation ) . toHaveBeenCalledWith ( {
119119 adminSession : mockAdminSession ,
120120 query : mutation ,
121- variables ,
121+ variablesJsonl : '{"input":{"id":"gid://shopify/Product/123","tags":["test"]}}' ,
122122 } )
123123 } )
124124
@@ -216,4 +216,94 @@ describe('executeBulkOperation', () => {
216216 expect ( runBulkOperationQuery ) . not . toHaveBeenCalled ( )
217217 expect ( runBulkOperationMutation ) . not . toHaveBeenCalled ( )
218218 } )
219+
220+ test ( 'reads variables from file when variableFile is provided' , async ( ) => {
221+ await inTemporaryDirectory ( async ( tmpDir ) => {
222+ const variableFilePath = joinPath ( tmpDir , 'variables.jsonl' )
223+ const variables = [
224+ '{"input":{"id":"gid://shopify/Product/123","tags":["test"]}}' ,
225+ '{"input":{"id":"gid://shopify/Product/456","tags":["test2"]}}' ,
226+ ]
227+ await writeFile ( variableFilePath , variables . join ( '\n' ) )
228+
229+ const mutation =
230+ 'mutation productUpdate($input: ProductInput!) { productUpdate(input: $input) { product { id } } }'
231+ const mockResponse = {
232+ bulkOperation : successfulBulkOperation ,
233+ userErrors : [ ] ,
234+ }
235+ vi . mocked ( runBulkOperationMutation ) . mockResolvedValue ( mockResponse as any )
236+
237+ await executeBulkOperation ( {
238+ app : mockApp ,
239+ storeFqdn,
240+ query : mutation ,
241+ variableFile : variableFilePath ,
242+ } )
243+
244+ expect ( runBulkOperationMutation ) . toHaveBeenCalledWith ( {
245+ adminSession : mockAdminSession ,
246+ query : mutation ,
247+ variablesJsonl : variables . join ( '\n' ) ,
248+ } )
249+ } )
250+ } )
251+
252+ test ( 'throws error when variableFile does not exist' , async ( ) => {
253+ await inTemporaryDirectory ( async ( tmpDir ) => {
254+ const nonExistentPath = joinPath ( tmpDir , 'nonexistent.jsonl' )
255+ const mutation =
256+ 'mutation productUpdate($input: ProductInput!) { productUpdate(input: $input) { product { id } } }'
257+
258+ await expect (
259+ executeBulkOperation ( {
260+ app : mockApp ,
261+ storeFqdn,
262+ query : mutation ,
263+ variableFile : nonExistentPath ,
264+ } ) ,
265+ ) . rejects . toThrow ( 'Variable file not found' )
266+
267+ expect ( runBulkOperationQuery ) . not . toHaveBeenCalled ( )
268+ expect ( runBulkOperationMutation ) . not . toHaveBeenCalled ( )
269+ } )
270+ } )
271+
272+ test ( 'throws error when variables are provided with a query (not mutation)' , async ( ) => {
273+ const query = 'query { products { edges { node { id } } } }'
274+ const variables = [ '{"input":{"id":"gid://shopify/Product/123"}}' ]
275+
276+ await expect (
277+ executeBulkOperation ( {
278+ app : mockApp ,
279+ storeFqdn,
280+ query,
281+ variables,
282+ } ) ,
283+ ) . rejects . toThrow ( 'can only be used with mutations, not queries' )
284+
285+ expect ( runBulkOperationQuery ) . not . toHaveBeenCalled ( )
286+ expect ( runBulkOperationMutation ) . not . toHaveBeenCalled ( )
287+ } )
288+
289+ test ( 'throws error when variableFile is provided with a query (not mutation)' , async ( ) => {
290+ await inTemporaryDirectory ( async ( tmpDir ) => {
291+ const variableFilePath = joinPath ( tmpDir , 'variables.jsonl' )
292+ await writeFile ( variableFilePath , '{"input":{}}' )
293+
294+ const query = 'query { products { edges { node { id } } } }'
295+
296+ await expect (
297+ executeBulkOperation ( {
298+ app : mockApp ,
299+ storeFqdn,
300+ query,
301+ variableFile : variableFilePath ,
302+ } ) ,
303+ ) . rejects . toThrow ( 'can only be used with mutations, not queries' )
304+
305+ expect ( runBulkOperationQuery ) . not . toHaveBeenCalled ( )
306+ expect ( runBulkOperationMutation ) . not . toHaveBeenCalled ( )
307+ } )
308+ } )
219309} )
0 commit comments