From 2825ae229bc9b034a2050fd84f1d3edb562f9a96 Mon Sep 17 00:00:00 2001 From: gonzaloriestra <14979109+gonzaloriestra@users.noreply.github.com> Date: Thu, 14 May 2026 00:31:59 +0000 Subject: [PATCH] [Tests] Remove filesystem mocks in execute-bulk-operation.test.ts Replace global filesystem mocks with real filesystem operations within temporary directories. This improves test reliability by verifying actual file content on disk instead of merely asserting mock call counts. - Removed `vi.mock('@shopify/cli-kit/node/fs')` - Updated tests to use `inTemporaryDirectory` - Replaced `toHaveBeenCalledWith` on `writeFile` with `readFile` content checks - Fixed a test expectation by adding missing `version` parameter to `runBulkOperationMutation` --- .../execute-bulk-operation.test.ts | 126 +++++++++--------- 1 file changed, 66 insertions(+), 60 deletions(-) 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 815d934fd34..0e866066d6c 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 @@ -10,7 +10,7 @@ import {BulkOperationRunMutationMutation} from '../../api/graphql/bulk-operation import {OrganizationApp, OrganizationSource, OrganizationStore} from '../../models/organization.js' import {renderSuccess, renderWarning, renderError, renderInfo} from '@shopify/cli-kit/node/ui' import {ensureAuthenticatedAdminAsApp} from '@shopify/cli-kit/node/session' -import {inTemporaryDirectory, writeFile} from '@shopify/cli-kit/node/fs' +import {inTemporaryDirectory, writeFile, readFile} from '@shopify/cli-kit/node/fs' import {joinPath} from '@shopify/cli-kit/node/path' import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest' @@ -39,7 +39,6 @@ vi.mock('@shopify/cli-kit/node/ui', async () => { renderInfo: vi.fn(), } }) -vi.mock('@shopify/cli-kit/node/fs') vi.mock('@shopify/cli-kit/node/session', async () => { const actual = await vi.importActual('@shopify/cli-kit/node/session') return { @@ -276,6 +275,7 @@ describe('executeBulkOperation', () => { adminSession: mockAdminSession, query: mutation, variablesJsonl: variables.join('\n'), + version: BULK_OPERATIONS_MIN_API_VERSION, }) }) }) @@ -552,36 +552,39 @@ describe('executeBulkOperation', () => { ) test('writes results to file when --output-file flag is provided', async () => { - const query = '{ products { edges { node { id } } } }' - const outputFile = '/tmp/results.jsonl' - const resultsContent = - '{"data":{"productCreate":{"product":{"id":"gid://shopify/Product/123"},"userErrors":[]}},"__lineNumber":0}\n{"data":{"productCreate":{"product":{"id":"gid://shopify/Product/456"},"userErrors":[]}},"__lineNumber":1}' + await inTemporaryDirectory(async (tmpDir) => { + const query = '{ products { edges { node { id } } } }' + const outputFile = joinPath(tmpDir, 'results.jsonl') + const resultsContent = + '{"data":{"productCreate":{"product":{"id":"gid://shopify/Product/123"},"userErrors":[]}},"__lineNumber":0}\n{"data":{"productCreate":{"product":{"id":"gid://shopify/Product/456"},"userErrors":[]}},"__lineNumber":1}' - const initialResponse: BulkOperationRunQueryMutation['bulkOperationRunQuery'] = { - bulkOperation: createdBulkOperation, - userErrors: [], - } - const completedOperation = { - ...createdBulkOperation, - status: 'COMPLETED' as const, - url: 'https://example.com/download', - objectCount: '2', - } + const initialResponse: BulkOperationRunQueryMutation['bulkOperationRunQuery'] = { + bulkOperation: createdBulkOperation, + userErrors: [], + } + const completedOperation = { + ...createdBulkOperation, + status: 'COMPLETED' as const, + url: 'https://example.com/download', + objectCount: '2', + } - vi.mocked(runBulkOperationQuery).mockResolvedValue(initialResponse) - vi.mocked(watchBulkOperation).mockResolvedValue(completedOperation) - vi.mocked(downloadBulkOperationResults).mockResolvedValue(resultsContent) + vi.mocked(runBulkOperationQuery).mockResolvedValue(initialResponse) + vi.mocked(watchBulkOperation).mockResolvedValue(completedOperation) + vi.mocked(downloadBulkOperationResults).mockResolvedValue(resultsContent) - await executeBulkOperation({ - organization: mockOrganization, - remoteApp: mockRemoteApp, - store: mockStore, - query, - watch: true, - outputFile, - }) + await executeBulkOperation({ + organization: mockOrganization, + remoteApp: mockRemoteApp, + store: mockStore, + query, + watch: true, + outputFile, + }) - expect(writeFile).toHaveBeenCalledWith(outputFile, resultsContent) + const content = await readFile(outputFile) + expect(content).toBe(resultsContent) + }) }) test('writes results to stdout when --output-file flag is not provided', async () => { @@ -615,7 +618,6 @@ describe('executeBulkOperation', () => { }) expect(mockOutput.info()).toContain(resultsContent) - expect(writeFile).not.toHaveBeenCalled() }) test.each(['FAILED', 'CANCELED', 'EXPIRED'] as const)( @@ -748,41 +750,45 @@ describe('executeBulkOperation', () => { }) test('renders warning when results written to file contain userErrors', async () => { - const query = '{ products { edges { node { id } } } }' - const outputFile = '/tmp/results.jsonl' - const resultsWithErrors = '{"data":{"productUpdate":{"userErrors":[{"message":"invalid input"}]}},"__lineNumber":0}' + await inTemporaryDirectory(async (tmpDir) => { + const query = '{ products { edges { node { id } } } }' + const outputFile = joinPath(tmpDir, 'results.jsonl') + const resultsWithErrors = + '{"data":{"productUpdate":{"userErrors":[{"message":"invalid input"}]}},"__lineNumber":0}' - const initialResponse: BulkOperationRunQueryMutation['bulkOperationRunQuery'] = { - bulkOperation: createdBulkOperation, - userErrors: [], - } - const completedOperation = { - ...createdBulkOperation, - status: 'COMPLETED' as const, - url: 'https://example.com/download', - objectCount: '1', - } + const initialResponse: BulkOperationRunQueryMutation['bulkOperationRunQuery'] = { + bulkOperation: createdBulkOperation, + userErrors: [], + } + const completedOperation = { + ...createdBulkOperation, + status: 'COMPLETED' as const, + url: 'https://example.com/download', + objectCount: '1', + } - vi.mocked(runBulkOperationQuery).mockResolvedValue(initialResponse) - vi.mocked(watchBulkOperation).mockResolvedValue(completedOperation) - vi.mocked(downloadBulkOperationResults).mockResolvedValue(resultsWithErrors) + vi.mocked(runBulkOperationQuery).mockResolvedValue(initialResponse) + vi.mocked(watchBulkOperation).mockResolvedValue(completedOperation) + vi.mocked(downloadBulkOperationResults).mockResolvedValue(resultsWithErrors) - await executeBulkOperation({ - organization: mockOrganization, - remoteApp: mockRemoteApp, - store: mockStore, - query, - watch: true, - outputFile, - }) + await executeBulkOperation({ + organization: mockOrganization, + remoteApp: mockRemoteApp, + store: mockStore, + query, + watch: true, + outputFile, + }) - expect(writeFile).toHaveBeenCalledWith(outputFile, resultsWithErrors) - expect(renderWarning).toHaveBeenCalledWith( - expect.objectContaining({ - headline: 'Bulk operation completed with errors.', - body: `Results written to ${outputFile}. Check file for error details.`, - }), - ) + const content = await readFile(outputFile) + expect(content).toBe(resultsWithErrors) + expect(renderWarning).toHaveBeenCalledWith( + expect.objectContaining({ + headline: 'Bulk operation completed with errors.', + body: `Results written to ${outputFile}. Check file for error details.`, + }), + ) + }) }) test('calls resolveApiVersion with minimum API version constant', async () => {