UNPKG

@storybook/test-runner

Version:
390 lines (382 loc) • 12.8 kB
import ESM_COMPAT_Module from "node:module"; import { fileURLToPath as ESM_COMPAT_fileURLToPath } from 'node:url'; const __filename = ESM_COMPAT_fileURLToPath(import.meta.url); const require = ESM_COMPAT_Module.createRequire(import.meta.url); var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x + '" is not supported'); }); // src/jest-playwright-preset/PlaywrightRunner.ts import JestRunner from "jest-runner"; // src/jest-playwright-preset/utils.ts import fs from "fs"; import path from "path"; // src/jest-playwright-preset/constants.ts var IMPORT_KIND_PLAYWRIGHT = "playwright"; var CONFIG_ENVIRONMENT_NAME = "jest-playwright"; var CHROMIUM = "chromium"; var FIREFOX = "firefox"; var WEBKIT = "webkit"; var LAUNCH = "LAUNCH"; var SERVER = "SERVER"; var DEFAULT_CONFIG = { launchType: SERVER, launchOptions: {}, connectOptions: {}, contextOptions: {}, browsers: [ CHROMIUM ], exitOnPageError: true, collectCoverage: false }; var DEFAULT_TEST_PLAYWRIGHT_TIMEOUT = 15e3; var DEBUG_TIMEOUT = 4 * 24 * 60 * 60 * 1e3; var PACKAGE_NAME = "@storybook/test-runner"; // src/jest-playwright-preset/utils.ts var fsPromises = fs.promises; var BROWSERS = [ CHROMIUM, FIREFOX, WEBKIT ]; var PlaywrightError = class PlaywrightError2 extends Error { static { __name(this, "PlaywrightError"); } constructor(message) { super(formatError(message)); this.name = "PlaywrightError"; } }; var checkBrowserEnv = /* @__PURE__ */ __name((param) => { if (!BROWSERS.includes(param)) { throw new PlaywrightError(`Wrong browser type. Should be one of [${BROWSERS.join(", ")}], but got ${param}`); } }, "checkBrowserEnv"); var isObject = /* @__PURE__ */ __name((item) => { return item && typeof item === "object" && !Array.isArray(item); }, "isObject"); var deepMerge = /* @__PURE__ */ __name((target, source) => { let output = { ...target }; const keys = Object.keys(source); if (isObject(target) && isObject(source)) { keys.forEach((key) => { if (Array.isArray(source[key]) && Array.isArray(target[key])) { output = { ...output, [key]: [ ...source[key], ...target[key] ] }; } else if (isObject(source[key])) { if (!(key in target)) { output = { ...output, [key]: source[key] }; } else { output[key] = deepMerge(target[key], source[key]); } } else { output = { ...output, [key]: source[key] }; } }); } return output; }, "deepMerge"); var checkDeviceEnv = /* @__PURE__ */ __name((device, availableDevices) => { if (!availableDevices.includes(device)) { throw new PlaywrightError(`Wrong device. Should be one of [${availableDevices}], but got ${device}`); } }, "checkDeviceEnv"); var checkDevice = /* @__PURE__ */ __name((device, availableDevices) => { if (typeof device === "string") { const availableDeviceNames = Object.keys(availableDevices); checkDeviceEnv(device, availableDeviceNames); } }, "checkDevice"); var getDisplayName = /* @__PURE__ */ __name((browser, device) => { const result = `browser: ${browser}`; if (device !== null) { if (typeof device === "string") { return `${result} device: ${device}`; } if (device.name) { return `${result} device: ${device.name}`; } } return result; }, "getDisplayName"); var getBrowserType = /* @__PURE__ */ __name((browser) => { return browser || CHROMIUM; }, "getBrowserType"); var generateKey = /* @__PURE__ */ __name((browser, config) => `${browser}${JSON.stringify(config)}`, "generateKey"); var getDeviceBrowserType = /* @__PURE__ */ __name((device, availableDevices) => { if (typeof device === "string") { return availableDevices[device].defaultBrowserType; } return device?.defaultBrowserType || null; }, "getDeviceBrowserType"); var getPlaywrightInstance = /* @__PURE__ */ __name((browserName) => { let pw; let name; if (!browserName) { pw = __require(IMPORT_KIND_PLAYWRIGHT); name = IMPORT_KIND_PLAYWRIGHT; return { name, instance: pw, devices: pw["devices"] }; } try { pw = __require(`${IMPORT_KIND_PLAYWRIGHT}-${browserName}`); name = browserName; } catch (e) { try { pw = __require(IMPORT_KIND_PLAYWRIGHT); name = IMPORT_KIND_PLAYWRIGHT; } catch (e2) { throw new PlaywrightError(`Cannot find playwright package to use ${browserName}`); } } if (!pw[browserName]) { throw new PlaywrightError(`Cannot find playwright package to use ${browserName}`); } return { name, instance: pw[browserName], devices: pw["devices"] }; }, "getPlaywrightInstance"); function getBrowserOptions(browserName, options) { let result = options ? { ...options } : {}; if (result[browserName]) { result = deepMerge(result, result[browserName]); } BROWSERS.forEach((browser) => { delete result[browser]; }); return result; } __name(getBrowserOptions, "getBrowserOptions"); var readConfig = /* @__PURE__ */ __name(async (rootDir = process.cwd(), jestEnvConfig) => { if (jestEnvConfig) { return { ...DEFAULT_CONFIG, ...jestEnvConfig }; } const { JEST_PLAYWRIGHT_CONFIG, npm_package_type } = process.env; const fileExtension = npm_package_type === "module" ? "cjs" : "js"; const configPath = JEST_PLAYWRIGHT_CONFIG || `${CONFIG_ENVIRONMENT_NAME}.config.${fileExtension}`; const absConfigPath = path.resolve(rootDir, configPath); try { await fsPromises.access(absConfigPath); } catch (e) { if (JEST_PLAYWRIGHT_CONFIG) { throw new PlaywrightError(`Can't find a root directory while resolving a config file path. Provided path to resolve: ${configPath}`); } else { return DEFAULT_CONFIG; } } const localConfig = await __require(absConfigPath); if (typeof localConfig === "function") { const config = await localConfig(); return { ...DEFAULT_CONFIG, ...config }; } return { ...DEFAULT_CONFIG, ...localConfig }; }, "readConfig"); var formatError = /* @__PURE__ */ __name((error) => `${PACKAGE_NAME}: ${error}`, "formatError"); // src/jest-playwright-preset/coverage.ts import * as uuid from "uuid"; import path2 from "path"; import fs2 from "fs"; import { promisify } from "util"; import rimraf from "rimraf"; import NYC from "nyc"; var fsAsync = fs2.promises; var NYC_DIR = ".nyc_output"; var COV_MERGE_DIR = path2.join(NYC_DIR, "merge"); var cleanMergeFiles = /* @__PURE__ */ __name(async () => { await promisify(rimraf)(COV_MERGE_DIR); }, "cleanMergeFiles"); var setupCoverage = /* @__PURE__ */ __name(async () => { if (!fs2.existsSync(NYC_DIR)) { await fsAsync.mkdir(NYC_DIR); } await cleanMergeFiles(); await fsAsync.mkdir(COV_MERGE_DIR); }, "setupCoverage"); var mergeCoverage = /* @__PURE__ */ __name(async () => { const nyc = new NYC({ _: [ "merge" ] }); const map = await nyc.getCoverageMapFromAllCoverageFiles(COV_MERGE_DIR); const outputFile = path2.join(NYC_DIR, "coverage.json"); const content = JSON.stringify(map, null, 2); await fsAsync.writeFile(outputFile, content); console.info(`Coverage file (${content.length} bytes) written to ${outputFile}`); await cleanMergeFiles(); }, "mergeCoverage"); // src/jest-playwright-preset/PlaywrightRunner.ts var getBrowserTest = /* @__PURE__ */ __name(({ test, config, browser, wsEndpoint, device, testTimeout }) => { const { displayName, testEnvironmentOptions } = test.context.config; const playwrightDisplayName = getDisplayName(config.displayName || browser, device); return { ...test, context: { ...test.context, config: { ...test.context.config, testEnvironmentOptions: { ...testEnvironmentOptions, [CONFIG_ENVIRONMENT_NAME]: { ...config, testTimeout } }, browserName: browser, wsEndpoint, device, displayName: { name: displayName ? `${playwrightDisplayName} ${displayName.name || displayName}` : playwrightDisplayName, color: displayName?.color || "yellow" } } } }; }, "getBrowserTest"); var getDevices = /* @__PURE__ */ __name((devices, availableDevices) => { let resultDevices = []; if (devices) { if (devices instanceof RegExp) { resultDevices = Object.keys(availableDevices).filter((item) => item.match(devices)); } else { resultDevices = devices; } } return resultDevices; }, "getDevices"); var getJestTimeout = /* @__PURE__ */ __name((configTimeout) => { if (configTimeout) { return configTimeout; } return process.env.PWDEBUG ? DEBUG_TIMEOUT : DEFAULT_TEST_PLAYWRIGHT_TIMEOUT; }, "getJestTimeout"); var PlaywrightRunner = class PlaywrightRunner2 extends JestRunner { static { __name(this, "PlaywrightRunner"); } browser2Server; config; constructor(globalConfig, context) { const config = { ...globalConfig }; config.testTimeout = getJestTimeout(config.testTimeout); super(config, context); this.browser2Server = {}; this.config = config; } async launchServer(config, wsEndpoint, browser, key, instance) { const { launchType, launchOptions, skipInitialization } = config; if (!skipInitialization && launchType === SERVER && wsEndpoint === null) { if (!this.browser2Server[key]) { const options = getBrowserOptions(browser, launchOptions); this.browser2Server[key] = await instance.launchServer(options); } } return wsEndpoint || this.browser2Server[key]?.wsEndpoint() || null; } async getTests(tests, config) { const { browsers, devices, connectOptions, useDefaultBrowserType } = config; const pwTests = []; for (const test of tests) { for (const browser of browsers) { const browserType = getBrowserType(typeof browser === "string" ? browser : browser.name); const browserConfig = typeof browser === "string" ? config : deepMerge(config, browser || {}); checkBrowserEnv(browserType); const { devices: availableDevices, instance } = getPlaywrightInstance(browserType); const resultDevices = getDevices(devices, availableDevices); const key = typeof browser === "string" ? browser : generateKey(browser.name, browserConfig); const browserOptions = getBrowserOptions(browserType, connectOptions); const wsEndpoint = await this.launchServer(browserConfig, "wsEndpoint" in browserOptions ? browserOptions.wsEndpoint : null, browserType, key, instance); const browserTest = { test, config: browserConfig, wsEndpoint, browser: browserType, testTimeout: this.config.testTimeout }; if (resultDevices.length) { resultDevices.forEach((device) => { checkDevice(device, availableDevices); if (useDefaultBrowserType) { const deviceBrowser = getDeviceBrowserType(device, availableDevices); if (deviceBrowser !== null && deviceBrowser !== browser) return; } pwTests.push(getBrowserTest({ ...browserTest, device })); }); } else { pwTests.push(getBrowserTest({ ...browserTest, device: null })); } } } return pwTests; } async runTests(tests, watcher, options) { const { rootDir, testEnvironmentOptions } = tests[0].context.config; const config = await readConfig(rootDir, testEnvironmentOptions[CONFIG_ENVIRONMENT_NAME]); if (this.config.testNamePattern) { config.launchType = LAUNCH; config.skipInitialization = true; config.haveSkippedTests = true; } const browserTests = await this.getTests(tests, config); if (config.collectCoverage) { await setupCoverage(); } await super.runTests(browserTests, watcher, options); for (const key in this.browser2Server) { await this.browser2Server[key].close(); } if (config.collectCoverage) { await mergeCoverage(); } } }; var PlaywrightRunner_default = PlaywrightRunner; // src/jest-playwright-entries/runner.ts var runner_default = PlaywrightRunner_default; export { runner_default as default };