From c68f0b494c2383f52a94890affc698e3798f8d2d Mon Sep 17 00:00:00 2001 From: Anso Date: Tue, 2 Jun 2026 21:54:01 -0400 Subject: [PATCH] test(stacks): drain pending download-metric records between tests (#1293) The "records the download metric exactly once" test in stack-files-routes intermittently failed with "expected 2 to be 1". The download route records its metric asynchronously, on the file stream's end/close and the response's close event, so a prior download test's record could land after the next test called resetFileExplorerMetrics(), leaking a count across the reset. The route's per-request recording is correct (a synchronous guard); the leak was purely cross-test in the suite. Add an afterEach in the download suite that waits for the download count to settle (bounded poll) before the next test runs, so no pending record survives the reset, and assert the count actually settled so a runaway record surfaces rather than being silently swallowed. --- .../src/__tests__/stack-files-routes.test.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/backend/src/__tests__/stack-files-routes.test.ts b/backend/src/__tests__/stack-files-routes.test.ts index d4d4acd6..555cb007 100644 --- a/backend/src/__tests__/stack-files-routes.test.ts +++ b/backend/src/__tests__/stack-files-routes.test.ts @@ -15,7 +15,7 @@ * Community-tier success, input validation, upload size limit, and happy-path * 204/200 responses. */ -import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach, vi } from 'vitest'; import request from 'supertest'; import bcrypt from 'bcrypt'; import { promises as fs } from 'fs'; @@ -406,6 +406,26 @@ describe('GET /api/stacks/:stackName/files/content', () => { // ── GET /:stackName/files/download ──────────────────────────────────────────── describe('GET /api/stacks/:stackName/files/download', () => { + // The download metric is recorded asynchronously, on the file stream's + // end/close and the response's close event, so it can land after a test's + // request has already resolved. Drain any such pending record before the next + // test runs: a prior download must not leak a count across the next test's + // resetFileExplorerMetrics() and inflate its "exactly once" assertion. Poll + // until the download count holds steady across several reads (bounded). + afterEach(async () => { + let prev = -1; + let stableReads = 0; + for (let i = 0; i < 50 && stableReads < 3; i++) { + const current = (await getDownloadMetric())?.count ?? 0; + stableReads = current === prev ? stableReads + 1 : 0; + prev = current; + await new Promise((resolve) => setTimeout(resolve, 10)); + } + // If the count never settled, a record is firing repeatedly (a real bug); + // surface it here rather than letting the bound silently swallow it. + expect(stableReads).toBeGreaterThanOrEqual(3); + }); + class CloseBeforeEndStream extends Readable { public bytesRead: number;