Skip to content

fix(tests): make apps/web and apps/api suites green - #164

Merged
Rieranthony merged 3 commits into
mainfrom
fix/green-test-suite
Aug 3, 2026
Merged

fix(tests): make apps/web and apps/api suites green#164
Rieranthony merged 3 commits into
mainfrom
fix/green-test-suite

Conversation

@Rieranthony

@Rieranthony Rieranthony commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

bun run test currently fails: 149 failures in apps/web, 240 in apps/api — and three more packages had test files that never ran at all. This makes the whole monorepo green. No production code is touched — only test files, test scripts, and the runner script.

Cause 1 — cross-file mock leakage (the large majority)

bun registers mock.module() factories globally for the whole test process and never unwinds them. Nearly every component/router test here mocks a module partially (e.g. @tanstack/react-query with only useMutation). In a combined run the first partial factory wins, and every later file importing a missing export dies with:

SyntaxError: Export named 'useMutation' not found in module .../@tanstack/react-query/...

That is not a defect in the tests. Run individually, 157/170 web files and 123/129 api files already passed.

Each app now runs one bun test process per file via scripts/test-isolated.ts — the same remedy CI already applies to apps/api's OpenAPI contract test (and documents in a comment), generalized. It runs files in parallel, so it costs almost nothing (web ~10s, api ~20s). The runner takes a path filter (bun run test src/lib) and prints full output for any failing file.

Cause 2 — 19 genuinely broken files

Fixed individually, not worked around:

  • Missing their own mocks — tests that only passed when a sibling file's mock leaked in: precision-flow-section, promo-precision-flow-scene, fake-conversation, page-tree-node, timeline-ui-test-page, use-faq-mutations, use-file-mutations.
  • Assertions left behind by deliberate source changes — background targetFps and pointer-trail defaults (retuned in feat: bolder ascii), and the tools catalog order/section counts (the catalog grew). Where the source exports a constant, the test now reads it instead of hardcoding, so future tuning cannot silently break the test again.
  • visitor-source-badge asserted height="12" while the source has always rendered height={16} at a 12px display size (size-3, for favicon crispness). Both landed in the same commit — this test has never passed.
  • docs-widget-release hardcoded /Users/anthonyriera/code/cossistant-monorepo, so it only passed on one machine and would fail in CI. It now derives the repo root from import.meta.dir.
  • seo-routes / sitemap assumed a localhost origin. getSiteUrl() only falls back to localhost when NODE_ENV === "development", which bun test does not set. They now pin NEXT_PUBLIC_APP_URL.
  • Fake dbs that predated a query extractionplan.self-hosted, website, contact-control, load-context. The routers moved to extracted queries (listOrganizationWebsitePlanTargets, listActiveAiAgentSummariesForWebsite, getActiveVisitorForWebsite, db.query.website); these now serve the same fixtures through those queries, so existing call sites are unchanged.

Cause 3 — suites that never ran

apps/workers (7 files), packages/jobs (8) and packages/tiny-markdown (1) had test files but no test script, so turbo run test skipped them. Wiring them up surfaced two real failures:

  • apps/workers/src/queues/index.test.ts mocked five worker factories but not ./lifecycle-email/worker, added later. Unmocked, it builds a real BullMQ worker and opens a Redis connection — so it could only pass against a live Redis and failed with ECONNREFUSED anywhere else. It also mocked @cossistant/redis partially, dropping createRedisConnection.
  • packages/jobs ai-agent-background asserted a 60s default delay; AI_AGENT_BACKGROUND_DELAY_MS is 30s. It now reads the exported constant.

Verification

bun run test: 18/18 turbo tasks pass

package tests
@cossistant/api 703
@cossistant/web 692
@cossistant/jobs 52
@cossistant/workers 33
@cossistant/memory 33
facehash 24
@cossistant/protocol 18
@cossistant/release 8
@cossistant/tiny-markdown 7

bun run check-types 20/20. Biome clean on every changed file.

Note

With apps/api's suite now isolated per file, the dedicated "Test REST OpenAPI contract" CI step is redundant (it exists only to dodge this leakage). Left in place here — worth removing separately.

🤖 Generated with Claude Code

`bun run test` failed with 149 failures in apps/web and 240 in apps/api. Two
independent causes, no production code involved.

Cause 1 — cross-file mock leakage (the large majority).

bun registers mock.module() factories globally for the whole test process and
never unwinds them. Almost every component/router test mocks a module partially
(say @tanstack/react-query with only useMutation), so in a combined run the
first partial factory wins and every later file importing a missing export dies
with "SyntaxError: Export named 'useX' not found in module ...". Run alone,
157/170 web files and 123/129 api files already passed.

Each app now runs one `bun test` process per file (scripts/test-isolated.ts),
which is the same remedy CI already applies to apps/api's OpenAPI contract test,
generalized. Parallel, so the web suite takes ~10s and api ~21s.

Cause 2 — 19 genuinely broken files, fixed individually:

- Tests that never mocked tRPC/react-query/website context and only passed when
  a sibling file's mock happened to leak in (precision-flow-section,
  promo-precision-flow-scene, fake-conversation, page-tree-node,
  timeline-ui-test-page, use-faq-mutations, use-file-mutations).
- Assertions left behind by deliberate source changes: background fps/pointer
  trail defaults (changed in "feat: bolder ascii"), the tools catalog order and
  section counts, and the visitor-source-badge favicon, which asserted 12 while
  the source has always rendered 16 intrinsic pixels at a 12px display size —
  both landed in the same commit, so it never passed. Where the source exports a
  constant the test now reads it instead of hardcoding, so tuning a value cannot
  silently break the test again.
- docs-widget-release hardcoded /Users/anthonyriera/code/cossistant-monorepo, so
  it only passed on one machine and would fail in CI. It now derives the repo
  root from import.meta.dir.
- seo-routes and sitemap assumed a localhost origin; getSiteUrl() only falls
  back to localhost when NODE_ENV is "development", which bun test does not set.
  They now pin NEXT_PUBLIC_APP_URL.
- Tests whose fake db predated a query extraction (plan.self-hosted,
  website, contact-control, load-context) now serve the same fixtures through
  the extracted queries.

Result: 15/15 turbo test tasks pass — web 692, api 703, protocol 18, memory 33,
facehash 24, release 8. check-types 20/20 and Biome clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
facehash-landing Ready Ready Preview Jul 30, 2026 3:46pm
web Ready Ready Preview Jul 30, 2026 3:46pm

Request Review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b159aeb14d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const args = process.argv.slice(2);
const filters = args.filter((arg) => !arg.startsWith("-"));

const glob = new Glob("src/**/*.test.{ts,tsx}");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include tests outside src in isolated discovery

When apps/web runs bun run test, this glob limits discovery to src, whereas the previous bun test command also discovered the repository-root next.config.test.ts. That configuration test is now silently skipped, so the suite can report success even if the Facehash image-host configuration it protects regresses; include root-level tests in the isolated runner's discovery.

Useful? React with 👍 / 👎.

apps/workers (7 files), packages/jobs (8) and packages/tiny-markdown (1) each
had test files but no `test` script, so `turbo run test` skipped them entirely
and 16 files had never run in CI.

Wiring them up surfaced two real failures:

- apps/workers/src/queues/index.test.ts mocked five worker factories but not
  ./lifecycle-email/worker, which was added later. Unmocked it builds a real
  BullMQ worker and opens a Redis connection, so the test could only pass
  against a live Redis — it failed with ECONNREFUSED everywhere else. It also
  mocked @cossistant/redis partially, dropping createRedisConnection.

- packages/jobs ai-agent-background asserted a 60s default delay;
  AI_AGENT_BACKGROUND_DELAY_MS is 30s. The test now reads the exported constant
  instead of hardcoding it.

Full suite: 18/18 turbo test tasks pass — web 692, api 703, jobs 52, workers 33,
memory 33, facehash 24, protocol 18, release 8, tiny-markdown 7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

fake-support-context rebuilt its state object on every getState/getSnapshot
call. useSyncExternalStore requires getSnapshot to return a stable reference
between store changes — a fresh object each call makes React see a new snapshot
on every render and bail out with "Maximum update depth exceeded". Its
subscribe() was also a no-op, so store changes never reached React.

Harmless today because nothing subscribes to the controller through
useSyncExternalStore. #161 adds useStoreSelector(controller, ...) inside
useSupport(), at which point the timeline UI test page infinite-loops — in the
browser as well as in tests.

The real controller in @cossistant/core already does this correctly: it holds
`snapshot` in a closure and rebuilds it only in syncSnapshot(). The fake now
mirrors that and forwards store changes to its subscribers, so it satisfies the
contract in both cases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@Rieranthony
Rieranthony merged commit 7178c62 into main Aug 3, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant