UNPKG

test-real-styles

Version:

utilities to test real styling of dom elements

183 lines (161 loc) 5.11 kB
import playwright, { Browser, BrowserContext, Page } from 'playwright'; import { resolveStyleInput, Styles } from './resolveStyleInput'; import domToPlaywrightModule from 'dom-to-playwright'; import { getStyles, Options } from './getStyles'; import { withTimeout } from './withTimeout'; import { createQueue } from 'ichschwoer'; const domToPlaywright: typeof domToPlaywrightModule = /* @ts-ignore */ domToPlaywrightModule.__esModule ? /* @ts-ignore */ domToPlaywrightModule.default : domToPlaywrightModule; if (!(global as any).setImmediate) { /** @see https://github.com/microsoft/playwright/issues/18243 */ (global as any).setImmediate = setTimeout; } export const PLAYWRIGHT_BROWSERS = [ 'chromium' as const, 'firefox' as const, 'webkit' as const, ]; export type PlaywrightBrowser = (typeof PLAYWRIGHT_BROWSERS)[0]; export interface LaunchedPage { name: PlaywrightBrowser; getPlaywright(): Promise<{ browser: Browser; context: BrowserContext; page: Page; }>; updatePage( element: HTMLElement | Document, options?: { transitions?: boolean; styles?: Styles | Promise<Styles> }, ): Promise<void>; getStyles<T extends (keyof CSSStyleDeclaration)[]>( element: HTMLElement, styles: T, options?: Options, ): Promise<{ [key in T[0]]: string }>; hover(element: HTMLElement): Promise<void>; focus(element: HTMLElement): Promise<void>; } const cache: { [key: string]: Promise<Browser> } = {}; const DISABLE_TRANSITIONS = ` * { -moz-transition: none !important; -webkit-transition: none !important; transition: none !important; }`; export default function launchPage( browserName: PlaywrightBrowser, stylesInput: Styles | Promise<Styles>, ): LaunchedPage { if (!cache[browserName]) { cache[browserName] = withTimeout( playwright[browserName].launch(), `Failed to launch ${browserName} in under %n`, ); } const browserP = cache[browserName]; const contextP = withTimeout( browserP.then((b) => b.newContext()), `Failed to create context in ${browserName} in under %n`, ); const pageP = withTimeout( contextP.then((c) => c.newPage()), `Failed to create page in ${browserName} in under %n`, ); const dtpP = pageP.then(domToPlaywright); const globalStylesP = withTimeout( resolveStyleInput(stylesInput), `Failed to global resolve style input for ${browserName} in under %n`, ); const q = createQueue(1); return { name: browserName, async getPlaywright() { return { browser: await browserP, context: await contextP, page: await pageP, }; }, updatePage(element, { transitions = false, styles: pageStylesP } = {}) { return q.push(async () => { const { update } = await dtpP; const page = await pageP; const styles = await globalStylesP; await withTimeout( update(element), `Failed to update page within ${browserName} in under %n`, ); await withTimeout( page.addStyleTag(styles), `Failed to add global styles to page within ${browserName} in under %n`, ); if (pageStylesP) { const pageStyles = await withTimeout( resolveStyleInput(pageStylesP), `Failed to resolve page style input for ${browserName} in under %n`, ); await withTimeout( page.addStyleTag(pageStyles), `Failed to add page styles to page within ${browserName} in under %n`, ); } if (!transitions) { await withTimeout( page.addStyleTag({ content: DISABLE_TRANSITIONS }), `Failed to disable transitions within ${browserName} in under %n`, ); } }); }, getStyles(element, styles, options) { return q.push(async () => { const { select } = await dtpP; const page = await pageP; return withTimeout( getStyles(page, select(element), styles, options), `Failed to get styles within ${browserName} in under %n`, ); }); }, hover(element) { return q.push(async () => { const { select } = await dtpP; const page = await pageP; await withTimeout( page.hover(select(element)), `Failed to hover element within ${browserName} in under %n`, ); }); }, focus(element) { return q.push(async () => { const { select } = await dtpP; const page = await pageP; await withTimeout( page.focus(select(element)), `Failed to focus element within ${browserName} in under %n`, ); }); }, }; } export async function cleanup() { const toBeCleared = { ...cache }; for (const key in cache) { delete cache[key]; } for (const key in toBeCleared) { const browser = await toBeCleared[key]; for (const context of browser.contexts()) { await context.close(); } await browser.close(); } } if (typeof afterAll === 'function') { afterAll(cleanup); }