diff --git a/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.test.ts b/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.test.ts index 11d221e0cf1..22f0eeccff6 100644 --- a/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.test.ts +++ b/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.test.ts @@ -134,6 +134,7 @@ describe('executeBulkOperation', () => { test('runs mutation operation when GraphQL document starts with mutation', async () => { const mutation = 'mutation productUpdate($input: ProductInput!) { productUpdate(input: $input) { product { id } } }' + const variables = ['{"input":{"id":"gid://shopify/Product/123"}}'] const mockResponse: BulkOperationRunMutationMutation['bulkOperationRunMutation'] = { bulkOperation: createdBulkOperation, userErrors: [], @@ -145,12 +146,13 @@ describe('executeBulkOperation', () => { remoteApp: mockRemoteApp, store: mockStore, query: mutation, + variables, }) expect(runBulkOperationMutation).toHaveBeenCalledWith({ adminSession: mockAdminSession, query: mutation, - variablesJsonl: undefined, + variablesJsonl: '{"input":{"id":"gid://shopify/Product/123"}}', version: BULK_OPERATIONS_MIN_API_VERSION, }) expect(runBulkOperationQuery).not.toHaveBeenCalled() @@ -326,6 +328,22 @@ describe('executeBulkOperation', () => { }) }) + test('throws error when mutation is provided without variables', async () => { + const mutation = 'mutation productUpdate($input: ProductInput!) { productUpdate(input: $input) { product { id } } }' + + await expect( + executeBulkOperation({ + organization: mockOrganization, + remoteApp: mockRemoteApp, + store: mockStore, + query: mutation, + }), + ).rejects.toThrow('Bulk mutations require variables') + + expect(runBulkOperationQuery).not.toHaveBeenCalled() + expect(runBulkOperationMutation).not.toHaveBeenCalled() + }) + test('uses watchBulkOperation (not quickWatchBulkOperation) when watch flag is true', async () => { const query = '{ products { edges { node { id } } } }' const initialResponse: BulkOperationRunQueryMutation['bulkOperationRunQuery'] = { diff --git a/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.ts b/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.ts index eecac70803d..81e1c07ffb6 100644 --- a/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.ts +++ b/packages/app/src/cli/services/bulk-operations/execute-bulk-operation.ts @@ -207,10 +207,15 @@ function resultsContainUserErrors(results: string): boolean { }) } -/** - * Validates bulk operation-specific constraints for variables. - */ function validateBulkOperationVariables(graphqlOperation: string, variablesJsonl?: string): void { + if (isMutation(graphqlOperation) && !variablesJsonl) { + throw new AbortError( + outputContent`Bulk mutations require variables. Provide a JSONL file with ${outputToken.yellow( + '--variable-file', + )} or individual JSON objects with ${outputToken.yellow('--variables')}.`, + ) + } + if (!isMutation(graphqlOperation) && variablesJsonl) { throw new AbortError( outputContent`The ${outputToken.yellow('--variables')} and ${outputToken.yellow(