11// Control UI tests cover form controls behavior.
22import { chromium , type Browser , type Page } from "playwright" ;
3- import { afterAll , beforeAll , describe , expect , it } from "vitest" ;
3+ import { describe , expect , it } from "vitest" ;
44import { readStyleSheet } from "../../../test/helpers/ui-style-fixtures.js" ;
55import {
66 canRunPlaywrightChromium ,
@@ -12,7 +12,10 @@ const describeBrowserLayout = canRunPlaywrightChromium(chromiumExecutablePath)
1212 ? describe
1313 : describe . skip ;
1414
15- let browser : Browser ;
15+ type MobileFixture = {
16+ browser : Browser ;
17+ page : Page ;
18+ } ;
1619
1720function readUiCss ( ) : string {
1821 const files = [
@@ -53,29 +56,35 @@ function controlsHtml() {
5356 ` ;
5457}
5558
56- async function openMobileFixture ( ) : Promise < Page > {
57- const page = await browser . newPage ( {
58- hasTouch : true ,
59- isMobile : true ,
60- viewport : { width : 390 , height : 844 } ,
61- } ) ;
62- await page . setContent (
63- `<!doctype html><html data-theme-mode="light"><head><style>${ readUiCss ( ) } </style></head><body>${ controlsHtml ( ) } </body></html>` ,
64- ) ;
65- return page ;
59+ async function openMobileFixture ( ) : Promise < MobileFixture > {
60+ const browser = await chromium . launch ( { executablePath : chromiumExecutablePath , headless : true } ) ;
61+ let page : Page | undefined ;
62+ try {
63+ page = await browser . newPage ( {
64+ hasTouch : true ,
65+ isMobile : true ,
66+ viewport : { width : 390 , height : 844 } ,
67+ } ) ;
68+ await page . setContent (
69+ `<!doctype html><html data-theme-mode="light"><head><style>${ readUiCss ( ) } </style></head><body>${ controlsHtml ( ) } </body></html>` ,
70+ ) ;
71+ return { browser, page } ;
72+ } catch ( error ) {
73+ await page ?. close ( ) . catch ( ( ) => { } ) ;
74+ await browser . close ( ) . catch ( ( ) => { } ) ;
75+ throw error ;
76+ }
6677}
6778
68- describeBrowserLayout ( "touch-primary form controls" , ( ) => {
69- beforeAll ( async ( ) => {
70- browser = await chromium . launch ( { executablePath : chromiumExecutablePath , headless : true } ) ;
71- } ) ;
72-
73- afterAll ( async ( ) => {
74- await browser . close ( ) ;
75- } ) ;
79+ async function closeMobileFixture ( fixture : MobileFixture ) : Promise < void > {
80+ await fixture . page . close ( ) . catch ( ( ) => { } ) ;
81+ await fixture . browser . close ( ) . catch ( ( ) => { } ) ;
82+ }
7683
84+ describeBrowserLayout ( "touch-primary form controls" , ( ) => {
7785 it ( "keeps text-entry controls large enough to avoid mobile focus zoom" , async ( ) => {
78- const page = await openMobileFixture ( ) ;
86+ const fixture = await openMobileFixture ( ) ;
87+ const { page } = fixture ;
7988 try {
8089 const metrics = await page . evaluate ( ( ) => {
8190 const selectors = [
@@ -119,12 +128,13 @@ describeBrowserLayout("touch-primary form controls", () => {
119128 expect ( size . fontSize , size . selector ) . toBeGreaterThanOrEqual ( 16 ) ;
120129 }
121130 } finally {
122- await page . close ( ) ;
131+ await closeMobileFixture ( fixture ) ;
123132 }
124133 } ) ;
125134
126135 it ( "keeps native select affordances visible in light mode" , async ( ) => {
127- const page = await openMobileFixture ( ) ;
136+ const fixture = await openMobileFixture ( ) ;
137+ const { page } = fixture ;
128138 try {
129139 const selects = await page . locator ( ".cfg-select, .field select" ) . evaluateAll ( ( nodes ) =>
130140 nodes . map ( ( node ) => {
@@ -144,7 +154,7 @@ describeBrowserLayout("touch-primary form controls", () => {
144154 expect ( select . repeat ) . toContain ( "no-repeat" ) ;
145155 }
146156 } finally {
147- await page . close ( ) ;
157+ await closeMobileFixture ( fixture ) ;
148158 }
149159 } ) ;
150160} ) ;
0 commit comments