UNPKG

@nx/cypress

Version:

The Nx Plugin for Cypress contains executors and generators allowing your workspace to use the powerful Cypress integration testing capabilities.

188 lines (187 loc) • 7.42 kB
"use strict"; 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(); }); }