Skip to content

Commit 6e7ba99

Browse files
committed
test: wait on the API view before asserting checkout expiry
The waiter polled Postgres, which the handler updates before the refresh middleware drops the cached subject, so customers.get could still serve the plan for a few ms after the predicate resolved. Poll the cache-backed API view instead and assert the DB row afterwards. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EUxZ3wtxSsZ1nC9YrPwjG1
1 parent b8ce5f9 commit 6e7ba99

1 file changed

Lines changed: 14 additions & 10 deletions

File tree

server/tests/integration/billing/attach/checkout/stripe-checkout/stripe-checkout-enable-plan-immediately.test.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,28 +211,32 @@ test.concurrent(`${chalk.yellowBright("stripe-checkout enable_plan_immediately:
211211
expect(before.some((cp) => cp.product.id === pro.id)).toBe(true);
212212

213213
// 2. Abandon the checkout: expire the session on Stripe, which emits
214-
// `checkout.session.expired`, then wait for Autumn to expire the row.
214+
// `checkout.session.expired`. Wait on the cache-backed API view, not the
215+
// DB row: the handler expires the row first and the refresh middleware
216+
// drops the cached subject after it returns, so a DB-only predicate can
217+
// resolve before `customers.get` stops reporting the plan.
215218
await ctx.stripeCli.checkout.sessions.expire(checkoutSessionId!);
216219

217-
const isProActiveInDb = async () => {
218-
const active = await CusProductService.list({
219-
db: ctx.db,
220-
internalCustomerId,
221-
inStatuses: [CusProductStatus.Active],
222-
});
223-
return active.some((cp) => cp.product.id === pro.id);
220+
const isProActiveInApi = async () => {
221+
const customer = await autumnV1.customers.get<ApiCustomerV3>(customerId);
222+
return (customer.products ?? []).some((product) => product.id === pro.id);
224223
};
225224

226225
await waitForStripeWebhook({
227226
stripeCli: ctx.stripeCli,
228227
env: ctx.env,
229228
types: ["checkout.session.expired"],
230229
objectId: checkoutSessionId!,
231-
until: async () => !(await isProActiveInDb()),
230+
until: async () => !(await isProActiveInApi()),
232231
});
233232

234233
// 3. After expiry: cusProduct should no longer be Active.
235-
expect(await isProActiveInDb()).toBe(false);
234+
const after = await CusProductService.list({
235+
db: ctx.db,
236+
internalCustomerId,
237+
inStatuses: [CusProductStatus.Active],
238+
});
239+
expect(after.some((cp) => cp.product.id === pro.id)).toBe(false);
236240

237241
// API view: pro is not active.
238242
const customerAfter = await autumnV1.customers.get<ApiCustomerV3>(customerId);

0 commit comments

Comments
 (0)