@nx/cypress
Version:
188 lines (187 loc) • 7.42 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.nxBaseCypressPreset = nxBaseCypressPreset;
exports.nxE2EPreset = nxE2EPreset;
const devkit_1 = require("@nx/devkit");
const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const http_1 = require("http");
const https_1 = require("https");
const path_1 = require("path");
const preprocessor_vite_1 = require("../src/plugins/preprocessor-vite");
const constants_1 = require("../src/utils/constants");
const treeKill = require('tree-kill');
function nxBaseCypressPreset(pathToConfig, options) {
// used to set babel settings for react CT.
process.env.NX_CYPRESS_COMPONENT_TEST =
options?.testingType === 'component' ? 'true' : 'false';
// prevent from placing path outside the root of the workspace
// if they pass in a file or directory
const normalizedPath = (0, fs_1.lstatSync)(pathToConfig).isDirectory()
? pathToConfig
: (0, path_1.dirname)(pathToConfig);
const projectPath = (0, path_1.relative)(devkit_1.workspaceRoot, normalizedPath);
const offset = (0, path_1.relative)(normalizedPath, devkit_1.workspaceRoot);
const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)();
const videosFolder = isTsSolutionSetup
? (0, path_1.join)('test-output', 'cypress', 'videos')
: (0, path_1.join)(offset, 'dist', 'cypress', projectPath, 'videos');
const screenshotsFolder = isTsSolutionSetup
? (0, path_1.join)('test-output', 'cypress', 'screenshots')
: (0, path_1.join)(offset, 'dist', 'cypress', projectPath, 'screenshots');
return {
videosFolder,
screenshotsFolder,
chromeWebSecurity: false,
};
}
function startWebServer(webServerCommand) {
const serverProcess = (0, child_process_1.spawn)(webServerCommand, {
cwd: devkit_1.workspaceRoot,
shell: true,
// Detaching the process on unix will create a process group, allowing us to kill it later
// Windows is fine so we leave it attached to this process
detached: process.platform !== 'win32',
stdio: 'inherit',
windowsHide: false,
});
return async () => {
if (process.platform === 'win32') {
try {
(0, child_process_1.execSync)('taskkill /pid ' + serverProcess.pid + ' /T /F', {
windowsHide: false,
});
}
catch (e) {
if (process.env.NX_VERBOSE_LOGGING === 'true') {
console.error(e);
}
}
}
else {
return new Promise((res, rej) => {
if (process.platform === 'win32' || process.platform === 'darwin') {
if (serverProcess.kill()) {
res();
}
else {
rej('Unable to kill process');
}
}
else {
treeKill(serverProcess.pid, (err) => {
if (err) {
rej(err);
}
res();
});
}
});
}
};
}
/**
* nx E2E Preset for Cypress
* @description
* this preset contains the base configuration
* for your e2e tests that nx recommends.
* you can easily extend this within your cypress config via spreading the preset
* @example
* export default defineConfig({
* e2e: {
* ...nxE2EPreset(__dirname)
* // add your own config here
* }
* })
*
*/
function nxE2EPreset(pathToConfig, options) {
const basePath = options?.cypressDir || 'src';
const baseConfig /*Cypress.EndToEndConfigOptions & {
[NX_PLUGIN_OPTIONS]: unknown;
}*/ = {
...nxBaseCypressPreset(pathToConfig),
fileServerFolder: '.',
supportFile: `${basePath}/support/e2e.{js,ts}`,
specPattern: `${basePath}/**/*.cy.{js,jsx,ts,tsx}`,
fixturesFolder: `${basePath}/fixtures`,
[constants_1.NX_PLUGIN_OPTIONS]: {
webServerCommand: options?.webServerCommands?.default,
webServerCommands: options?.webServerCommands,
ciWebServerCommand: options?.ciWebServerCommand,
ciBaseUrl: options?.ciBaseUrl,
reuseExistingServer: options?.webServerConfig?.reuseExistingServer,
},
async setupNodeEvents(on, config) {
const webServerCommands = config.env?.webServerCommands ?? options?.webServerCommands;
const webServerCommand = config.env?.webServerCommand ?? webServerCommands?.default;
if (options?.bundler === 'vite') {
on('file:preprocessor', (0, preprocessor_vite_1.default)(options?.viteConfigOverrides));
}
if (!options?.webServerCommands) {
return;
}
if (!webServerCommand) {
return;
}
if (config.baseUrl && webServerCommand) {
if (await isServerUp(config.baseUrl)) {
if (options?.webServerConfig?.reuseExistingServer === undefined
? true
: options.webServerConfig.reuseExistingServer) {
console.log(`Reusing the server already running on ${config.baseUrl}`);
return;
}
else {
throw new Error(`Web server is already running at ${config.baseUrl}`);
}
}
const killWebServer = startWebServer(webServerCommand);
on('after:run', () => {
return killWebServer();
});
await waitForServer(config.baseUrl, options.webServerConfig);
}
},
};
return baseConfig;
}
function waitForServer(url, webServerConfig) {
return new Promise((resolve, reject) => {
let pollTimeout;
const { protocol } = new URL(url);
const timeoutDuration = webServerConfig?.timeout ?? 60 * 1000;
const timeout = setTimeout(() => {
clearTimeout(pollTimeout);
reject(new Error(`Web server failed to start in ${timeoutDuration}ms. This can be configured in cypress.config.ts.`));
}, timeoutDuration);
const makeRequest = protocol === 'https:' ? https_1.request : http_1.request;
function pollForServer() {
const request = makeRequest(url, () => {
clearTimeout(timeout);
resolve();
});
request.on('error', () => {
pollTimeout = setTimeout(pollForServer, 100);
});
// Don't forget to end the request
request.end();
}
pollForServer();
});
}
function isServerUp(url) {
const { protocol } = new URL(url);
const makeRequest = protocol === 'https:' ? https_1.request : http_1.request;
return new Promise((resolve) => {
const request = makeRequest(url, () => {
resolve(true);
});
request.on('error', () => {
resolve(false);
});
// Don't forget to end the request
request.end();
});
}
;