test(sw): shared Playwright runtime resolver
This commit is contained in:
1 parent
94c0a13c74
commit
df650c02dd
23 files changed
+120
-55
No files matched your search
@@ -0,0 +1,76 @@
|
||||
// Playwright (and the image helpers pngjs / pixelmatch) for the SW browser tests. Playwright is not a repository
|
||||
// dependency, so the first location that has it is used:
|
||||
// 1. SW_PLAYWRIGHT_PATH the playwright package directory (or its entry file)
|
||||
// 2. SW_RUNTIME_MODULES a node_modules directory that contains playwright
|
||||
// 3. HM_PLAYWRIGHT_DIR a project directory whose node_modules contains playwright (scripts/verify-quality-runtime.mjs)
|
||||
// 4. this repository node_modules/playwright (npm i -D playwright, not committed)
|
||||
// 5. the Codex runtime <home>/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules
|
||||
// 6. global npm `npm root -g`
|
||||
// A location set by an environment variable must exist: a wrong value fails instead of falling back silently.
|
||||
import { createRequire } from 'node:module'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { existsSync } from 'node:fs'
|
||||
import os from 'node:os'
|
||||
import path from 'node:path'
|
||||
|
||||
const nodeModulesOf = file => {
|
||||
const parts = path.resolve(file).split(path.sep)
|
||||
const index = parts.lastIndexOf('node_modules')
|
||||
return index < 0 ? null : parts.slice(0, index + 1).join(path.sep)
|
||||
}
|
||||
const fromNodeModules = dir => createRequire(path.join(dir, 'index.js'))
|
||||
const globalRoot = () => {
|
||||
try { return execFileSync('npm', ['root', '-g'], { encoding: 'utf8', shell: process.platform === 'win32', stdio: ['ignore', 'pipe', 'ignore'] }).trim() } catch { return null }
|
||||
}
|
||||
|
||||
function candidates() {
|
||||
const list = []
|
||||
const { SW_PLAYWRIGHT_PATH: entry, SW_RUNTIME_MODULES: modules, HM_PLAYWRIGHT_DIR: project } = process.env
|
||||
if (entry) {
|
||||
const modulesDir = nodeModulesOf(entry)
|
||||
list.push({ source: `SW_PLAYWRIGHT_PATH=${entry}`, explicit: true, entry: path.resolve(entry), require: modulesDir ? fromNodeModules(modulesDir) : createRequire(import.meta.url) })
|
||||
}
|
||||
if (modules) list.push({ source: `SW_RUNTIME_MODULES=${modules}`, explicit: true, require: fromNodeModules(path.resolve(modules)) })
|
||||
if (project) list.push({ source: `HM_PLAYWRIGHT_DIR=${project}`, explicit: true, require: createRequire(path.join(path.resolve(project), 'package.json')) })
|
||||
list.push({ source: 'repository node_modules', require: createRequire(import.meta.url) })
|
||||
const codex = path.join(os.homedir(), '.cache', 'codex-runtimes', 'codex-primary-runtime', 'dependencies', 'node', 'node_modules')
|
||||
if (existsSync(codex)) list.push({ source: `Codex runtime ${codex}`, require: fromNodeModules(codex) })
|
||||
const global = globalRoot()
|
||||
if (global && existsSync(global)) list.push({ source: `global npm ${global}`, require: fromNodeModules(global) })
|
||||
return list
|
||||
}
|
||||
|
||||
let resolved
|
||||
function resolve() {
|
||||
if (resolved) return resolved
|
||||
const tried = []
|
||||
for (const candidate of candidates()) {
|
||||
try {
|
||||
const entry = candidate.entry ?? candidate.require.resolve('playwright')
|
||||
if (candidate.entry && !existsSync(candidate.entry)) throw new Error('path does not exist')
|
||||
resolved = { ...candidate, entry }
|
||||
return resolved
|
||||
} catch (error) {
|
||||
tried.push(`${candidate.source}: ${error.message.split('\n')[0]}`)
|
||||
if (candidate.explicit) break
|
||||
}
|
||||
}
|
||||
throw new Error(`Playwright not found for the SW browser tests. Set SW_RUNTIME_MODULES to a node_modules directory that contains playwright (or SW_PLAYWRIGHT_PATH to the playwright package).\n tried:\n - ${tried.join('\n - ')}`)
|
||||
}
|
||||
|
||||
/** The playwright module (`{ chromium, firefox, ... }`). */
|
||||
export const loadPlaywright = () => resolve().require(resolve().entry)
|
||||
|
||||
/**
|
||||
* A `require` rooted where Playwright was found, for the other runtime modules the tests use (pngjs, pixelmatch).
|
||||
* `require('playwright')` through it returns the same module as `loadPlaywright()`.
|
||||
*/
|
||||
export function runtimeRequire() {
|
||||
const { require, entry } = resolve()
|
||||
const wrapped = id => (id === 'playwright' ? require(entry) : require(id))
|
||||
wrapped.resolve = (id, options) => (id === 'playwright' ? entry : require.resolve(id, options))
|
||||
return wrapped
|
||||
}
|
||||
|
||||
/** Where Playwright came from (for reports). */
|
||||
export const playwrightSource = () => resolve().source
|
||||
Reference in new issue
Block a user