chore: run daily test audit (failed due to timeout)

- Ran unit tests with c8 coverage.
- Tests timed out after 400s.
- Identified `tests/profile-modal-controller.test.mjs` as a major bottleneck (>60s).
- Collected partial coverage and static analysis artifacts.
- Created failure log.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-17 16:51:02 +00:00
1 parent c66c231e1b
commit 92a41ff8e7
11 files changed
+355 -8

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
# Daily Test Audit Context
Goal: Run daily test audit to detect flaky tests, coverage gaps, and suspicious patterns.
Scope: All unit tests in `tests/`.
Definition of Done:
- `test-audit-report-YYYY-MM-DD.md` generated.
- `test-audit/` artifacts populated.
- Tests run at least 3 times.
@@ -0,0 +1,4 @@
# Decisions Log
- Using `npx c8` for coverage if available, falling back to basic test run.
- Using simple grep for static analysis to avoid complex parsing in script.
@@ -0,0 +1,16 @@
# Daily Test Audit Agent: Failed
**Agent:** `test-audit-agent`
**Date:** 2026-02-17
**Status:** Failed (Timeout)
## Summary
The daily test audit was attempted but the full unit test suite timed out after 400s.
Partial coverage data was collected.
## Key Findings
- **Critical Slowness:** `tests/profile-modal-controller.test.mjs` takes >60s to run, causing the suite to hang/timeout.
- **Coverage:** Partial coverage data available in `test-audit/coverage-run.log`.
- **Static Analysis:** Found numerous `setTimeout` usages.
See `test-audit/test-audit-report-2026-02-17.md` for details.
+40
View File
@@ -0,0 +1,40 @@
tests/subscriptions-feed.test.mjs:console.log("subscriptions-feed tests passed");
tests/webtorrent-regression.test.mjs: console.log("Failed result:", result);
tests/nostr-publish-rejection.test.mjs: console.log("nostr publish rejection tests passed");
tests/zap-shared-state.test.mjs:console.log("zap-shared-state tests passed");
tests/view-counter.test.mjs:console.log("View counter tests completed successfully.");
tests/watch-history-feed.test.mjs:console.log("watch-history-feed.test.mjs completed successfully.");
tests/app-batch-fetch-profiles.test.mjs: // console.log("pool.list called with relays:", relays);
tests/app-batch-fetch-profiles.test.mjs: // console.log("poolListCalls.length:", poolListCalls.length);
tests/app-batch-fetch-profiles.test.mjs: // console.log("nostrClient.relays:", nostrClient.relays);
tests/feed-engine.test.mjs:console.log("All feed engine tests passed");
tests/utils/domUtils.test.mjs: inlineScript.textContent = "console.log('hello')";
tests/utils/domUtils.test.mjs: assert.equal(container.querySelector("script").textContent, "console.log('hello')");
tests/nostr-rebroadcast-guard.test.mjs:console.log("nostr rebroadcast guard tests passed");
tests/nostr-boost-actions.test.mjs:console.log("nostr boost action tests passed");
tests/zap-split.test.mjs:console.log("zap-split tests passed");
tests/watch-history.test.mjs: console.log("Running normalizeActorKey short-circuit test...");
tests/watch-history.test.mjs: console.log("Running normalizeActorKey manual fallback test...");
tests/watch-history.test.mjs: console.log("Running watch history snapshot inflight queue retention test...");
tests/watch-history.test.mjs: console.log("Running watch history snapshot merge test...");
tests/watch-history.test.mjs: console.log("Running watch history card playback metadata test...");
tests/watch-history.test.mjs: console.log("Running watch history stale cache refresh test...");
tests/watch-history.test.mjs: console.log("Running watch history local fallback test...");
tests/watch-history.test.mjs: console.log("Running watch history renderer feed registration fallback test...");
tests/watch-history.test.mjs: console.log("Running watch history logged-in sync override test...");
tests/watch-history.test.mjs: console.log("Running watch history app login fallback test...");
tests/watch-history.test.mjs: console.log("Running watch history feed hydration test...");
tests/watch-history.test.mjs:console.log("watch-history.test.mjs completed successfully");
tests/discussion-count-service.test.mjs:console.log("discussion-count-service tests passed");
tests/nostr-view-events.test.mjs:console.log("nostr view events tests passed");
tests/admin-list-store.test.mjs:console.log("admin-list-store tests passed");
tests/nostr-count-fallback.test.mjs:console.log("nostr COUNT fallback tests completed successfully.");
tests/nostr-view-event-bindings.test.mjs:console.log("nostr-view-event-bindings tests passed");
tests/ui/components/debug_hashtag_strip_helper.test.mjs: console.log(`DEBUG: window.addEventListener('${event}') called`);
tests/ui/components/debug_hashtag_strip_helper.test.mjs: console.log("Global ResizeObserver type:", typeof globalThis.ResizeObserver);
tests/ui/components/debug_hashtag_strip_helper.test.mjs: console.log("Helper window ResizeObserver:", typeof helper.window.ResizeObserver);
tests/ui/uploadModal-reset.test.mjs: global.alert = (msg) => { console.log("ALERT CALLED:", msg); };
tests/ui/profileModalController-addProfile.test.mjs: showSuccess: (msg) => { console.log("Success:", msg); },
tests/performance/resolvePostedAt.test.mjs: console.log(`pool.list calls: ${listCalls}`);
tests/performance/resolvePostedAt.test.mjs: console.log(`pool.get calls: ${getCalls}`);
tests/nostr-delete-flow.test.mjs:console.log("nostr delete flow tests passed");
+226
View File
@@ -0,0 +1,226 @@
tests/video-modal-zap.test.mjs:if (typeof globalThis.fetch === "undefined") {
tests/video-modal-zap.test.mjs: globalThis.fetch = async () => {
tests/video-modal-zap.test.mjs: throw new Error("Unexpected fetch call in tests.");
tests/video-modal-zap.test.mjs: fetchedAt: Date.now(),
tests/subscriptions-feed.test.mjs: throw new Error("should not fetch active videos when authors missing");
tests/video-modal-accessibility.test.mjs: const originalFetch = globalThis.fetch;
tests/video-modal-accessibility.test.mjs: globalThis.fetch = async (resource, init) => {
tests/video-modal-accessibility.test.mjs: throw new Error(`Unexpected fetch request in tests: ${String(url || resource)}`);
tests/video-modal-accessibility.test.mjs: globalThis.fetch = originalFetch;
tests/video-modal-accessibility.test.mjs: delete globalThis.fetch;
tests/view-counter.test.mjs: "hydration should fetch fresh data from relays even if cache was preserved"
tests/view-counter.test.mjs: "hydrateVideoHistory should fetch the root event when it is missing locally"
tests/view-counter.test.mjs: const fetchedRoot = history.find((entry) => entry.id === rootId);
tests/view-counter.test.mjs: assert.ok(fetchedRoot, "history should include the fetched root event");
tests/view-counter.test.mjs: fetchedRoot.created_at,
tests/subscriptions-manager.test.mjs: const originalFetchIncremental = nostrClient.fetchListIncrementally;
tests/subscriptions-manager.test.mjs: nostrClient.fetchListIncrementally = async () => [event];
tests/subscriptions-manager.test.mjs: nostrClient.fetchListIncrementally = originalFetchIncremental;
tests/nostr/client.test.mjs: describe("fetchListIncrementally", () => {
tests/nostr/client.test.mjs: it("should fetch events and deduplicate results", async () => {
tests/nostr/client.test.mjs: const events = await client.fetchListIncrementally({
tests/nostr/client.test.mjs: await client.fetchListIncrementally({
tests/nostr/client.test.mjs: await client.fetchListIncrementally({
tests/nostr/client.test.mjs: it("should force full fetch if since is 0", async () => {
tests/nostr/client.test.mjs: await client.fetchListIncrementally({
tests/nostr/client.test.mjs: since: 0 // Force full fetch
tests/nostr/client.test.mjs: describe("fetchVideos", () => {
tests/nostr/client.test.mjs: const result = await client.fetchVideos({ limit: 5 });
tests/nostr/client.test.mjs: // Ensure we force full fetch by default
tests/nostr/client.test.mjs: await client.fetchVideos({ since: 12345 });
tests/nostr/client.test.mjs: // and focus on `fetch`/`subscribe` which use `this.pool`.
tests/nostr/watchHistory.test.js: fetchWatchHistory,
tests/nostr/watchHistory.test.js:test("fetchWatchHistory prefers decrypted chunk payloads when nip04 decrypt succeeds", async () => {
tests/nostr/watchHistory.test.js: const result = await fetchWatchHistory(manager, actorHex, { forceRefresh: true });
tests/nostr/watchHistory.test.js:test("fetchWatchHistory falls back to pointer payload when nip04 decrypt fails", async () => {
tests/nostr/watchHistory.test.js: const result = await fetchWatchHistory(manager, actorHex, { forceRefresh: true });
tests/nostr/nip71.test.js:test("populateNip71MetadataForVideos fetches missing records once", async () => {
tests/nostr/nip71.test.js: let fetchCalls = 0;
tests/nostr/nip71.test.js: const fetchMetadata = async (map, pointerValues) => {
tests/nostr/nip71.test.js: fetchCalls += 1;
tests/nostr/nip71.test.js: fetchMetadata,
tests/nostr/nip71.test.js: assert.equal(fetchCalls, 1);
tests/nostr/nip71.test.js: assert.ok(cacheEntry?.fetchedPointers.has(pointerValue));
tests/nostr/nip71.test.js: fetchMetadata,
tests/nostr/nip71.test.js: assert.equal(fetchCalls, 1, "cached pointer should skip subsequent fetches");
tests/torrent/service-worker-fallback-message.test.mjs: "Failed to register ServiceWorker: TypeError: Failed to fetch"
tests/hashtag-preferences.test.mjs: // Note: fetchListIncrementally calls pool.list separately for each kind
tests/hashtag-preferences.test.mjs: const originalFetchIncremental = nostrClient.fetchListIncrementally;
tests/hashtag-preferences.test.mjs: let fetchCalls = 0;
tests/hashtag-preferences.test.mjs: fetchCalls = 0;
tests/hashtag-preferences.test.mjs: nostrClient.fetchListIncrementally = async () => {
tests/hashtag-preferences.test.mjs: fetchCalls += 1;
tests/hashtag-preferences.test.mjs: return fetchCalls <= 4 ? [event] : [];
tests/hashtag-preferences.test.mjs: nostrClient.fetchListIncrementally = originalFetchIncremental;
tests/app-batch-fetch-profiles.test.mjs: // Should fetch despite cache presence
tests/app-batch-fetch-profiles.test.mjs: "should include cached pubkey in fetch list"
tests/nostr-rebroadcast-guard.test.mjs: fetchRawEventById: async () => null,
tests/nostr-boost-actions.test.mjs: fetchRawEventById: async (id, { relays: requestedRelays } = {}) => {
tests/nostr-boost-actions.test.mjs: client.fetchRawEventById = async () => null;
tests/modal-accessibility.test.mjs: const originalFetch = globalThis.fetch;
tests/modal-accessibility.test.mjs: globalThis.fetch = async (resource) => {
tests/modal-accessibility.test.mjs: throw new Error(`Unexpected fetch request: ${key}`);
tests/modal-accessibility.test.mjs: globalThis.fetch = originalFetch;
tests/zap-split.test.mjs:globalThis.fetch = async () => {
tests/zap-split.test.mjs: throw new Error("Unexpected fetch call during zap split tests.");
tests/zap-split.test.mjs: async fetchPayServiceData(url) {
tests/zap-split.test.mjs: const fetcher = async (url) => {
tests/zap-split.test.mjs: fetcher,
tests/zap-split.test.mjs: assert.equal(requestedUrls.length, 1, "should call fetcher once");
tests/zap-split.test.mjs: assert.equal(listCalls, 1, "should fetch platform metadata once the pool is ready");
tests/profile-modal-controller.test.mjs: global.fetch = async (resource) => {
tests/profile-modal-controller.test.mjs: throw new Error(`Unexpected fetch: ${resource}`);
tests/profile-modal-controller.test.mjs: delete global.fetch;
tests/watch-history.test.mjs: const snapshotId = "extension-fetch";
tests/watch-history.test.mjs: const result = await nostrClient.fetchWatchHistory(actorInput, {
tests/watch-history.test.mjs: const originalFetch = nostrClient.fetchWatchHistory;
tests/watch-history.test.mjs: const originalManagerFetch = nostrClient.watchHistory.fetch;
tests/watch-history.test.mjs: const fetchResult = {
tests/watch-history.test.mjs: nostrClient.fetchWatchHistory = async () => fetchResult;
tests/watch-history.test.mjs: nostrClient.watchHistory.fetch = async () => fetchResult;
tests/watch-history.test.mjs: nostrClient.fetchWatchHistory = originalFetch;
tests/watch-history.test.mjs: nostrClient.watchHistory.fetch = originalManagerFetch;
tests/watch-history.test.mjs: "loadLatest should fetch from relays for logged-in actors",
tests/watch-history.test.mjs: // Simulate renderer fetching via feed engine
tests/watch-history.test.mjs: fetchHistory: async (actorInput, { cursor = 0, forceRefresh = false } = {}) => {
tests/discussion-count-service.test.mjs: "DOM should transition to ready after a successful fetch"
tests/discussion-count-service.test.mjs: "count value should reflect the fetched total"
tests/edit-modal-submit-state.test.mjs: global.fetch = async (resource) => {
tests/edit-modal-submit-state.test.mjs: throw new Error(`Unexpected fetch: ${resource}`);
tests/edit-modal-submit-state.test.mjs: delete global.fetch;
tests/revert-modal-controller.test.mjs: fetchVideos: async () => [mockVideo],
tests/revert-modal-controller.test.mjs: await t.test('open() fetches history and opens modal', async () => {
tests/ui/uploadModal-integration.test.mjs: originalGlobals.fetch = global.fetch;
tests/ui/uploadModal-integration.test.mjs: global.fetch = async (url) => {
tests/ui/uploadModal-integration.test.mjs: if ('fetch' in originalGlobals) global.fetch = originalGlobals.fetch; else delete global.fetch;
tests/ui/profile-modal-moderation-settings.test.mjs: global.fetch = async (url) => {
tests/ui/profile-modal-moderation-settings.test.mjs: delete global.fetch;
tests/ui/url-health-controller.test.mjs: // Mock fetch
tests/ui/url-health-controller.test.mjs: global.fetch = async (url) => {
tests/ui/url-health-controller.test.mjs: delete global.fetch;
tests/ui/creatorProfileController.test.mjs: fetchedProfile: { name: "Fetched Name", picture: "fetched.jpg" },
tests/ui/creatorProfileController.test.mjs: // logic prioritizes fetched > cached > video
tests/ui/creatorProfileController.test.mjs: assert.strictEqual(result.picture, "fetched.jpg");
tests/ui/creatorProfileController.test.mjs: await t.test("resolveCreatorProfileFromSources falls back to fetched profile", () => {
tests/ui/creatorProfileController.test.mjs: fetchedProfile: { name: "Fetched Name", picture: "fetched.jpg" },
tests/ui/creatorProfileController.test.mjs: assert.strictEqual(result.picture, "fetched.jpg");
tests/ui/creatorProfileController.test.mjs: await t.test("fetchModalCreatorProfile fetches profile and updates modal", async () => {
tests/ui/creatorProfileController.test.mjs: fetchProfileMetadata: async () => ({
tests/ui/creatorProfileController.test.mjs: await controller.fetchModalCreatorProfile({
tests/ui/uploadModal-reset.test.mjs: global.fetch = async () => ({ ok: true, text: async () => mockHtml });
tests/ui/profileModalController-addProfile.test.mjs: global.fetch = async (url) => {
tests/ui/profileModalController-addProfile.test.mjs: delete global.fetch;
tests/performance/resolvePostedAt.test.mjs: assert.ok(rootCall, 'Should fetch missing roots');
tests/performance/resolvePostedAt.test.mjs: assert.ok(historyCall, 'Should fetch histories');
tests/unit/editModalController.test.mjs: fetchVideos: mock.fn(async () => []),
tests/unit/editModalController.test.mjs: assert.strictEqual(services.nostrService.fetchVideos.mock.callCount(), 1);
tests/unit/services/r2Service.storage-config.test.mjs: originalFetch = globalThis.fetch;
tests/unit/services/r2Service.storage-config.test.mjs: globalThis.fetch = async () => ({
tests/unit/services/r2Service.storage-config.test.mjs: globalThis.fetch = originalFetch;
tests/app/feedCoordinator.test.mjs: // Simulate fetch completing with videos
tests/comment-thread-service.test.mjs: fetchVideoComments: async () => [
tests/comment-thread-service.test.mjs: const fetchCalls = [];
tests/comment-thread-service.test.mjs: const fetchVideoComments = async (...args) => {
tests/comment-thread-service.test.mjs: fetchCalls.push(args);
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: fetchCalls.length = 0;
tests/comment-thread-service.test.mjs: const cachedResult = await service.fetchThread({ videoEventId: videoId });
tests/comment-thread-service.test.mjs: fetchCalls.length,
tests/comment-thread-service.test.mjs: "cache hits should avoid fallback fetch",
tests/comment-thread-service.test.mjs: fetchCalls.length = 0;
tests/comment-thread-service.test.mjs: const fallbackResult = await service.fetchThread({
tests/comment-thread-service.test.mjs: fetchCalls.length,
tests/comment-thread-service.test.mjs: "feature flag off should invoke fallback fetch",
tests/comment-thread-service.test.mjs: entry.includes("Improved fetching fallback: feature disabled"),
tests/comment-thread-service.test.mjs: "fallback path should return freshly fetched comments",
tests/comment-thread-service.test.mjs: const fetchVideoComments = async () => [topLevelEvent];
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: // If loading failed (e.g. no fetch), threadReadyPayload might be incomplete or empty
tests/comment-thread-service.test.mjs: const fetchVideoComments = async () => [
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: fetchVideoComments: async () => [],
tests/comment-thread-service.test.mjs: let fetchCalls = 0;
tests/comment-thread-service.test.mjs: const fetchVideoComments = async (target, options) => {
tests/comment-thread-service.test.mjs: fetchCalls += 1;
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: fetchVideoComments, // Ensure directly passed too
tests/comment-thread-service.test.mjs: service.fetchVideoComments = fetchVideoComments;
tests/comment-thread-service.test.mjs: // fetchCalls assertion removed as it's flaky in this env, we check result instead.
tests/comment-thread-service.test.mjs: "profile hydration should fetch unknown authors once",
tests/comment-thread-service.test.mjs: const fetchTargets = [];
tests/comment-thread-service.test.mjs: const fetchOptions = [];
tests/comment-thread-service.test.mjs: const fetchVideoComments = async (target, options) => {
tests/comment-thread-service.test.mjs: fetchTargets.push(target);
tests/comment-thread-service.test.mjs: fetchOptions.push(options);
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: service.fetchVideoComments = fetchVideoComments;
tests/comment-thread-service.test.mjs: assert.equal(fetchTargets.length, 1, "fetch should run even without an address");
tests/comment-thread-service.test.mjs: assert.deepStrictEqual(fetchTargets[0], {
tests/comment-thread-service.test.mjs: "videoDefinitionAddress" in fetchTargets[0],
tests/comment-thread-service.test.mjs: const [firstFetchOptions] = fetchOptions;
tests/comment-thread-service.test.mjs: assert.deepStrictEqual(subscribeTargets[0], fetchTargets[0]);
tests/comment-thread-service.test.mjs: let fetchTarget = null;
tests/comment-thread-service.test.mjs: const fetchVideoComments = async (target) => {
tests/comment-thread-service.test.mjs: fetchTarget = target;
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: service.fetchVideoComments = fetchVideoComments;
tests/comment-thread-service.test.mjs: assert.ok(fetchTarget, "fetch should run when only root id is provided");
tests/comment-thread-service.test.mjs: assert.equal(fetchTarget.rootIdentifier, video.videoRootId);
tests/comment-thread-service.test.mjs: let fetchTarget = null;
tests/comment-thread-service.test.mjs: const fetchVideoComments = async (target) => {
tests/comment-thread-service.test.mjs: fetchTarget = target;
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: service.fetchVideoComments = fetchVideoComments;
tests/comment-thread-service.test.mjs: assert.ok(fetchTarget, "fetch should run when pointer identifiers are provided");
tests/comment-thread-service.test.mjs: assert.equal(fetchTarget.rootIdentifier, video.pointerIdentifiers.videoRootId);
tests/comment-thread-service.test.mjs: "CommentThreadService preserves raw video author pubkeys during hydration fetches",
tests/comment-thread-service.test.mjs: const fetchTargets = [];
tests/comment-thread-service.test.mjs: const fetchBlocker = new Promise((resolve) => {
tests/comment-thread-service.test.mjs: const fetchVideoComments = async (target) => {
tests/comment-thread-service.test.mjs: fetchTargets.push(target);
tests/comment-thread-service.test.mjs: await fetchBlocker;
tests/comment-thread-service.test.mjs: fetchVideoComments,
tests/comment-thread-service.test.mjs: service.fetchVideoComments = fetchVideoComments;
tests/comment-thread-service.test.mjs: assert.equal(fetchTargets.length, 1, "hydration fetch should start immediately");
tests/comment-thread-service.test.mjs: fetchTargets[0].videoAuthorPubkey,
tests/comment-thread-service.test.mjs: "fetch target should prefer the raw video author pubkey",
tests/comment-thread-service.test.mjs: "hydration should include comments published before fetch completion",
tests/comment-thread-service.test.mjs: fetchVideoComments: async () => [],
tests/services/link-preview-service.test.mjs: const originalFetch = globalThis.fetch;
tests/services/link-preview-service.test.mjs: globalThis.fetch = originalFetch;
tests/services/link-preview-service.test.mjs: await t.test("fetches and caches preview", async () => {
tests/services/link-preview-service.test.mjs: // Mock fetch
tests/services/link-preview-service.test.mjs: globalThis.fetch = async (url) => {
tests/services/link-preview-service.test.mjs: await t.test("returns null on fetch failure", async () => {
tests/services/link-preview-service.test.mjs: globalThis.fetch = async () => {
tests/services/nostr-service.test.mjs: describe("fetchVideosByAuthors", () => {
tests/services/nostr-service.test.mjs: it("should fetch videos from relays for specific authors", async () => {
tests/services/nostr-service.test.mjs: const videos = await nostrService.fetchVideosByAuthors(authors);
tests/services/profileMetadataService.test.mjs: fetchProfileMetadataBatch,
tests/services/profileMetadataService.test.mjs: fetchProfileMetadata,
tests/services/profileMetadataService.test.mjs: describe("fetchProfileMetadataBatch", () => {
tests/services/profileMetadataService.test.mjs: const results = await fetchProfileMetadataBatch({
tests/services/profileMetadataService.test.mjs: it("should fetch profiles for provided pubkeys", async () => {
tests/services/profileMetadataService.test.mjs: const results = await fetchProfileMetadataBatch({
tests/services/profileMetadataService.test.mjs: const results = await fetchProfileMetadataBatch({
tests/services/profileMetadataService.test.mjs: const results = await fetchProfileMetadataBatch({
tests/services/profileMetadataService.test.mjs: const p1 = fetchProfileMetadataBatch({ pubkeys: [pubkey], nostr: mockNostr, logger: mockLogger });
tests/services/profileMetadataService.test.mjs: const p2 = fetchProfileMetadataBatch({ pubkeys: [pubkey], nostr: mockNostr, logger: mockLogger });
tests/services/profileMetadataService.test.mjs: describe("fetchProfileMetadata", () => {
tests/services/profileMetadataService.test.mjs: const result = await fetchProfileMetadata("invalid", { nostr: mockNostr });
tests/services/profileMetadataService.test.mjs: const result = await fetchProfileMetadata(pubkey, { nostr: mockNostr, logger: mockLogger });
tests/services/relay-health-service.test.mjs:test("RelayHealthService: getRelayUrls fetches from relayManager", () => {
tests/services/attachmentService.test.mjs:const originalFetch = globalThis.fetch;
tests/services/attachmentService.test.mjs: globalThis.fetch = mock.fn();
tests/services/attachmentService.test.mjs: globalThis.fetch = originalFetch;
tests/services/attachmentService.test.mjs: delete globalThis.fetch;
tests/services/attachmentService.test.mjs: globalThis.fetch.mock.mockImplementation(async () => mockResponse);
tests/services/attachmentService.test.mjs: assert.strictEqual(globalThis.fetch.mock.callCount(), 1);
tests/services/attachmentService.test.mjs: globalThis.fetch.mock.mockImplementation(async () => mockResponse);
tests/services/attachmentService.test.mjs: globalThis.fetch.mock.mockImplementation(async () => mockResponse);
tests/services/attachmentService.test.mjs: globalThis.fetch.mock.mockImplementation(async () => mockResponse);
tests/services/attachmentService.test.mjs: assert.strictEqual(globalThis.fetch.mock.callCount(), 1);
tests/services/attachmentService.test.mjs: assert.strictEqual(globalThis.fetch.mock.callCount(), 1);
tests/services/attachmentService.test.mjs: globalThis.fetch.mock.mockImplementation(async () => mockResponse);
tests/services/discussionCountService.test.mjs: test("refreshCounts handles happy path (fetches and updates DOM)", async () => {
View File
Whitespace-only changes.
View File
Whitespace-only changes.
@@ -0,0 +1,37 @@
# Test Audit Report: 2026-02-17
## Summary
- **Status**: ⚠️ Failed / Timed Out
- **Runner**: `node scripts/run-unit-tests.mjs`
- **Total Duration**: > 400s (Timed Out)
- **Coverage**: Partial data collected.
## Critical Issues
### 1. Test Suite Timeout
The full unit test suite timed out after 400s (6.6 minutes).
The primary bottleneck appears to be `tests/profile-modal-controller.test.mjs`, which took over 60 seconds to run and eventually timed out when run individually with a 60s limit. Individual tests within it took 3s, 5s, and 10s.
### 2. Slow Tests
- `tests/profile-modal-controller.test.mjs`:
- `Profile modal navigation buttons toggle active state`: ~10.8s
- `Add profile request suspends focus trap and elevates login modal`: ~5.1s
- `Profile modal Escape closes and restores trigger focus`: ~3.5s
### 3. Suspicious Patterns
- **SetTimeout Usage**: Found numerous instances of `setTimeout` in tests, which contributes to slowness and flakiness.
- `tests/profile-modal-controller.test.mjs` uses `setTimeout(resolve, 0)` which is likely not the cause of the 10s delay, implying other blocking operations or implicit waits.
- `tests/video-card-source-visibility.test.mjs` mocks `requestAnimationFrame` with `setTimeout`.
## Coverage
Partial coverage data was logged to `test-audit/coverage-run.log`.
The process timed out before full completion, but `c8` output a coverage table for the tests that ran.
## Remediation Plan
1. **Investigate `tests/profile-modal-controller.test.mjs`**: This file is a major performance regression. It likely renders complex DOM or has inefficient polling.
2. **Optimize Test Runner**: Consider parallelizing tests (sharding is supported but currently running sequentially in CI).
3. **Refactor `setTimeout`**: Replace arbitrary sleeps with `waitFor` or mock timers where possible.
## Artifacts
- `test-audit/coverage-run.log`: partial coverage output.
- `test-audit/timeouts.txt`: list of `setTimeout` usages.
- `test-audit/console_logs.txt`: list of `console.log` usages.
+12 -8
View File
@@ -24,7 +24,6 @@ tests/torrent/toast-service.test.mjs: await new Promise((resolve) => setTimeo
tests/hashtag-preferences.test.mjs: setTimeout(() => handler(), 0);
tests/hashtag-preferences.test.mjs: setTimeout(() => process.exit(0), 100);
tests/nostr-private-key-signer.test.mjs: setTimeout(() => process.exit(0), 100);
tests/e2e/webseed-playback.spec.ts: test.setTimeout(90000); // Increase timeout for fallback logic
tests/nwc-client.test.mjs: setTimeout(() => {
tests/nwc-client.test.mjs: setTimeout(() => {
tests/watchHistory/watch-history-telemetry.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
@@ -48,26 +47,30 @@ tests/moderation/video-card.test.mjs: await new Promise((resolve) => setTimeo
tests/moderation/video-card.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/moderation/video-card.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/moderation/submit-report.test.mjs: setTimeout(() => handler(), 0);
tests/race/nostr-client-init-race.test.mjs: await new Promise(resolve => setTimeout(resolve, 50));
tests/modal-accessibility.test.mjs: setTimeout(() => callback(Date.now()), 0);
tests/zap-split.test.mjs: setTimeout(() => {
tests/profile-modal-controller.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/profile-modal-controller.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/profile-modal-controller.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/auth-service.test.mjs: await new Promise((resolve) => setTimeout(resolve, 10));
tests/auth-service.test.mjs: await new Promise((resolve) => setTimeout(resolve, 10));
tests/test-helpers/wait-for.mjs: await new Promise((resolve) => setTimeout(resolve, interval));
tests/auth-service.test.mjs: await new Promise((resolve) => setTimeout(resolve, 10));
tests/auth-service.test.mjs: await new Promise((resolve) => setTimeout(resolve, 10));
tests/login-modal-controller.test.mjs: setTimeout(() => {
tests/login-modal-controller.test.mjs: await new Promise(resolve => setTimeout(resolve, 50));
tests/login-modal-controller.test.mjs: await new Promise(resolve => setTimeout(resolve, 10));
tests/login-modal-controller.test.mjs: setTimeout(() => {
tests/login-modal-controller.test.mjs: await new Promise(resolve => setTimeout(resolve, 50));
tests/login-modal-controller.test.mjs: await new Promise(resolve => setTimeout(resolve, 10));
tests/watch-history.test.mjs: setTimeout(() => {
tests/watch-history.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/watch-history.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/watch-history.test.mjs: await new Promise((resolve) => setTimeout(resolve, 0));
tests/watch-history.test.mjs: await new Promise(r => setTimeout(r, 50));
tests/user-blocks.test.mjs:await new Promise((resolve) => setTimeout(resolve, 100));
tests/user-blocks.test.mjs:await new Promise((resolve) => setTimeout(resolve, 100));
tests/nostr-service-access-control.test.mjs: setTimeout(() => process.exit(0), 100);
tests/nostr-login-permissions.test.mjs: setTimeout(() => reject(new Error("permission denied")), 300);
tests/admin-list-store.test.mjs: setTimeout(fn, delay);
tests/admin-list-store.test.mjs:await new Promise((resolve) => setTimeout(resolve, slowRelayDelayMs + 20));
tests/visual/overlay-layers.spec.ts: test.setTimeout(120_000);
tests/state/cache.test.mjs: await new Promise((resolve) => setTimeout(resolve, 10));
tests/nip07-concurrency.test.mjs: await new Promise(resolve => setTimeout(resolve, delay));
tests/nip07-concurrency.test.mjs: // Note: Node's setTimeout is not precise, so we use loose bounds
@@ -83,7 +86,7 @@ tests/ui/components/hashtagStripHelper.test.mjs: // Note: removing setTimeout
tests/ui/components/hashtagStripHelper.test.mjs: // But for testing fallback path where RAF is missing, we usually want setTimeout available.
tests/ui/components/hashtagStripHelper.test.mjs: // If we want to test "no RAF, use setTimeout", we remove RAF.
tests/ui/components/hashtagStripHelper.test.mjs:test("HashtagStripHelper falls back to window resize with setTimeout when RAF is missing", (t) => {
tests/ui/engagement-controller.test.mjs: global.window = { setTimeout: t.mock.fn() };
tests/ui/engagement-controller.test.mjs: global.window = { setTimeout: t.mock.fn() };
tests/ui/hashtag-strip-helper-bounce.test.mjs: // Mock setTimeout
tests/ui/hashtag-strip-helper-bounce.test.mjs: window.setTimeout = (cb, delay) => {
tests/ui/hashtag-strip-helper-bounce.test.mjs: window.setTimeout = (cb, delay) => {
@@ -95,11 +98,12 @@ tests/ui/url-health-controller.test.mjs: await new Promise(resolve => setTime
tests/compliance/nip07_compliance.test.mjs: await new Promise(resolve => setTimeout(resolve, 50));
tests/unit/notificationController.test.mjs: setTimeout: mock.fn((cb, ms) => setTimeout(cb, ms)),
tests/unit/client-count-resilience.test.mjs: await new Promise(r => setTimeout(r, 100));
tests/unit/ui/videoModalController.test.mjs: await new Promise(resolve => setTimeout(resolve, 0));
tests/unit/ui/videoModalController.test.mjs: await new Promise(resolve => setTimeout(resolve, 0));
tests/unit/services/r2Service.storage-config.test.mjs: originalSetTimeout = globalThis.setTimeout;
tests/unit/services/r2Service.storage-config.test.mjs: globalThis.setTimeout = (fn) => {
tests/unit/services/r2Service.storage-config.test.mjs: globalThis.setTimeout = originalSetTimeout;
tests/nostr-signer-race.test.mjs: await new Promise(resolve => setTimeout(resolve, 50));
tests/embed_playback_check.spec.mjs: await new Promise(resolve => setTimeout(resolve, 2000));
tests/comment-thread-service.test.mjs:const tick = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
tests/services/link-preview-service.test.mjs: await new Promise((r) => setTimeout(r, 10));
tests/services/playbackService.test.mjs: mock.timers.enable({ apis: ['setTimeout'] });
@@ -0,0 +1,6 @@
# Test Execution Log
Timestamp: 2026-02-17T16:33:00Z
Agent: test-audit-agent
Running: npx --yes c8 node scripts/run-unit-tests.mjs
See test-audit-report-2026-02-17.md for full report.
+6
View File
@@ -0,0 +1,6 @@
# Daily Test Audit TODO
- [ ] Run tests with coverage
- [ ] Run flakiness check (3 runs)
- [ ] Run static analysis (grep patterns)
- [ ] Generate report