fix(e2e): WebAuthn on prod build, saved-filters navigation, Vercel scripts
CI e2e serves a production build on localhost; Next inlines NODE_ENV so WebAuthn RP resolution now treats localhost requests as test mode. Saved filters avoids a racing bare goto. Analytics/SpeedInsights render only on Vercel.
This commit is contained in:
parent
865c9e0a32
commit
30170509f7
4 changed files with 36 additions and 7 deletions
|
|
@ -77,8 +77,12 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
|
|||
>
|
||||
<body className="antialiased w-screen scrollbar-hide overflow-hidden">
|
||||
<ThemeProvider attribute="class">
|
||||
<SpeedInsights />
|
||||
<Analytics />
|
||||
{process.env.VERCEL === '1' ? (
|
||||
<>
|
||||
<SpeedInsights />
|
||||
<Analytics />
|
||||
</>
|
||||
) : null}
|
||||
<RefreshRouteOnSave />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ export type CampaignWebAuthnRelyingParty = {
|
|||
|
||||
const RP_NAME = 'Campanha Jorge Solla'
|
||||
|
||||
/** Matches `LOCAL_AUTHORITY_PATTERN` in `campaignInviteOrigin` — kept local on purpose. */
|
||||
const LOCAL_REQUEST_HOST = /^(localhost|127\.0\.0\.1|\[::1\])(?::[0-9]{1,5})?$/i
|
||||
|
||||
const isLocalRequestHost = (host: string | undefined): boolean =>
|
||||
Boolean(host && LOCAL_REQUEST_HOST.test(host))
|
||||
|
||||
/**
|
||||
* The authority the browser is actually talking to, which is what has to agree
|
||||
* with the relying party. Compared as `host` (name + port) and not as a full
|
||||
|
|
@ -61,9 +67,17 @@ const requestHostOf = ({
|
|||
export const getCampaignWebAuthnRelyingParty = (
|
||||
input: CampaignInviteOriginInput = {},
|
||||
): CampaignWebAuthnRelyingParty | null => {
|
||||
const requestHost = requestHostOf(input)
|
||||
// `getCampaignInviteBaseURL` reads `process.env.NODE_ENV`, which Next inlines
|
||||
// at build time as `"production"`. CI e2e serves that build on
|
||||
// http://localhost:3000 (`pnpm start`), which would otherwise demand HTTPS
|
||||
// DNS and hide biometrics. The request host is authoritative here.
|
||||
const environment =
|
||||
input.environment ?? (isLocalRequestHost(requestHost) ? ('test' as const) : undefined)
|
||||
|
||||
let baseURL: string
|
||||
try {
|
||||
baseURL = getCampaignInviteBaseURL(input)
|
||||
baseURL = getCampaignInviteBaseURL(environment ? { ...input, environment } : input)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
|
|
@ -74,7 +88,6 @@ export const getCampaignWebAuthnRelyingParty = (
|
|||
|
||||
// Absent host: a non-request context (a script, a test) that cannot be
|
||||
// checked. The ceremonies always pass the headers.
|
||||
const requestHost = requestHostOf(input)
|
||||
if (requestHost && requestHost !== url.host.toLowerCase()) return null
|
||||
|
||||
return { rpID, rpName: RP_NAME, origin: url.origin }
|
||||
|
|
|
|||
|
|
@ -55,11 +55,14 @@ test.describe('Filtros salvos de Municípios', () => {
|
|||
await expect(shortcut).toHaveAttribute('aria-current', 'page')
|
||||
|
||||
// A page is a position inside the recorte, not part of it.
|
||||
await page.goto(`${SAVED_RECORTE}&page=2`)
|
||||
await page.goto(`${SAVED_RECORTE}&page=2`, NAVIGATION)
|
||||
await expect(shortcut).toHaveAttribute('aria-current', 'page')
|
||||
|
||||
// Another recorte is not this one, and the shortcut brings it back.
|
||||
await page.goto('/campanha/municipios')
|
||||
// Another recorte is not this one, and the shortcut brings it back. Use the
|
||||
// sidebar link — a bare `goto` here races an in-flight RSC navigation and
|
||||
// flakes as net::ERR_ABORTED under prod load (measured in CI 2026-07-30).
|
||||
await page.getByRole('link', { name: 'Municípios', exact: true }).click()
|
||||
await expect(page).toHaveURL('/campanha/municipios', NAVIGATION)
|
||||
await expect(shortcut).not.toHaveAttribute('aria-current', 'page')
|
||||
await shortcut.click()
|
||||
await expect(page).toHaveURL(SAVED_RECORTE, NAVIGATION)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,15 @@ describe('getCampaignWebAuthnRelyingParty', () => {
|
|||
).toMatchObject({ rpID: 'localhost', origin: 'http://localhost:3100' })
|
||||
})
|
||||
|
||||
it('follows localhost when a production build is served there (CI e2e)', () => {
|
||||
expect(
|
||||
getCampaignWebAuthnRelyingParty({
|
||||
configuredURL: 'https://pt.jorgesolla.com.br',
|
||||
forwardedHost: 'localhost:3000',
|
||||
}),
|
||||
).toMatchObject({ rpID: 'localhost', origin: 'http://localhost:3000' })
|
||||
})
|
||||
|
||||
it('refuses production without a configured site URL', () => {
|
||||
expect(
|
||||
getCampaignWebAuthnRelyingParty({ environment: 'production', configuredURL: undefined }),
|
||||
|
|
|
|||
Loading…
Reference in a new issue