[READ-ONLY] Mirror of https://github.com/danielroe/cross-origin-storage. Load shared dependencies from Cross-Origin Storage (COS).
cross-origin-storage
experimental
nuxt
vite
vite-plugin
1import { existsSync } from 'node:fs'
2import { fileURLToPath } from 'node:url'
3import { chromium } from 'playwright-core'
4import type { Browser, BrowserContext } from 'playwright-core'
5
6export const extensionDir = fileURLToPath(new URL('../.cos-extension', import.meta.url))
7
8/**
9 * The COS extension only loads in a full, headed Chrome for Testing build:
10 * headless mode and the `chrome-headless-shell` binary both disable extensions,
11 * and the system Chrome blocks `--load-extension`.
12 */
13function hasFullChromium(): boolean {
14 try {
15 const executable = chromium.executablePath()
16 return existsSync(executable) && !executable.includes('headless-shell')
17 }
18 catch {
19 return false
20 }
21}
22
23/**
24 * Whether the COS test may skip itself. A missing extension-capable browser is
25 * fatal by default so CI cannot pass green without running the real COS path;
26 * only an environment that explicitly cannot run a headed browser (e.g. a
27 * sandbox, via `COS_SKIP_EXTENSION_TEST=1`) is allowed to skip.
28 */
29export function skipExtensionTest(): boolean {
30 return process.env.COS_SKIP_EXTENSION_TEST === '1'
31}
32
33export function assertExtensionRunnable(): void {
34 if (!existsSync(extensionDir)) {
35 throw new Error(
36 `COS extension missing at ${extensionDir}. Global setup should have cloned it; `
37 + `run the suite via vitest so global-setup runs, or clone it manually.`,
38 )
39 }
40 if (!hasFullChromium()) {
41 throw new Error(
42 'COS test requires a full Chrome for Testing build (extensions do not load in '
43 + 'headless mode or chrome-headless-shell). Run `npx playwright-core install chromium`. '
44 + 'Set COS_SKIP_EXTENSION_TEST=1 only in an environment that genuinely cannot run a headed browser.',
45 )
46 }
47}
48
49export async function launchPlainBrowser(): Promise<Browser> {
50 return chromium.launch({ headless: true })
51}
52
53export async function launchWithExtension(userDataDir: string): Promise<BrowserContext> {
54 const context = await chromium.launchPersistentContext(userDataDir, {
55 headless: false,
56 ignoreDefaultArgs: ['--disable-extensions'],
57 args: [
58 `--disable-extensions-except=${extensionDir}`,
59 `--load-extension=${extensionDir}`,
60 '--no-first-run',
61 '--no-default-browser-check',
62 ],
63 })
64 // Give the extension's service worker time to register before navigating.
65 await new Promise(resolve => setTimeout(resolve, 2000))
66 return context
67}