Fully closes #11b's un-quarantine work: the QUARANTINE map is now EMPTY.
dm-block-filter.test.mjs (node:test) PASSED all subtests then hung, so the
node:test runner never exited. Diagnosed via process.getActiveResourcesInfo():
the "integration with loaded user block list" test's manager.loadBlocks() opens a
LIVE block-list subscription through nostrClient's real SimplePool aimed at the
test's fake relay URLs, leaking 4 TCP sockets + reconnect timers. It is NOT the
decrypt-retry timer (verified absent). Nulling nostrClient.pool did not help —
loadBlocks calls ensurePool() (userBlocks.js:967) to re-create+connect a real
pool when pool is falsy.
Fix (node:test-SAFE, no force-exit): make the test hermetic — (1) a TRUTHY stub
pool so ensurePool() is skipped, (2) a no-op getSubscriptionManager so
startBlockListSubscription opens nothing. The block-merge logic under test still
runs fully through the already-stubbed fetchListIncrementally. Restored in finally.
Verified BOTH directions: a clean run exits 0 (# pass 12), AND a deliberately
broken assertion still exits 1 (# fail 1) — failures are NOT masked. A force
process.exit in an after() hook was rejected precisely because it masked failures
(process.exitCode isn't set when the hook fires). See TEST_INTEGRITY.md.
NOTE: the full suite still has one SEPARATE, pre-existing red unrelated to #11b —
tests/ui/uploadModal-reset.test.mjs (TODO #11): its "zombie callbacks" subtest
feeds a plain object where webtorrent expects a Blob ("must be an instance of
Blob") and leaks async activity after the test ends. Untouched here; tracked
under #11 (harden flaky tests), not the #11b quarantine work.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Closes the #11b un-quarantine work: the three target files now pass and run in
CI. A full-suite run with a per-file timeout then surfaced a FOURTH, pre-existing
hang that had never been in the map (dm-block-filter) — quarantined with a triage
note rather than left to hang CI.
user-blocks.test.mjs — post-completion HANG. The decrypt-timeout section installs
a never-resolving nip44Decrypt whose background decrypt-retry timer outlives the
run (manager.reset() races it). Added the repo's established bare-assert
`setTimeout(() => process.exit(0), 50)` exit after the final assertion.
nostr-publish-rejection.test.mjs — post-completion HANG (was NOT in the map, so it
had been silently hanging local `npm run test:unit`, which has no per-file timeout
unless UNIT_TEST_TIMEOUT_MS is set). All assertions pass, then the imported app
stack (app.js + subscriptions + userBlocks) keeps the loop alive. Same
`process.exit(0)`-after-cleanup fix. (The dev-mode + NIP-71 spec fixes were
already in the file.)
nwc-client.test.mjs — (1) mock shadow: readToolkitFromScope prefers the bootstrap's
frozen canonical toolkit over window.NostrTools, so per-section mocks never took
effect and real @noble rejected the fake keys. Remove the scope canonical so the
resolver falls through to each mock. (2) spec correction: one section expected a
rejection when the toolkit "lacks nip44", but mergeWithCanonical ALWAYS backfills
the canonical nip44 (even explicit `nip44:null`) — nip44_v2 is never absent. The
wallet now advertises a genuinely-unsupported scheme (nip44_v3) to exercise the
same UNSUPPORTED_ENCRYPTION path, and asserts error.code too. See TEST_INTEGRITY.md.
dm-block-filter.test.mjs — QUARANTINED (pre-existing, node:test). All subtests pass,
then it hangs: manager.loadBlocks() opens a live block-list subscription through
nostrClient's real SimplePool pointed at the test's fake relay URLs, leaking TCP
sockets + reconnect timers that node:test can't drain. Needs a node:test-safe fix
(inject a mock pool so no real socket opens) — a force process.exit in after() is
UNSAFE (verified: process.exitCode isn't set yet, so it masks failures).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Two fixes bring the file fully green in CI:
1. Force dev mode via globalThis.__BITVID_DEV_MODE_OVERRIDE__ BEFORE any
config-importing module loads — the dev-default assertions depended on the
environment (#50's documented test-harness gap).
2. spec_correction: the NIP-71 sub-test asserted publishVideo auto-invokes
publishNip71Video whenever nip71 metadata is present. Stale on two counts:
legacy 21/22 auto-publish is deliberately OFF (FEATURE_PUBLISH_NIP71:false;
the opt-in 34235/36 MIRROR is the interop story, and #58 removed the form UI
feeding this path), and the internal call uses the module-level function so
the client-method stub never intercepted anyway. Corrected to assert the
video note publishes with NO NIP-71 auto-publish while the flag is off.
Removed from the runner QUARANTINE map — remaining quarantined: user-blocks
(hang, needs deterministic rewrite) and nwc-client (mock-injection rework).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
nostr-count-fallback: STALE TEST after a refactor — countUnsupportedRelays moved
from NostrClient to its ConnectionManager, and the test read it off the client
(undefined.has). Repointed the assertion at client.connectionManager
.countUnsupportedRelays. No behavior change, no assertion weakened.
Also recorded the precise multi-precondition diagnosis for the still-quarantined
nostr-publish-rejection (dev-mode override before the first dynamic config import;
then a NIP-71 invocation sub-test) in the QUARANTINE note + TODO, so it's a quick
finish next time.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Triaged two more silently-excluded test files back into CI.
- nostr-boost-actions: STALE SPEC. Test required buildRepostEvent to throw
/missing-event-relay/ with no relay hint, but a relay hint is a NIP-18 SHOULD
(not MUST) — the builder degrades to a two-element `e` tag so a user can always
repost. Replaced with an exact assertion of the valid output (kind 16 + e/p/k).
- admin-list-store: STALE HARNESS (no production change, no assertion weakened).
Community curator lists are fetched via the batched SubscriptionManager
(cold-start relay-storm fix) the harness never mocked; the mock "hex" curator
values started with "npub" so parseCommunityBlacklistReferences decoded them
twice; and createListEvent omitted the `d` tag selectNewestEventsForReferences
matches on. Fixed all three to be faithful to production.
Removed both from the QUARANTINE map; TEST_INTEGRITY.md + TODO updated.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Triaged the monolithic tests/view-counter.test.mjs and got the whole file green,
then removed it from the QUARANTINE map:
- Pinned nostrClient.getSubscriptionManager() to null so the test exercises the
legacy per-pointer hydrate/subscribe path it mocks. The batched
SubscriptionManager path (added with the relay-storm work) was silently
shadowing the mocked legacy APIs.
- Made the dedupe-window test bucket-aligned (it used Date.now(), so the
+window/2 offset could straddle a fixed-bucket boundary and flake by time of
day).
- Corrected the hydrateVideoHistory root-timestamp assertions to the refactored
unit boundary: hydrateVideoHistory populates the rootCreatedAtByRoot MAP; the
video object's rootCreatedAt FIELD is applied by syncActiveVideoRootTimestamp.
reactionCounter.js audit (kind-7 likes): accurate, no fix needed. It does not use
NIP-45 COUNT; it lists kind-7 events and dedupes via applyReactionToState keyed
by pubkey (one reaction per user, latest-wins) with per-content totals — no
raw-count inflation. Kind-7 isn't replaceable, so listing+dedupe is the only
accurate model.
Spec corrections documented in TEST_INTEGRITY.md (SCN-view-counter-legacy-path,
SCN-hydrate-root-timestamp).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
The unit runner only collected files that imported node:test, silently
excluding ~20 bare-assert files (several were failing on main, unnoticed).
Collect every *.test.{mjs,js}; known-broken files live in an explicit
QUARANTINE map that is reported on every run (never silently skipped) with
a stale-entry check.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
- Fix flaky test in `tests/hashtag-preferences.test.mjs` by defining missing `fetchCalls` variable.
- Fix `webtorrent` initialization error in `tests/unit/services/r2Service.storage-config.test.mjs` by ensuring `window.crypto` is available and `File` mock extends `Blob`.
- Update `tests/test-helpers/setup-localstorage.mjs` to polyfill `window.crypto` using `globalThis.crypto`.
- Update `scripts/run-unit-tests.mjs` to support test file filtering via command line arguments.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Fix `tests/app-batch-fetch-profiles.test.mjs` by mocking `readRelays` to ensure deterministic query counts.
- Set `NODE_ENV=test` in `scripts/run-unit-tests.mjs` to prevent `nostr-tools` bootstrap failures in test environment.
- Run `npm ci` and `npm audit fix` to maintain lockfile health.
Co-authored-by: PR0M3TH3AN <[email protected]>
- Update smoke-test.mjs to output structured summary with logs
- Update telemetry-aggregator.mjs to collect from unit, smoke, and load tests
- Update run-unit-tests.mjs to log output to artifacts/test_unit.log
- Ensure PII sanitization in telemetry reports