From 8b7f433553e4ea9ac82c23137bf19ac32e547761 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:40:15 +0000 Subject: [PATCH] Cover the bulk operations status table formatting The text-mode table rendered by `renderBulkOperationStatusResult` had no direct coverage: the count abbreviation thresholds, the ID shortening, the date columns, and the results-link fallback were never asserted. Co-Authored-By: Claude Opus 4.8 --- .../cli/services/store/bulk/result.test.ts | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/packages/store/src/cli/services/store/bulk/result.test.ts b/packages/store/src/cli/services/store/bulk/result.test.ts index ee452cd01c2..16b79d2811d 100644 --- a/packages/store/src/cli/services/store/bulk/result.test.ts +++ b/packages/store/src/cli/services/store/bulk/result.test.ts @@ -42,6 +42,17 @@ function completedResult(): ExecuteBulkOperationResult { } } +// The list query omits the operation type. +function listedOperation() { + const {type: _type, ...operation} = completedResult().operation! + return { + ...operation, + id: 'gid://shopify/BulkOperation/1', + createdAt: '2025-11-10T12:37:52Z', + completedAt: '2025-11-10T16:37:12Z', + } +} + test('preserves raw counts, nullable fields, and omitted fields through encoding', () => { const result = completedResult() const {completedAt: _completedAt, ...operation} = result.operation! @@ -195,6 +206,70 @@ test('outputs status JSON without a table or terminal banners', () => { expect(renderInfo).not.toHaveBeenCalled() }) +test.each([ + [999, '999'], + [1000, '1.0K'], + [123500, '123.5K'], + [999999, '1000.0K'], + [1000000, '1.0M'], + [2450000, '2.5M'], +])('abbreviates an object count of %i as %s in the table', (objectCount, expectedCount) => { + renderBulkOperationStatusResult({operations: [{...listedOperation(), objectCount}]}, 'text') + + expect(renderTable).toHaveBeenCalledWith( + expect.objectContaining({rows: [expect.objectContaining({count: expectedCount})]}), + ) +}) + +test('shortens the operation ID and links the results for a completed operation', () => { + renderBulkOperationStatusResult({operations: [listedOperation()]}, 'text') + + expect(renderTable).toHaveBeenCalledWith( + expect.objectContaining({ + rows: [ + expect.objectContaining({ + id: '1', + status: expect.stringContaining('COMPLETED'), + dateCreated: '2025-11-10 12:37:52', + dateFinished: '2025-11-10 16:37:12', + results: expect.stringContaining('https://example.com/results.jsonl'), + }), + ], + }), + ) +}) + +test('falls back to the partial results link while an operation is unfinished', () => { + const operation = { + ...listedOperation(), + status: 'FAILED' as const, + completedAt: undefined, + url: null, + partialDataUrl: 'https://example.com/partial.jsonl', + } + + renderBulkOperationStatusResult({operations: [operation]}, 'text') + + expect(renderTable).toHaveBeenCalledWith( + expect.objectContaining({ + rows: [ + expect.objectContaining({ + dateFinished: '', + results: expect.stringContaining('https://example.com/partial.jsonl'), + }), + ], + }), + ) +}) + +test('leaves the results cell empty when an operation has no download links', () => { + const operation = {...listedOperation(), status: 'RUNNING' as const, url: null, partialDataUrl: null} + + renderBulkOperationStatusResult({operations: [operation]}, 'text') + + expect(renderTable).toHaveBeenCalledWith(expect.objectContaining({rows: [expect.objectContaining({results: ''})]})) +}) + test('keeps missing status and cancellation results nonfatal in text mode', () => { const exitCode = process.exitCode renderBulkOperationStatusResult({operationId: '123', operation: null}, 'text')