From 50feb3ac6b30e8fdcb6b6a70777b283a38f00c00 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 11 Sep 2026 13:21:18 -0700 Subject: [PATCH] test(e2e): fail the WhatsApp suite fast when FAPI downgrades the channel When the instance's WhatsApp OTP quota is exhausted FAPI silently answers the sign-up or sign-in create with channel "sms". The suite then spent six 10s locator timeouts per test hunting for the "Send code via SMS instead" link. Assert the channel on the create response so the failure names its cause. --- .changeset/e2e-whatsapp-channel-assert.md | 2 ++ integration/tests/whatsapp-phone-code.test.ts | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 .changeset/e2e-whatsapp-channel-assert.md diff --git a/.changeset/e2e-whatsapp-channel-assert.md b/.changeset/e2e-whatsapp-channel-assert.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/e2e-whatsapp-channel-assert.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/integration/tests/whatsapp-phone-code.test.ts b/integration/tests/whatsapp-phone-code.test.ts index ed48df1b3f4..391f7bf2da8 100644 --- a/integration/tests/whatsapp-phone-code.test.ts +++ b/integration/tests/whatsapp-phone-code.test.ts @@ -1,4 +1,5 @@ /* eslint-disable turbo/no-undeclared-env-vars */ +import type { Page } from '@playwright/test'; import { expect, test } from '@playwright/test'; import type { Application } from '../models/application'; @@ -6,6 +7,22 @@ import { appConfigs } from '../presets'; import type { FakeUser } from '../testUtils'; import { createTestUtils } from '../testUtils'; +const channelOf = { + '/sign_ups': (body: any) => body.verifications.phone_number.channel, + '/sign_ins': (body: any) => body.first_factor_verification.channel, +}; + +function expectWhatsAppChannel(page: Page, path: keyof typeof channelOf) { + const response = page.waitForResponse(res => res.url().includes(path) && res.request().method() === 'POST'); + return async () => { + const { response: body } = await (await response).json(); + expect( + channelOf[path](body), + 'FAPI downgraded the WhatsApp channel to SMS. The instance WhatsApp OTP quota is likely exhausted.', + ).toBe('whatsapp'); + }; +} + test.describe('sign up and sign in with WhatsApp phone code @generic', () => { // The WhatsApp alternate phone-code channel is not provisioned on the staging // instance, so the WhatsApp sign-up button never renders there and every test in @@ -59,10 +76,12 @@ test.describe('sign up and sign in with WhatsApp phone code @generic', () => { // Click on WhatsApp button await page.getByRole('button', { name: new RegExp(`WhatsApp`, 'gi') }).click(); + const assertChannel = expectWhatsAppChannel(page, '/sign_ups'); // Fill in sign up form with phone number await u.po.signUp.signUp({ phoneNumber: fakeUser.phoneNumber, }); + await assertChannel(); // intercept the request to /prepare_verification await page.context().route('**/prepare_verification*', async route => { @@ -98,9 +117,11 @@ test.describe('sign up and sign in with WhatsApp phone code @generic', () => { // Click on WhatsApp button await page.getByRole('button', { name: new RegExp(`WhatsApp`, 'gi') }).click(); + const assertChannel = expectWhatsAppChannel(page, '/sign_ins'); // Fill in WhatsApp sign in form with phone number await u.po.signIn.getIdentifierInput().fill(fakeUser.phoneNumber); await u.po.signIn.continue(); + await assertChannel(); // intercept the request to /prepare_first_factor await page.context().route('**/prepare_first_factor*', async route => { @@ -137,9 +158,11 @@ test.describe('sign up and sign in with WhatsApp phone code @generic', () => { await route.continue(); }); + const assertChannel = expectWhatsAppChannel(page, '/sign_ins'); // Fill in the sign in form with the test US phone number await u.po.signIn.getIdentifierInput().fill(fakeUser.phoneNumber); await u.po.signIn.continue(); + await assertChannel(); // intercept the request to /prepare_first_factor await page.context().route('**/prepare_first_factor*', async route => {