diff --git a/src/app/core/services/package-actions.service.spec.ts b/src/app/core/services/package-actions.service.spec.ts index 953e00f..f66f963 100644 --- a/src/app/core/services/package-actions.service.spec.ts +++ b/src/app/core/services/package-actions.service.spec.ts @@ -47,9 +47,55 @@ describe('PackageActionsService', () => { it('runs batch upgrade and shows toast', async () => { const service = TestBed.inject(PackageActionsService); - await service.upgradeMany({ items: [{ kind: 'formula', name: 'ripgrep' }] }); + await service.upgradeMany({ + items: [ + { kind: 'formula', name: 'ripgrep' }, + { kind: 'formula', name: 'node' } + ] + }); expect(facade.upgradeMany).toHaveBeenCalled(); - expect(toast.push).toHaveBeenCalledWith(expect.stringContaining('Batch upgrade'), 'success'); + expect(toast.push).toHaveBeenCalledWith( + 'Batch upgrade finished (2/2 succeeded).', + 'success' + ); + }); + + it('shows error toasts for partial batch failures', async () => { + const service = TestBed.inject(PackageActionsService); + facade.upgradeMany.mockResolvedValueOnce({ succeeded: 1, failed: 1, results: [] }); + facade.uninstallMany.mockResolvedValueOnce({ succeeded: 1, failed: 2, results: [] }); + facade.pinMany.mockResolvedValueOnce({ succeeded: 0, failed: 1, results: [] }); + + await service.upgradeMany({ + items: [ + { kind: 'formula', name: 'ripgrep' }, + { kind: 'formula', name: 'node' } + ] + }); + await service.uninstallMany({ + items: [ + { kind: 'formula', name: 'ripgrep' }, + { kind: 'formula', name: 'node' }, + { kind: 'cask', name: 'firefox' } + ] + }); + await service.pinMany({ items: [{ kind: 'formula', name: 'node' }] }); + + expect(toast.push).toHaveBeenNthCalledWith( + 1, + 'Batch upgrade finished with failures (1/2 succeeded).', + 'error' + ); + expect(toast.push).toHaveBeenNthCalledWith( + 2, + 'Batch uninstall finished with failures (1/3 succeeded).', + 'error' + ); + expect(toast.push).toHaveBeenNthCalledWith( + 3, + 'Batch pin finished with failures (0/1 succeeded).', + 'error' + ); }); it('shows pin undo toast', () => { diff --git a/src/app/core/services/package-actions.service.ts b/src/app/core/services/package-actions.service.ts index 22fa0f4..6676439 100644 --- a/src/app/core/services/package-actions.service.ts +++ b/src/app/core/services/package-actions.service.ts @@ -139,31 +139,28 @@ export class PackageActionsService { async upgradeMany(request: BatchManyRequest): Promise { const result = await this.facade.upgradeMany(request); - this.toast.push( - `Batch upgrade finished (${result.succeeded}/${request.items.length} succeeded).`, - 'success' - ); + this.notifyBatchResult('upgrade', result, request.items.length); return result; } async uninstallMany(request: BatchManyRequest): Promise { const result = await this.facade.uninstallMany(request); - this.toast.push( - `Batch uninstall finished (${result.succeeded}/${request.items.length} succeeded).`, - 'success' - ); + this.notifyBatchResult('uninstall', result, request.items.length); return result; } async pinMany(request: BatchManyRequest): Promise { const result = await this.facade.pinMany(request); - this.toast.push( - `Batch pin finished (${result.succeeded}/${request.items.length} succeeded).`, - 'success' - ); + this.notifyBatchResult('pin', result, request.items.length); return result; } + private notifyBatchResult(action: 'upgrade' | 'uninstall' | 'pin', result: BatchJobResult, total: number): void { + const outcome = result.failed > 0 ? 'finished with failures' : 'finished'; + const kind = result.failed > 0 ? 'error' : 'success'; + this.toast.push(`Batch ${action} ${outcome} (${result.succeeded}/${total} succeeded).`, kind); + } + notifyPinSuccess(request: PinOneRequest): void { this.toast.pushWithAction(`Pinned ${request.name}.`, 'success', { label: 'Unpin',