Skip to content

fix(quotes): fix stale mock in cloneQuote test after pax8 select insertion#2563

Merged
ToddHebebrand merged 1 commit into
mainfrom
fix/quote-image-clone-testapi
Jul 16, 2026
Merged

fix(quotes): fix stale mock in cloneQuote test after pax8 select insertion#2563
ToddHebebrand merged 1 commit into
mainfrom
fix/quote-image-clone-testapi

Conversation

@ToddHebebrand

Copy link
Copy Markdown
Collaborator

Summary

Fixes the red Test API CI job on main (quoteService.clone.test.ts).

Root cause

Not a product bug — a stale mock in quoteService.clone.test.ts after two independently-merged PRs interacted:

quoteService.clone.test.ts mocks db.select() with a shared FIFO queue of canned results, and pushed exactly 4 entries (quote, blocks, lines, images) — the correct count before #2501 landed. With the extra pax8OrderSummary select now spliced into getQuote(), the queue's "images" entry was consumed by the pax8OrderSummary destructure instead, so the real quoteImages select fell through to the queue's empty-array default. imageIds ended up an empty Map, so remapping the image block's imageId legitimately found nothing and cloneQuote correctly threw QuoteServiceError('Quote image could not be cloned', 409, 'IMAGE_NOT_FOUND').

Confirmed this can't happen in production: real Postgres queries are scoped by real WHERE clauses per table and can't cross-contaminate the way the mock's shared queue does.

Fix

apps/api/src/services/quoteService.clone.test.ts: push one extra empty result for the pax8OrderSummary select (i.e. "no staged Pax8 order for this quote"), which also correctly short-circuits the conditional pax8OrderLineSummary select exactly as the real code does. This makes the mock's select order match getQuote()'s actual current select order.

Verification

  • pnpm vitest run src/services/quoteService.clone.test.ts src/services/quoteService.test.ts src/services/quoteLifecycle.test.ts — 31/31 passing (was 1 failing).
  • pnpm vitest run src/services/ (full suite, 5825 tests) — all green except one unrelated pre-existing timing flake in encryptedColumnRegistry.test.ts (5000ms scrypt timeout), confirmed to pass in isolation and untouched by this change.
  • Node 22.20.0, matching .nvmrc.

🤖 Generated with Claude Code

…rtion

Main's Test API job was red: quoteService.clone.test.ts threw
QuoteServiceError "Quote image could not be cloned" (IMAGE_NOT_FOUND).

Root cause: #2501 (pax8 ordering) added two DB selects inside
getQuote() — a pax8OrderSummary lookup and a conditional
pax8OrderLineSummary lookup — between the existing lines select and
getQuote()'s return. cloneQuote() (added by #2535) calls getQuote()
and then issues its own quoteImages select immediately after. The
clone test's mock drives a shared FIFO queue of select results with
exactly 4 entries (quote, blocks, lines, images), assuming getQuote
only issues 3 selects. With the extra pax8OrderSummary select spliced
in, that queue's "images" entry got consumed by the pax8OrderSummary
destructure instead, so the real images select fell through to an
empty default result. imageIds ended up an empty Map, so remapping the
image block's imageId legitimately found nothing and threw.

This is a stale-test problem, not a product bug: real Postgres
queries are scoped by real WHERE clauses and can't cross-contaminate
like the mock's shared queue does. Fixed by pushing an extra empty
result for the pax8OrderSummary select (no staged order), matching
production's actual select order and short-circuiting the conditional
pax8OrderLineSummary select exactly as the real code does.

Verified: quoteService.clone.test.ts, quoteService.test.ts,
quoteLifecycle.test.ts all green; full src/services/ suite green
(one unrelated pre-existing timing flake in
encryptedColumnRegistry.test.ts, confirmed to pass in isolation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ToddHebebrand
ToddHebebrand merged commit df3d8f2 into main Jul 16, 2026
27 of 28 checks passed
@ToddHebebrand
ToddHebebrand deleted the fix/quote-image-clone-testapi branch July 16, 2026 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant