vitest-e2e
Version:
vitest e2e utils
242 lines (239 loc) • 6.94 kB
JavaScript
import { workspaceRoot, isBuild } from './chunk-JXTCPVDR.js';
import fs from 'fs-extra';
import os from 'node:os';
import { join, dirname, resolve } from 'node:path';
import { chromium } from 'playwright-chromium';
import { mergeConfig, createServer, build, preview, loadConfigFromFile } from 'vite';
import { beforeAll, afterEach } from 'vitest';
var server;
var viteServer;
var rootDir;
var testPath;
var testDir;
var testName;
var viteConfig;
var serverLogs = [];
var browserLogs = [];
var browserErrors = [];
var resolvedConfig = void 0;
var page = void 0;
var browser = void 0;
var viteTestUrl = "";
var watcher = void 0;
function setViteUrl(url) {
viteTestUrl = url;
}
var DIR = join(os.tmpdir(), "vitest_playwright_global_setup");
beforeAll(async (s) => {
const suite = s;
if (!suite.filepath.includes("playground")) {
return;
}
const wsEndpoint = fs.readFileSync(join(DIR, "wsEndpoint"), "utf-8");
if (!wsEndpoint) {
throw new Error("wsEndpoint not found");
}
browser = await chromium.connect(wsEndpoint);
page = await browser.newPage();
const globalConsole = global.console;
const warn = globalConsole.warn;
globalConsole.warn = (msg, ...args) => {
if (msg.includes("Generated an empty chunk"))
return;
warn.call(globalConsole, msg, ...args);
};
try {
page.on("console", (msg) => {
if (process.env.VITE_DEBUG_SERVE && msg.text().includes("Failed to load resource:") && msg.location().url.includes("favicon.ico")) {
return;
}
if (msg.text().includes("React DevTools"))
return;
browserLogs.push(msg.text());
});
page.on("pageerror", (error) => {
browserErrors.push(error);
});
testPath = suite.filepath;
testName = slash(testPath).match(/playground\/([\w-]+)\//)?.[1];
testDir = dirname(testPath);
if (testName) {
testDir = resolve(workspaceRoot, "playground-temp", testName);
const testCustomRoot = resolve(testDir, "root");
rootDir = fs.existsSync(testCustomRoot) ? testCustomRoot : testDir;
const testCustomServe = [resolve(dirname(testPath), "serve.ts"), resolve(dirname(testPath), "serve.js")].find(
(i) => fs.existsSync(i)
);
if (testCustomServe) {
const mod = await import(testCustomServe);
const serve = mod.serve || mod.default?.serve;
const preServe = mod.preServe || mod.default?.preServe;
if (preServe) {
await preServe();
}
if (serve) {
server = await serve();
viteServer = mod.viteServer;
return;
}
} else {
await startDefaultServe();
}
}
} catch (e) {
await page.close();
await server?.close();
throw e;
}
return async () => {
serverLogs = [];
await page?.close();
await server?.close();
await watcher?.close();
if (browser) {
await browser.close();
}
};
});
afterEach(() => {
browserLogs = [];
browserErrors = [];
});
function loadConfigFromDir(dir) {
return loadConfigFromFile(
{
command: isBuild ? "build" : "serve",
mode: isBuild ? "production" : "development"
},
void 0,
dir
);
}
async function startDefaultServe() {
let config = null;
const res = await loadConfigFromDir(dirname(testPath));
if (res) {
config = res.config;
}
if (!config) {
const res2 = await loadConfigFromDir(rootDir);
if (res2) {
config = res2.config;
}
}
const options = {
root: rootDir,
logLevel: "silent",
configFile: false,
server: {
watch: {
// During tests we edit the files too fast and sometimes chokidar
// misses change events, so enforce polling for consistency
usePolling: true,
interval: 100
},
host: true,
fs: {
strict: !isBuild
}
},
build: {
// esbuild do not minify ES lib output since that would remove pure annotations and break tree-shaking
// skip transpilation during tests to make it faster
target: "esnext",
// tests are flaky when `emptyOutDir` is `true`
emptyOutDir: false
},
customLogger: createInMemoryLogger(serverLogs)
};
setupConsoleWarnCollector();
if (!isBuild) {
process.env.VITE_INLINE = "inline-serve";
const testConfig = mergeConfig(options, config || {});
viteConfig = testConfig;
viteServer = server = await (await createServer(testConfig)).listen();
const devBase = server.config.base;
viteTestUrl = `http://localhost:${server.config.server.port}${devBase === "/" ? "" : devBase}`;
await page.goto(viteTestUrl);
} else {
process.env.VITE_INLINE = "inline-build";
const resolvedPlugin = () => ({
name: "vite-plugin-watcher",
configResolved(config2) {
resolvedConfig = config2;
}
});
options.plugins = [resolvedPlugin()];
const testConfig = mergeConfig(options, config || {});
viteConfig = testConfig;
const rollupOutput = await build(testConfig);
const isWatch = !!resolvedConfig.build.watch;
if (isWatch) {
watcher = rollupOutput;
await notifyRebuildComplete(watcher);
}
if (config && config.__test__) {
config.__test__();
}
const _nodeEnv = process.env.NODE_ENV;
const previewServer = await preview(testConfig);
process.env.NODE_ENV = _nodeEnv;
viteTestUrl = previewServer.resolvedUrls.local[0];
await page.goto(viteTestUrl);
}
}
async function notifyRebuildComplete(watcher2) {
let resolveFn;
const callback = (event) => {
if (event.code === "END") {
resolveFn?.();
}
};
watcher2.on("event", callback);
await new Promise((resolve2) => {
resolveFn = resolve2;
});
return watcher2.off("event", callback);
}
function createInMemoryLogger(logs) {
const loggedErrors = /* @__PURE__ */ new WeakSet();
const warnedMessages = /* @__PURE__ */ new Set();
const logger = {
hasWarned: false,
hasErrorLogged: (err) => loggedErrors.has(err),
clearScreen: () => {
},
info(msg) {
logs.push(msg);
},
warn(msg) {
logs.push(msg);
logger.hasWarned = true;
},
warnOnce(msg) {
if (warnedMessages.has(msg))
return;
logs.push(msg);
logger.hasWarned = true;
warnedMessages.add(msg);
},
error(msg, opts) {
logs.push(msg);
if (opts?.error) {
loggedErrors.add(opts.error);
}
}
};
return logger;
}
function setupConsoleWarnCollector(_logs) {
const warn = console.warn;
console.warn = (...args) => {
serverLogs.push(args.join(" "));
return warn.call(console, ...args);
};
}
function slash(p) {
return p.replace(/\\/g, "/");
}
export { browser, browserErrors, browserLogs, notifyRebuildComplete, page, resolvedConfig, rootDir, serverLogs, setViteUrl, slash, startDefaultServe, testDir, testName, testPath, viteConfig, viteServer, viteTestUrl, watcher };