Skip to content

(SP: 3) [Backend] Harden Stripe webhook processing and stabilize tests (dedupe/idempotency, raw-body signature path, cleanup + small janitor/admin nitpicks)#123

Merged
ViktorSvertoka merged 1 commit into
developfrom
lso/feat/shop
Jan 9, 2026
Merged

(SP: 3) [Backend] Harden Stripe webhook processing and stabilize tests (dedupe/idempotency, raw-body signature path, cleanup + small janitor/admin nitpicks)#123
ViktorSvertoka merged 1 commit into
developfrom
lso/feat/shop

Conversation

@liudmylasovetovs
Copy link
Copy Markdown
Collaborator

@liudmylasovetovs liudmylasovetovs commented Jan 9, 2026

Description

This PR hardens Stripe webhook processing and stabilizes the associated test suite after recent shop payment/ledger changes. It focuses on correctness and idempotency in webhook handling (paid/refund flows), plus small follow-up fixes in admin products and the janitor runner to reduce operational risk.


Related Issue

Issue: #<issue_number>


Changes

  • Strengthened Stripe webhook processing to be more resilient and deterministic:
    • Improved validation around Stripe objects (e.g., PaymentIntent/Charge linkage and identifiers).
    • Ensured safer idempotency / dedupe behavior in webhook flows (paid, refund, retry scenarios).
    • Reduced ambiguity in error paths to prevent partial side effects.
  • Stabilized webhook-related tests and removed flakiness:
    • Fixed mock hoisting / ordering issues.
    • Applied Biome-safe cleanup where it affected test reliability.
    • Added/updated coverage for webhook repair / refund edge cases and concurrency behavior.
  • Small operational/UI follow-ups:
    • Admin Products: minor fixes to align currency display/handling and reduce UI friction (overflow-related follow-up).
    • Janitor runner script: minor adjustments to improve robustness when invoking the internal restock-stale endpoint.

Database Changes (if applicable)

  • Schema migration required
  • Seed data updated
  • Breaking changes to existing queries
  • Transaction-safe migration
  • Migration tested locally on Neon

How Has This Been Tested?

  • Tested locally
  • Verified in development environment
  • Checked responsive layout (if UI-related)
  • Tested accessibility (keyboard / screen reader)

Commands

  • npx vitest run (23 files / 56 tests passed)
  • npm run build (Next.js build succeeded)

Screenshots (if applicable)

N/A (UI changes are minor / non-visual or not meaningful to capture)


Checklist

Before submitting

  • Code has been self-reviewed
  • No TypeScript or console errors (build passes; test logs expected for webhook contract tests)
  • Code follows project conventions
  • Scope is limited to this feature/fix
  • No unrelated refactors included
  • English used in code, commits, and docs
  • New dependencies discussed with team
  • Database migration tested locally (if applicable)
  • GitHub Projects card moved to In Review

Reviewers

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling and logging for admin product management operations
    • Enhanced input validation for payment processing to prevent runtime errors
    • Fixed stock restoration logic to prevent unnecessary inventory restocking
    • Refined refund processing with better edge-case handling and amount detection
    • Stricter validation for environment configuration parameters
  • Improvements

    • Enhanced webhook processing with conditional logic for order state management
    • Better error tracking and reporting across payment operations

✏️ Tip: You can customize this high-level summary in your review settings.

…nup, mock hoisting, PI id validation) and apply small admin/janitor nitpicks
@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 9, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit edeaa36
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/696188fb29d01900086fabd4
😎 Deploy Preview https://deploy-preview-123--develop-devlovers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Enhanced payment validation and refund handling across admin products, API routes, and Stripe webhook processing. Added input validation for Stripe operations, hardened error type guards, introduced conditional restocking logic, and improved test infrastructure with dynamic imports and comprehensive webhook scenario coverage.

Changes

Cohort / File(s) Summary
Admin Products UI
frontend/app/[locale]/shop/admin/products/page.tsx
Enhanced safeFromDbMoney utility with context parameter (productId, currency) for improved error logging; calls now pass context containing row id and display currency.
Admin API Validation
frontend/app/api/shop/admin/products/[id]/route.ts, frontend/app/api/shop/admin/products/route.ts
Hardened isInvalidPricesJsonError type guards by explicitly checking for null/non-object values before accessing code property; replaced truthy checks with safer Record-based casting.
Stripe PSP Utility
frontend/lib/psp/stripe.ts
Added input validation to retrievePaymentIntent (throws on empty ID) and retrieveCharge (throws on empty chargeId); minor formatting updates throughout; no public API signature changes.
Stripe Webhook Handler
frontend/app/api/shop/webhooks/stripe/route.ts
Introduced shouldRestockFromWebhook helper to conditionally gate restock calls based on stockRestored and inventoryStatus fields; hardened refund fullness logic with cumulativeRefunded calculation and REFUND_FULLNESS_UNDETERMINED fallback; extended order retrieval to include new fields.
Test Infrastructure
frontend/lib/tests/checkout-concurrency-stock1.test.ts, frontend/lib/tests/stripe-webhook-paid-status-repair.test.ts
Switched to dynamic imports with vi mocking utilities; replaced environment mutations with vi.stubEnv/vi.unstubAllEnvs for test isolation; conditional cleanup logic.
Webhook Test Scenarios
frontend/lib/tests/stripe-webhook-refund-full.test.ts
Added test helpers (makeCharge, makeRequest, insertPaidOrder); expanded test coverage for refund paths via charge.refunded, charge.refund.updated; added edge cases (missing amount_refunded, restock retry logic); introduced mock verification for retrieveCharge and restockOrder calls.
Complex Test Updates
frontend/lib/tests/order-items-snapshot-immutable.test.ts
Reformatted imports and mock setup; replaced static import with dynamic runtime import; enhanced error tracking with primaryError/cleanupError variables for improved failure propagation.
Shop Janitor Script
frontend/scripts/shop-janitor-restock-stale.mjs
Replaced permissive numeric parsing of JANITOR_TIMEOUT_MS with strict digits-only validation; retains default timeout on non-numeric input with appropriate logging.

Sequence Diagram(s)

sequenceDiagram
    participant Webhook as Stripe Webhook
    participant Handler as Webhook Handler
    participant DB as Database
    participant Restock as Restock Service
    participant PSP as PSP/Stripe

    Webhook->>Handler: Receive payment_intent.succeeded
    Handler->>DB: Fetch order (with stockRestored, inventoryStatus)
    DB-->>Handler: Return order
    Handler->>Handler: Check shouldRestockFromWebhook(order)
    
    alt Should Restock (stockRestored=false, inventoryStatus≠'released')
        Handler->>Restock: Trigger restock
        Restock-->>Handler: Success
        Handler->>DB: Update order (stockRestored=true)
    else Should Not Restock
        Handler->>Handler: Skip restock (gate prevents call)
    end
    Handler-->>Webhook: Complete

    Webhook->>Handler: Receive charge.refund.updated
    Handler->>DB: Fetch order
    DB-->>Handler: Return order
    Handler->>PSP: retrieveCharge(chargeId) - get refunds.data
    PSP-->>Handler: Charge with refund details
    Handler->>Handler: Calculate cumulativeRefunded or fullness
    
    alt Full Refund Detected
        Handler->>Handler: Check shouldRestockFromWebhook(order)
        alt Should Restock
            Handler->>Restock: Trigger restock
            Restock-->>Handler: Success
        end
        Handler->>DB: Update order (full refund state, stockRestored=true)
    else Partial Refund
        Handler->>DB: Mark PARTIAL_REFUND_IGNORED, keep state
    end
    Handler-->>Webhook: Complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • AM1007
  • ViktorSvertoka

Poem

🐰✨ Hops through the refunds with glee,
Validations tightened, safe and free!
Conditional restocks guard the way,
Tests now mock what they need to say.
Payment flows sparkle, errors caught—
A rabbit's delight, just as I sought! 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: hardening Stripe webhook processing and stabilizing tests, with mentions of specific improvements (dedupe/idempotency, signature verification) and smaller fixes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @frontend/lib/tests/stripe-webhook-paid-status-repair.test.ts:
- Around line 113-123: The afterEach currently only calls cleanupByIds when both
lastOrderId and lastEventId are truthy, leaving orphaned records if only one was
set; update the afterEach to always attempt cleanup by calling cleanupByIds if
either lastOrderId or lastEventId is truthy (or invoke separate cleanup calls
for order and event when each ID is present), ensuring you reference and clear
lastOrderId and lastEventId after awaiting cleanup so no test-state leaks
remain; modify the afterEach closure that references lastOrderId, lastEventId,
and cleanupByIds accordingly.
🧹 Nitpick comments (1)
frontend/app/api/shop/webhooks/stripe/route.ts (1)

662-664: Throwing REFUND_FULLNESS_UNDETERMINED returns 500 and triggers retry — verify this is intentional.

When amt or cumulativeRefunded cannot be determined, the code throws REFUND_FULLNESS_UNDETERMINED, which bubbles up to the catch block at line 802-804 and returns a 500 error. This triggers Stripe to retry the webhook.

This is a deliberate design choice (fail-safe over fail-silent), which is good for data integrity. However, if Stripe consistently sends malformed events, this could cause repeated 500s and eventual webhook disabling by Stripe.

Consider logging a specific warning before throwing to aid debugging:

💡 Optional: Add structured logging before throwing
         if (amt == null || cumulativeRefunded == null) {
+          console.warn('stripe_webhook_refund_fullness_undetermined', {
+            eventId: event.id,
+            chargeAmount: amt,
+            cumulativeRefunded,
+            eventType,
+          });
           throw new Error('REFUND_FULLNESS_UNDETERMINED');
         }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9df9fd and edeaa36.

📒 Files selected for processing (10)
  • frontend/app/[locale]/shop/admin/products/page.tsx
  • frontend/app/api/shop/admin/products/[id]/route.ts
  • frontend/app/api/shop/admin/products/route.ts
  • frontend/app/api/shop/webhooks/stripe/route.ts
  • frontend/lib/psp/stripe.ts
  • frontend/lib/tests/checkout-concurrency-stock1.test.ts
  • frontend/lib/tests/order-items-snapshot-immutable.test.ts
  • frontend/lib/tests/stripe-webhook-paid-status-repair.test.ts
  • frontend/lib/tests/stripe-webhook-refund-full.test.ts
  • frontend/scripts/shop-janitor-restock-stale.mjs
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/app/[locale]/shop/admin/products/page.tsx (1)
frontend/lib/shop/money.ts (1)
  • fromDbMoney (51-56)
frontend/app/api/shop/webhooks/stripe/route.ts (2)
frontend/db/schema/shop.ts (1)
  • orders (107-198)
frontend/lib/services/orders.ts (2)
  • restockOrder (1039-1197)
  • restockOrder (1640-1640)
🔇 Additional comments (18)
frontend/app/api/shop/admin/products/route.ts (1)

26-31: LGTM: Improved type guard with explicit validation.

The explicit null and type checks are safer than the previous truthy coercion (!!value). This guards against edge cases where value might be a primitive (string, number, boolean) that would pass a truthy check but fail when accessing .code.

frontend/app/api/shop/admin/products/[id]/route.ts (1)

32-37: LGTM: Consistent type guard improvement.

Matches the safer validation pattern from the sibling route file. Good consistency across the codebase.

frontend/scripts/shop-janitor-restock-stale.mjs (1)

22-46: LGTM: Robust timeout validation.

The strict digit-only regex and safe integer validation appropriately harden the input handling. The distinct warning messages for different failure modes improve debuggability.

frontend/lib/tests/stripe-webhook-paid-status-repair.test.ts (1)

60-62: LGTM: Better test isolation with stubEnv.

Using vi.stubEnv instead of directly mutating process.env is the correct approach for test environment variable handling. The corresponding vi.unstubAllEnvs() in afterEach ensures proper cleanup.

frontend/app/[locale]/shop/admin/products/page.tsx (1)

15-33: LGTM: Enhanced observability with context-aware logging.

The additional context (productId, currency, valueType) in the warning message provides excellent debugging information when money conversion fails. The early return for null values is cleaner. All call sites have been properly updated—there is one call site at line 123 that correctly passes the new context parameter.

frontend/lib/tests/checkout-concurrency-stock1.test.ts (1)

2-2: LGTM! Dynamic import pattern correctly ensures mock hoisting.

The dynamic import of the checkout route after mock installation is the correct approach for vitest. This ensures vi.mock calls are hoisted and in effect before the module under test is loaded, preventing flaky behavior from static imports racing with mock setup.

Also applies to: 16-17, 124-126

frontend/lib/psp/stripe.ts (2)

82-84: LGTM! Defensive input validation prevents invalid Stripe API calls.

The early validation for empty paymentIntentId is a good safeguard that fails fast with a clear error message rather than making an API call that would fail anyway.


104-106: LGTM! Consistent validation pattern for charge retrieval.

Same defensive validation applied to retrieveCharge, maintaining consistency across Stripe utility functions.

frontend/lib/tests/order-items-snapshot-immutable.test.ts (2)

123-125: LGTM! Dynamic import ensures mocks are in place.

Consistent with the pattern used in checkout-concurrency-stock1.test.ts.


140-141: LGTM! Improved error handling ensures cleanup failures are surfaced.

The primaryError/cleanupError pattern ensures:

  1. Primary test failures are propagated immediately (line 216)
  2. Cleanup always runs in finally
  3. Silent cleanup failures are surfaced when the primary test passes (lines 225-227)

This prevents flaky test state from accumulating due to hidden cleanup issues.

Also applies to: 214-227

frontend/app/api/shop/webhooks/stripe/route.ts (3)

115-124: LGTM! Webhook-level restock gate prevents redundant calls.

The shouldRestockFromWebhook helper correctly implements an early-exit check that mirrors the guards in restockOrder (per the relevant code snippet from frontend/lib/services/orders.ts). This avoids unnecessary work and potential race conditions from multiple restock attempts.


324-325: LGTM! Required fields for restock gating are now fetched.

The order select now includes stockRestored and inventoryStatus, which are required for the shouldRestockFromWebhook decision.


541-543: LGTM! Restock calls are now consistently gated.

All restock invocations (payment_failed, payment_canceled, charge.refunded/charge.refund.updated) now use the shouldRestockFromWebhook guard, ensuring idempotent behavior and avoiding redundant restocking when inventory has already been released.

Also applies to: 592-594, 781-783

frontend/lib/tests/stripe-webhook-refund-full.test.ts (5)

9-19: LGTM! Mock setup correctly exposes both Stripe functions.

The mock now properly exposes both verifyWebhookSignature and retrieveCharge, enabling comprehensive testing of webhook flows that require charge retrieval.


86-118: LGTM! makeCharge helper provides flexible test data construction.

The helper cleanly constructs Stripe.Charge objects with configurable refunds, enabling tests to cover various refund scenarios (full, partial, multiple refunds). The as unknown as Stripe.Charge cast is acceptable for test data.


312-378: Excellent coverage for retry-after-failure scenario.

This test validates critical behavior: when restockOrder fails (500 returned), the event's processedAt remains NULL, allowing Stripe's retry to reprocess successfully. This ensures restock is not lost due to transient failures.


445-494: LGTM! Edge case coverage for missing amount_refunded.

This test validates the fallback logic in the webhook route (lines 640-660) where amount_refunded is missing and the cumulative must be computed from the refunds list. The explicit delete (charge as any).amount_refunded simulates the edge case effectively.


44-60: LGTM! Typed row object improves type safety.

Using typeof orders.$inferInsert for the row definition ensures the test data matches the schema, reducing the risk of test failures due to schema drift.

Comment on lines +640 to +664
// Fallback: sum refunds list if amount_refunded is missing
if (
cumulativeRefunded == null &&
Array.isArray((effectiveCharge as any)?.refunds?.data)
) {
const list = (effectiveCharge as any).refunds.data as any[];
const sumFromList = list.reduce((sum, r) => {
const a = typeof r?.amount === 'number' ? r.amount : 0;
return sum + a;
}, 0);

const currentAmt =
typeof (refund as any)?.amount === 'number'
? (refund as any).amount
: 0;

const hasCurrent =
refund?.id && list.some(r => r?.id && r.id === refund.id);

cumulativeRefunded = sumFromList + (hasCurrent ? 0 : currentAmt);
}

if (amt == null || cumulativeRefunded == null) {
throw new Error('REFUND_FULLNESS_UNDETERMINED');
}
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

git ls-files frontend/app/api/shop/webhooks/stripe/ | head -20

Repository: DevLoversTeam/devlovers.net

Length of output: 117


🏁 Script executed:

wc -l frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 121


🏁 Script executed:

# Search for the charge.refunded event handler around line 609
sed -n '600,620p' frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 682


🏁 Script executed:

# Also search for the full refund determination logic
sed -n '600,680p' frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 2961


🏁 Script executed:

# Search for refundObject assignment/definition
sed -n '1,610p' frontend/app/api/shop/webhooks/stripe/route.ts | grep -n "refundObject" | head -20

Repository: DevLoversTeam/devlovers.net

Length of output: 454


🏁 Script executed:

# Get more context around where refundObject is used
sed -n '570,610p' frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 1114


🏁 Script executed:

# Get context around refundObject initialization
sed -n '160,190p' frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 963


🏁 Script executed:

# Check the event type and object type logic
sed -n '140,180p' frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 1425


🏁 Script executed:

# Check if there's any refund amount data available in charge.refunded event
sed -n '609,675p' frontend/app/api/shop/webhooks/stripe/route.ts | head -80

Repository: DevLoversTeam/devlovers.net

Length of output: 2663


🏁 Script executed:

# Search for any comments or documentation about Stripe charge.refunded event structure
grep -n "charge.refunded" frontend/app/api/shop/webhooks/stripe/route.ts | head -20

Repository: DevLoversTeam/devlovers.net

Length of output: 223


🏁 Script executed:

# Check if there's any information about refund amount in the charge object itself during charge.refunded
sed -n '600,650p' frontend/app/api/shop/webhooks/stripe/route.ts | grep -E "(amount|refund)" -A 2 -B 2

Repository: DevLoversTeam/devlovers.net

Length of output: 1712


🏁 Script executed:

# Look for how charge.refunded is documented or any comments about Stripe API structure
grep -n "amount_refunded\|refunds.data" frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 687


🏁 Script executed:

# Check Stripe API documentation comments or any related notes in the codebase
grep -n "Stripe\|refund\|amount_refunded" frontend/app/api/shop/webhooks/stripe/route.ts | grep -i "comment\|note\|todo\|bug\|fixme" -A 2 -B 2

Repository: DevLoversTeam/devlovers.net

Length of output: 53


🏁 Script executed:

# Look at the entire charge.refunded block to see if there's any other way amount_refunded or refund data could be obtained
sed -n '627,675p' frontend/app/api/shop/webhooks/stripe/route.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 1994


Clarify handling when refunds list is unavailable in charge.refunded events.

The fallback logic at lines 640-664 correctly sums charge.refunds.data when amount_refunded is missing. However, the edge case the reviewer identified is valid: if charge.refunds.data is empty AND refund is null (because charge?.refunds?.data?.[0] returns undefined), then cumulativeRefunded becomes 0, not null. Since the error check at line 663 only throws when cumulativeRefunded == null, it proceeds with isFullRefund = (0 === amt), which will be false even if a full refund just occurred.

This can happen due to API timing: the charge.refunded webhook event fires before the charge object's refunds.data array is populated. The current logic treats this as "no refunds recorded" (cumulativeRefunded = 0) rather than "refund status undetermined."

Consider either:

  1. Throwing REFUND_FULLNESS_UNDETERMINED when the refunds list is empty and refund data cannot be extracted from the event, or
  2. Adding a check that validates whether currentAmt could actually be determined from the event before relying on the fallback calculation.

Comment on lines 113 to 123
afterEach(async () => {
if (!lastOrderId || !lastEventId) return;
await cleanupByIds({ orderId: lastOrderId, eventId: lastEventId });
// restore env stubs to avoid cross-test coupling
vi.unstubAllEnvs();

if (lastOrderId && lastEventId) {
await cleanupByIds({ orderId: lastOrderId, eventId: lastEventId });
}

lastOrderId = null;
lastEventId = null;
});
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.

⚠️ Potential issue | 🟡 Minor

Potential test cleanup gap with conditional logic.

The cleanup now requires both lastOrderId AND lastEventId to be truthy (line 117). If a test fails after setting only one ID, cleanup won't execute, potentially leaving orphaned records in the database.

🧹 Proposed fix to ensure cleanup always runs
  afterEach(async () => {
    // restore env stubs to avoid cross-test coupling
    vi.unstubAllEnvs();

-   if (lastOrderId && lastEventId) {
+   if (lastOrderId || lastEventId) {
      await cleanupByIds({ orderId: lastOrderId, eventId: lastEventId });
    }

    lastOrderId = null;
    lastEventId = null;
  });

Alternatively, clean up each resource independently:

  afterEach(async () => {
    vi.unstubAllEnvs();

-   if (lastOrderId && lastEventId) {
-     await cleanupByIds({ orderId: lastOrderId, eventId: lastEventId });
-   }
+   if (lastEventId) {
+     try {
+       await db.delete(stripeEvents).where(eq(stripeEvents.eventId, lastEventId));
+     } catch (e) {
+       console.error('[test cleanup]', e);
+     }
+   }
+   if (lastOrderId) {
+     try {
+       await db.delete(orders).where(eq(orders.id, lastOrderId));
+     } catch (e) {
+       console.error('[test cleanup]', e);
+     }
+   }

    lastOrderId = null;
    lastEventId = null;
  });
🤖 Prompt for AI Agents
In @frontend/lib/tests/stripe-webhook-paid-status-repair.test.ts around lines
113 - 123, The afterEach currently only calls cleanupByIds when both lastOrderId
and lastEventId are truthy, leaving orphaned records if only one was set; update
the afterEach to always attempt cleanup by calling cleanupByIds if either
lastOrderId or lastEventId is truthy (or invoke separate cleanup calls for order
and event when each ID is present), ensuring you reference and clear lastOrderId
and lastEventId after awaiting cleanup so no test-state leaks remain; modify the
afterEach closure that references lastOrderId, lastEventId, and cleanupByIds
accordingly.

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.

2 participants