diff --git a/website/tests/e2e.fixture.ts b/website/tests/e2e.fixture.ts index 9f4e86b982..89cd32dcf3 100644 --- a/website/tests/e2e.fixture.ts +++ b/website/tests/e2e.fixture.ts @@ -15,6 +15,7 @@ import { SequencePage } from './pages/sequences/sequences.page'; import { SubmitPage } from './pages/submission/submit.page'; import { GroupPage } from './pages/user/group/group.page.ts'; import { UserPage } from './pages/user/userPage/userPage.ts'; +import { throwOnConsole } from './util/throwOnConsole.ts'; import { ACCESS_TOKEN_COOKIE, REFRESH_TOKEN_COOKIE } from '../src/middleware/authMiddleware'; import { BackendClient } from '../src/services/backendClient'; import { GroupManagementClient } from '../src/services/groupManagementClient.ts'; @@ -171,42 +172,46 @@ export async function authorize( }; } +type PageConstructor = new (page: Page) => T; + +async function setupPageWithConsoleListener( + page: Page, + pageClass: PageConstructor, + use: (pageInstance: T) => Promise, +) { + const pageInstance = new pageClass(page); + const cleanup = throwOnConsole(page); // Setup console listener and get cleanup function + await use(pageInstance); + cleanup(); +} + export const test = base.extend({ searchPage: async ({ page }, use) => { - const searchPage = new SearchPage(page); - await use(searchPage); + await setupPageWithConsoleListener(page, SearchPage, use); }, sequencePage: async ({ page }, use) => { - const sequencePage = new SequencePage(page); - await use(sequencePage); + await setupPageWithConsoleListener(page, SequencePage, use); }, submitPage: async ({ page }, use) => { - const submitPage = new SubmitPage(page); - await use(submitPage); + await setupPageWithConsoleListener(page, SubmitPage, use); }, reviewPage: async ({ page }, use) => { - const reviewPage = new ReviewPage(page); - await use(reviewPage); + await setupPageWithConsoleListener(page, ReviewPage, use); }, userPage: async ({ page }, use) => { - const userPage = new UserPage(page); - await use(userPage); + await setupPageWithConsoleListener(page, UserPage, use); }, groupPage: async ({ page }, use) => { - const groupPage = new GroupPage(page); - await use(groupPage); + await setupPageWithConsoleListener(page, GroupPage, use); }, seqSetPage: async ({ page }, use) => { - const seqSetPage = new SeqSetPage(page); - await use(seqSetPage); + await setupPageWithConsoleListener(page, SeqSetPage, use); }, revisePage: async ({ page }, use) => { - const revisePage = new RevisePage(page); - await use(revisePage); + await setupPageWithConsoleListener(page, RevisePage, use); }, editPage: async ({ page }, use) => { - const editPage = new EditPage(page); - await use(editPage); + await setupPageWithConsoleListener(page, EditPage, use); }, navigationFixture: async ({ page }, use) => { await use(new NavigationFixture(page)); diff --git a/website/tests/pages/sequences/sequences.page.ts b/website/tests/pages/sequences/sequences.page.ts index f02d0a16d1..6465efe8c6 100644 --- a/website/tests/pages/sequences/sequences.page.ts +++ b/website/tests/pages/sequences/sequences.page.ts @@ -4,6 +4,7 @@ import { routes } from '../../../src/routes/routes.ts'; import type { AccessionVersion } from '../../../src/types/backend.ts'; import { getAccessionVersionString } from '../../../src/utils/extractAccessionVersion.ts'; import { baseUrl } from '../../e2e.fixture'; +import { throwOnConsole } from '../../util/throwOnConsole.ts'; export class SequencePage { public readonly notLatestVersionBanner: Locator; @@ -19,6 +20,7 @@ export class SequencePage { this.allVersions = this.page.getByRole('link', { name: `All versions`, }); + throwOnConsole(page); this.notLatestVersionBanner = this.page.getByText('This is not the latest version of this sequence entry.'); this.revocationVersionBanner = this.page.getByText('This is a revocation version.'); } diff --git a/website/tests/util/throwOnConsole.ts b/website/tests/util/throwOnConsole.ts new file mode 100644 index 0000000000..cd13f9bdd8 --- /dev/null +++ b/website/tests/util/throwOnConsole.ts @@ -0,0 +1,29 @@ +import { type ConsoleMessage, type Page } from '@playwright/test'; + +const messagesToIgnore = [ + /Ignoring Event: localhost/, + /\[vite\] connecting\.\.\./, + /\[vite\] connected\./, + /\[vite\] ready\./, + /Download the React DevTools for a better development experience: https:\/\/reactjs\.org\/link\/react-devtools/, + /\[astro-island\] Error hydrating .* TypeError: Importing a module script failed\./, // Fires in `astro dev` mode only + /downloadable font: kern: Too large subtable/, + /downloadable font: Table discarded/, + /Target page, context or browser has been closed/, +]; + +export function throwOnConsole(page: Page) { + const listener = (message: ConsoleMessage) => { + if (messagesToIgnore.some((regex) => regex.test(message.text()))) { + return; + } + if (message.type() !== 'error') { + return; + } + throw new Error(`[${message.type()}]: '${message.text()}'`); + }; + + page.on('console', listener); + + return () => page.removeListener('console', listener); +}