|
| 1 | +import {cancelBulkOperation} from './cancel-bulk-operation.js' |
| 2 | +import {createAdminSessionAsApp, formatOperationInfo} from '../graphql/common.js' |
| 3 | +import {OrganizationApp, Organization, OrganizationSource} from '../../models/organization.js' |
| 4 | +import {describe, test, expect, vi, beforeEach, afterEach} from 'vitest' |
| 5 | +import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' |
| 6 | +import {adminRequestDoc} from '@shopify/cli-kit/node/api/admin' |
| 7 | +import {renderInfo, renderError, renderSuccess, renderWarning} from '@shopify/cli-kit/node/ui' |
| 8 | + |
| 9 | +vi.mock('../graphql/common.js') |
| 10 | +vi.mock('@shopify/cli-kit/node/api/admin') |
| 11 | +vi.mock('@shopify/cli-kit/node/ui') |
| 12 | + |
| 13 | +describe('cancelBulkOperation', () => { |
| 14 | + const mockOrganization: Organization = { |
| 15 | + id: 'test-org-id', |
| 16 | + businessName: 'Test Organization', |
| 17 | + source: OrganizationSource.BusinessPlatform, |
| 18 | + } |
| 19 | + |
| 20 | + const mockRemoteApp = { |
| 21 | + apiKey: 'test-app-client-id', |
| 22 | + apiSecretKeys: [{secret: 'test-api-secret'}], |
| 23 | + title: 'Test App', |
| 24 | + } as OrganizationApp |
| 25 | + |
| 26 | + const storeFqdn = 'test-store.myshopify.com' |
| 27 | + const operationId = 'gid://shopify/BulkOperation/123' |
| 28 | + const mockAdminSession = {token: 'test-token', storeFqdn} |
| 29 | + |
| 30 | + beforeEach(() => { |
| 31 | + vi.mocked(createAdminSessionAsApp).mockResolvedValue(mockAdminSession) |
| 32 | + vi.mocked(formatOperationInfo).mockReturnValue([ |
| 33 | + `Organization: ${mockOrganization.businessName}`, |
| 34 | + `App: ${mockRemoteApp.title}`, |
| 35 | + `Store: ${storeFqdn}`, |
| 36 | + ]) |
| 37 | + }) |
| 38 | + |
| 39 | + afterEach(() => { |
| 40 | + mockAndCaptureOutput().clear() |
| 41 | + }) |
| 42 | + |
| 43 | + test('renders initial info message with operation details', async () => { |
| 44 | + vi.mocked(adminRequestDoc).mockResolvedValue({ |
| 45 | + bulkOperationCancel: { |
| 46 | + bulkOperation: { |
| 47 | + id: operationId, |
| 48 | + status: 'CANCELING', |
| 49 | + createdAt: '2024-01-01T00:00:00Z', |
| 50 | + completedAt: null, |
| 51 | + }, |
| 52 | + userErrors: [], |
| 53 | + }, |
| 54 | + }) |
| 55 | + |
| 56 | + await cancelBulkOperation({organization: mockOrganization, storeFqdn, operationId, remoteApp: mockRemoteApp}) |
| 57 | + |
| 58 | + expect(renderInfo).toHaveBeenCalledWith( |
| 59 | + expect.objectContaining({ |
| 60 | + headline: 'Canceling bulk operation.', |
| 61 | + }), |
| 62 | + ) |
| 63 | + }) |
| 64 | + |
| 65 | + test('calls adminRequestDoc with correct parameters', async () => { |
| 66 | + vi.mocked(adminRequestDoc).mockResolvedValue({ |
| 67 | + bulkOperationCancel: { |
| 68 | + bulkOperation: { |
| 69 | + id: operationId, |
| 70 | + status: 'CANCELING', |
| 71 | + createdAt: '2024-01-01T00:00:00Z', |
| 72 | + completedAt: null, |
| 73 | + }, |
| 74 | + userErrors: [], |
| 75 | + }, |
| 76 | + }) |
| 77 | + |
| 78 | + await cancelBulkOperation({organization: mockOrganization, storeFqdn, operationId, remoteApp: mockRemoteApp}) |
| 79 | + |
| 80 | + expect(adminRequestDoc).toHaveBeenCalledWith({ |
| 81 | + query: expect.any(Object), |
| 82 | + session: mockAdminSession, |
| 83 | + variables: {id: operationId}, |
| 84 | + version: '2026-01', |
| 85 | + }) |
| 86 | + }) |
| 87 | + |
| 88 | + test.each([ |
| 89 | + { |
| 90 | + status: 'CANCELING' as const, |
| 91 | + renderer: 'renderSuccess', |
| 92 | + headline: 'Bulk operation is being cancelled.', |
| 93 | + }, |
| 94 | + { |
| 95 | + status: 'CANCELED' as const, |
| 96 | + renderer: 'renderWarning', |
| 97 | + headline: 'Bulk operation is already canceled.', |
| 98 | + }, |
| 99 | + { |
| 100 | + status: 'COMPLETED' as const, |
| 101 | + renderer: 'renderWarning', |
| 102 | + headline: 'Bulk operation is already completed.', |
| 103 | + }, |
| 104 | + { |
| 105 | + status: 'RUNNING' as const, |
| 106 | + renderer: 'renderInfo', |
| 107 | + headline: 'Bulk operation in progress', |
| 108 | + }, |
| 109 | + ])('renders $renderer for $status status', async ({status, renderer, headline}) => { |
| 110 | + vi.mocked(adminRequestDoc).mockResolvedValue({ |
| 111 | + bulkOperationCancel: { |
| 112 | + bulkOperation: { |
| 113 | + id: operationId, |
| 114 | + status, |
| 115 | + createdAt: '2024-01-01T00:00:00Z', |
| 116 | + completedAt: status === 'CANCELING' || status === 'RUNNING' ? null : '2024-01-01T01:00:00Z', |
| 117 | + }, |
| 118 | + userErrors: [], |
| 119 | + }, |
| 120 | + }) |
| 121 | + |
| 122 | + await cancelBulkOperation({organization: mockOrganization, storeFqdn, operationId, remoteApp: mockRemoteApp}) |
| 123 | + |
| 124 | + const rendererFn = {renderSuccess, renderWarning, renderInfo}[renderer] |
| 125 | + expect(rendererFn).toHaveBeenCalledWith( |
| 126 | + expect.objectContaining({ |
| 127 | + headline: expect.stringContaining(headline), |
| 128 | + }), |
| 129 | + ) |
| 130 | + }) |
| 131 | + |
| 132 | + test('renders user errors when present', async () => { |
| 133 | + vi.mocked(adminRequestDoc).mockResolvedValue({ |
| 134 | + bulkOperationCancel: { |
| 135 | + bulkOperation: null, |
| 136 | + userErrors: [{field: ['id'], message: 'Operation not found'}], |
| 137 | + }, |
| 138 | + }) |
| 139 | + |
| 140 | + await cancelBulkOperation({organization: mockOrganization, storeFqdn, operationId, remoteApp: mockRemoteApp}) |
| 141 | + |
| 142 | + expect(renderError).toHaveBeenCalledWith({ |
| 143 | + headline: 'Bulk operation cancellation errors.', |
| 144 | + body: 'id: Operation not found', |
| 145 | + }) |
| 146 | + }) |
| 147 | + |
| 148 | + test('renders error when no operation is returned and no user errors', async () => { |
| 149 | + vi.mocked(adminRequestDoc).mockResolvedValue({ |
| 150 | + bulkOperationCancel: { |
| 151 | + bulkOperation: null, |
| 152 | + userErrors: [], |
| 153 | + }, |
| 154 | + }) |
| 155 | + |
| 156 | + await cancelBulkOperation({organization: mockOrganization, storeFqdn, operationId, remoteApp: mockRemoteApp}) |
| 157 | + |
| 158 | + expect(renderError).toHaveBeenCalledWith( |
| 159 | + expect.objectContaining({ |
| 160 | + headline: 'Bulk operation not found or could not be canceled.', |
| 161 | + }), |
| 162 | + ) |
| 163 | + }) |
| 164 | +}) |
0 commit comments