@storybook/test-runner
Version:
Test runner for Storybook stories
390 lines (382 loc) • 12.8 kB
JavaScript
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
};