diff --git a/ui/src/ui/form-controls.browser.test.ts b/ui/src/ui/form-controls.browser.test.ts index c9544986d833..6d8383358645 100644 --- a/ui/src/ui/form-controls.browser.test.ts +++ b/ui/src/ui/form-controls.browser.test.ts @@ -1,6 +1,6 @@ // Control UI tests cover form controls behavior. import { chromium, type Browser, type Page } from "playwright"; -import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { describe, expect, it } from "vitest"; import { readStyleSheet } from "../../../test/helpers/ui-style-fixtures.js"; import { canRunPlaywrightChromium, @@ -12,7 +12,10 @@ const describeBrowserLayout = canRunPlaywrightChromium(chromiumExecutablePath) ? describe : describe.skip; -let browser: Browser; +type MobileFixture = { + browser: Browser; + page: Page; +}; function readUiCss(): string { const files = [ @@ -53,29 +56,35 @@ function controlsHtml() { `; } -async function openMobileFixture(): Promise { - const page = await browser.newPage({ - hasTouch: true, - isMobile: true, - viewport: { width: 390, height: 844 }, - }); - await page.setContent( - `${controlsHtml()}`, - ); - return page; +async function openMobileFixture(): Promise { + const browser = await chromium.launch({ executablePath: chromiumExecutablePath, headless: true }); + let page: Page | undefined; + try { + page = await browser.newPage({ + hasTouch: true, + isMobile: true, + viewport: { width: 390, height: 844 }, + }); + await page.setContent( + `${controlsHtml()}`, + ); + return { browser, page }; + } catch (error) { + await page?.close().catch(() => {}); + await browser.close().catch(() => {}); + throw error; + } +} + +async function closeMobileFixture(fixture: MobileFixture): Promise { + await fixture.page.close().catch(() => {}); + await fixture.browser.close().catch(() => {}); } describeBrowserLayout("touch-primary form controls", () => { - beforeAll(async () => { - browser = await chromium.launch({ executablePath: chromiumExecutablePath, headless: true }); - }); - - afterAll(async () => { - await browser.close(); - }); - it("keeps text-entry controls large enough to avoid mobile focus zoom", async () => { - const page = await openMobileFixture(); + const fixture = await openMobileFixture(); + const { page } = fixture; try { const metrics = await page.evaluate(() => { const selectors = [ @@ -119,12 +128,13 @@ describeBrowserLayout("touch-primary form controls", () => { expect(size.fontSize, size.selector).toBeGreaterThanOrEqual(16); } } finally { - await page.close(); + await closeMobileFixture(fixture); } }); it("keeps native select affordances visible in light mode", async () => { - const page = await openMobileFixture(); + const fixture = await openMobileFixture(); + const { page } = fixture; try { const selects = await page.locator(".cfg-select, .field select").evaluateAll((nodes) => nodes.map((node) => { @@ -144,7 +154,7 @@ describeBrowserLayout("touch-primary form controls", () => { expect(select.repeat).toContain("no-repeat"); } } finally { - await page.close(); + await closeMobileFixture(fixture); } }); });