UNPKG

@nx/cypress

Version:

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

189 lines (187 loc) • 7.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = cypressExecutor; const devkit_1 = require("@nx/devkit"); const fs_1 = require("fs"); const path_1 = require("path"); const ct_helpers_1 = require("../../utils/ct-helpers"); const versions_1 = require("../../utils/versions"); const start_dev_server_1 = require("../../utils/start-dev-server"); const Cypress = require('cypress'); // @NOTE: Importing via ES6 messes the whole test dependencies. async function cypressExecutor(options, context) { const installedCypressMajorVersion = (0, versions_1.getInstalledCypressMajorVersion)(); options = normalizeOptions(options, context, installedCypressMajorVersion); // this is used by cypress component testing presets to build the executor contexts with the correct configuration options. process.env.NX_CYPRESS_TARGET_CONFIGURATION = context.configurationName; let success; const generatorInstance = (0, start_dev_server_1.startDevServer)(options, context); for await (const devServerValues of generatorInstance) { try { success = await runCypress(devServerValues.baseUrl, { ...options, portLockFilePath: devServerValues.portLockFilePath, }, installedCypressMajorVersion); if (!options.watch) { generatorInstance.return(); break; } } catch (e) { devkit_1.logger.error(e.message); success = false; if (!options.watch) break; } } return { success }; } function normalizeOptions(options, context, installedCypressMajorVersion) { options.env = options.env || {}; if (options.testingType === 'component') { const project = context?.projectGraph?.nodes?.[context.projectName]; if (project?.data?.root) { options.ctTailwindPath = (0, ct_helpers_1.getTempTailwindPath)(context); } } checkSupportedBrowser(options, installedCypressMajorVersion); warnDeprecatedHeadless(options, installedCypressMajorVersion); warnDeprecatedCypressVersion(installedCypressMajorVersion); return options; } function checkSupportedBrowser({ browser }, installedCypressMajorVersion) { // Browser was not passed in as an option, cypress will use whatever default it has set and we dont need to check it if (!browser) { return; } if (installedCypressMajorVersion >= 4 && browser == 'canary') { devkit_1.logger.warn((0, devkit_1.stripIndents) ` Warning: You are using a browser that is not supported by cypress v4+. Read here for more info: https://docs.cypress.io/guides/references/migration-guide.html#Launching-Chrome-Canary-with-browser `); return; } const supportedV3Browsers = ['electron', 'chrome', 'canary', 'chromium']; if (installedCypressMajorVersion <= 3 && !supportedV3Browsers.includes(browser)) { devkit_1.logger.warn((0, devkit_1.stripIndents) ` Warning: You are using a browser that is not supported by cypress v3. `); return; } } function warnDeprecatedHeadless({ headless }, installedCypressMajorVersion) { if (installedCypressMajorVersion < 8 || headless === undefined) { return; } if (headless) { const deprecatedMsg = (0, devkit_1.stripIndents) ` NOTE: You can now remove the use of the '--headless' flag during 'cypress run' as this is the default for all browsers.`; devkit_1.logger.warn(deprecatedMsg); } } function warnDeprecatedCypressVersion(installedCypressMajorVersion) { if (installedCypressMajorVersion < 10) { devkit_1.logger.warn((0, devkit_1.stripIndents) ` NOTE: Support for Cypress versions < 10 is deprecated. Please upgrade to at least Cypress version 10. A generator to migrate from v8 to v10 is provided. See https://nx.dev/cypress/v10-migration-guide `); } } /** * @whatItDoes Initialize the Cypress test runner with the provided project configuration. * By default, Cypress will run tests from the CLI without the GUI and provide directly the results in the console output. * If `watch` is `true`: Open Cypress in the interactive GUI to interact directly with the application. */ async function runCypress(baseUrl, opts, installedCypressMajorVersion) { // Cypress expects the folder where a cypress config is present const projectFolderPath = (0, path_1.dirname)(opts.cypressConfig); const options = { project: projectFolderPath, configFile: (0, path_1.basename)(opts.cypressConfig), }; // If not, will use the `baseUrl` normally from `cypress.json` if (baseUrl) { options.config = { baseUrl }; } if (opts.browser) { options.browser = opts.browser; } if (opts.env) { options.env = { ...options.env, ...opts.env, }; } if (opts.spec) { options.spec = opts.spec; } options.tag = opts.tag; options.exit = opts.exit; options.headed = opts.headed; options.runnerUi = opts.runnerUi; if (opts.headless) { options.headless = opts.headless; } options.record = opts.record; options.key = opts.key; options.parallel = opts.parallel; options.ciBuildId = opts.ciBuildId?.toString(); options.group = opts.group; // renamed in cy 10 if (installedCypressMajorVersion >= 10) { options.config ??= {}; options.config[opts.testingType] = { excludeSpecPattern: opts.ignoreTestFiles, }; } else { options.ignoreTestFiles = opts.ignoreTestFiles; } if (opts.reporter) { options.reporter = opts.reporter; } if (opts.reporterOptions) { options.reporterOptions = opts.reporterOptions; } if (opts.quiet) { options.quiet = opts.quiet; } if (opts.autoCancelAfterFailures !== undefined) { options.autoCancelAfterFailures = opts.autoCancelAfterFailures; } options.testingType = opts.testingType; const result = await (opts.watch ? Cypress.open(options) : Cypress.run(options)); cleanupTmpFile(opts.ctTailwindPath); cleanupTmpFile(opts.portLockFilePath); if (process.env.NX_VERBOSE_LOGGING === 'true' && opts.portLockFilePath) { (0, fs_1.readdirSync)((0, path_1.dirname)(opts.portLockFilePath)).forEach((f) => { if (f.endsWith('.txt')) { devkit_1.logger.debug(`Lock file ${f} still present`); } }); } /** * `cypress.open` is returning `0` and is not of the same type as `cypress.run`. * `cypress.open` is the graphical UI, so it will be obvious to know what wasn't * working. Forcing the build to success when `cypress.open` is used. */ return !result.totalFailed && !result.failures; } function cleanupTmpFile(path) { try { if (path && (0, fs_1.existsSync)(path)) { (0, fs_1.unlinkSync)(path); } return true; } catch (err) { return false; } }