From 0429b492ea22a118479ae900d016eaef6aca8299 Mon Sep 17 00:00:00 2001 From: saltbo Date: Wed, 5 Aug 2026 11:26:42 -0400 Subject: [PATCH] fix(test): make coverage sorting proof deterministic --- .github/workflows/ci.yml | 30 +++++++++++----- .../adapters/repos/matter.integration.test.ts | 36 +++++++++++++++---- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2028707..1f76e671 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,12 +78,22 @@ jobs: fail-fast: false matrix: include: - - label: Unit + - label: Unit (1/2) project: unit - report: unit - - label: Integration + shard: 1 + report: unit-1 + - label: Unit (2/2) + project: unit + shard: 2 + report: unit-2 + - label: Integration (1/2) project: integration - report: integration + shard: 1 + report: integration-1 + - label: Integration (2/2) + project: integration + shard: 2 + report: integration-2 steps: - uses: actions/checkout@v6 - uses: pnpm/action-setup@v4 @@ -95,7 +105,7 @@ jobs: - name: Run tests with coverage # Passing tests produce hundreds of KB of intentional request/error logs. # Keep captured output for failures without paying to stream every success. - run: pnpm exec vitest run --project ${{ matrix.project }} --silent=passed-only --coverage --coverage.reportsDirectory=coverage/${{ matrix.report }} --reporter=default --reporter=blob --outputFile.blob=.vitest-reports/${{ matrix.report }}.blob + run: pnpm exec vitest run --project ${{ matrix.project }} --shard=${{ matrix.shard }}/2 --silent=passed-only --coverage --coverage.reportsDirectory=coverage/${{ matrix.report }} --reporter=default --reporter=blob --outputFile.blob=.vitest-reports/${{ matrix.report }}.blob - uses: actions/upload-artifact@v4 if: always() with: @@ -138,11 +148,13 @@ jobs: pattern: vitest-coverage-* path: .vitest-reports merge-multiple: true - - name: Verify both coverage reports are present + - name: Verify every coverage shard is present run: | - test -f .vitest-reports/unit.blob - test -f .vitest-reports/integration.blob - test "$(find .vitest-reports -type f -name '*.blob' | wc -l)" -eq 2 + test -f .vitest-reports/unit-1.blob + test -f .vitest-reports/unit-2.blob + test -f .vitest-reports/integration-1.blob + test -f .vitest-reports/integration-2.blob + test "$(find .vitest-reports -type f -name '*.blob' | wc -l)" -eq 4 - name: Merge coverage and enforce thresholds env: COVERAGE_ENFORCE: '1' diff --git a/server/adapters/repos/matter.integration.test.ts b/server/adapters/repos/matter.integration.test.ts index 6d8c3edf..3a36cf90 100644 --- a/server/adapters/repos/matter.integration.test.ts +++ b/server/adapters/repos/matter.integration.test.ts @@ -507,12 +507,23 @@ describe('updateMatter', () => { async function insertTrashedMatter( db: TestDb, orgId: string, - opts: { id: string; alias: string; name: string; parent: string; dirtype: number; storageId: string }, + opts: { + id: string + alias: string + name: string + parent: string + dirtype: number + storageId: string + trashedAt?: number + createdAt?: number + }, ) { const now = Date.now() + const trashedAt = opts.trashedAt ?? now + const createdAt = opts.createdAt ?? now await db.run(sql` INSERT INTO matters (id, org_id, alias, name, type, size, dirtype, parent, object, storage_id, status, trashed_at, created_at, updated_at) - VALUES (${opts.id}, ${orgId}, ${opts.alias}, ${opts.name}, 'text/plain', 0, ${opts.dirtype}, ${opts.parent}, '', ${opts.storageId}, 'active', ${now}, ${now}, ${now}) + VALUES (${opts.id}, ${orgId}, ${opts.alias}, ${opts.name}, 'text/plain', 0, ${opts.dirtype}, ${opts.parent}, '', ${opts.storageId}, 'active', ${trashedAt}, ${createdAt}, ${now}) `) } @@ -574,7 +585,7 @@ describe('listTrashedRoots', () => { expect(ids).not.toContain('file-in-b') }) - it('returns multiple independent trashed items when none is a descendant of another', async () => { + it('orders independent roots by trashed time and then creation time', async () => { const { db } = await createTestApp() const orgId = nanoid() const storageId = await insertStorage(db, { id: 'st-trash3' }) @@ -586,6 +597,8 @@ describe('listTrashedRoots', () => { parent: '', dirtype: 0, storageId, + trashedAt: 1_000, + createdAt: 1_000, }) await insertTrashedMatter(db, orgId, { id: 'item-y', @@ -594,14 +607,23 @@ describe('listTrashedRoots', () => { parent: '', dirtype: 0, storageId, + trashedAt: 2_000, + createdAt: 1_000, + }) + await insertTrashedMatter(db, orgId, { + id: 'item-z', + alias: 'item-z-alias', + name: 'Z', + parent: '', + dirtype: 0, + storageId, + trashedAt: 2_000, + createdAt: 2_000, }) const roots = await listTrashedRoots(db, orgId) - const ids = roots.map((m) => m.id) - expect(ids).toContain('item-x') - expect(ids).toContain('item-y') - expect(roots).toHaveLength(2) + expect(roots.map((matter) => matter.id)).toEqual(['item-z', 'item-y', 'item-x']) }) it('returns an empty array when no trashed items exist for the org', async () => {