UNPKG

@nxextensions/firebase-cypress

Version:

An NX Plugin for Firebase Applications that would like to use emulators for E2E testing with Cypress

230 lines 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.initGenerator = initGenerator; const tslib_1 = require("tslib"); const devkit_1 = require("@nx/devkit"); const add_plugin_1 = require("@nx/devkit/src/utils/add-plugin"); const process = tslib_1.__importStar(require("node:process")); const js_1 = require("@nx/js"); const target_generator_1 = require("../../target-generator"); const path_1 = require("path"); const cypress_version_1 = require("../../utils/cypress-version"); const config_1 = require("../../utils/config"); const child_process_1 = require("child_process"); const firebaseJsonGlob = '**/firebase.json'; function normalizeOptions(options, project, tree) { var _a, _b, _c, _d, _e; options !== null && options !== void 0 ? options : (options = {}); (_a = options.directory) !== null && _a !== void 0 ? _a : (options.directory = 'src'); (_b = options.js) !== null && _b !== void 0 ? _b : (options.js = false); (_c = options.jsx) !== null && _c !== void 0 ? _c : (options.jsx = false); const offsetFromProjectRoot = options.directory.split('/') // eslint-disable-next-line @typescript-eslint/no-unused-vars .map(_ => '..') .join('/'); options.hasTsConfig = tree.exists((0, devkit_1.joinPathFragments)(project.root, 'tsconfig.json')); (_d = options.bundler) !== null && _d !== void 0 ? _d : (options.bundler = 'webpack'); (_e = options.baseUrl) !== null && _e !== void 0 ? _e : (options.baseUrl = 'http://localhost:4200'); return { ...options, offsetFromProjectRoot: `${offsetFromProjectRoot}/`, projectConfig: project }; } async function initGenerator(tree, options) { var _a, _b; // set plugin options const nxJson = (0, devkit_1.readNxJson)(tree); (_a = options.skipNxFirebase) !== null && _a !== void 0 ? _a : (options.skipNxFirebase = true); const addPlugins = options.addPlugin = process.env.NX_ADD_PLUGINS !== 'false' && nxJson.useInferencePlugins !== false; const graph = await (0, devkit_1.createProjectGraphAsync)({ exitOnError: true }); let cp = undefined; // eslint-disable-next-line @typescript-eslint/no-explicit-any if (!((_b = nxJson.plugins) === null || _b === void 0 ? void 0 : _b.find((x) => x.plugin === '@nxextensions/nx-firebase')) && !options.skipNxFirebase) { cp = (0, child_process_1.spawn)('npx nx add @nxextensions/nx-firebase --verbose', { detached: false, shell: true }); cp.stdout.on('data', (data) => { process.stdout.write(data); }); cp.stderr.on('data', (data) => { process.stderr.write(data); }); cp.on('error', (err) => { process.stderr.write(err.toString()); }); } if (addPlugins) { await addPlugin(tree, graph, true); } // detect projects const applicationProjectNames = []; Object.keys(graph.nodes).forEach((p) => { if (graph.nodes[p].type === 'app') { applicationProjectNames.push(graph.nodes[p].name); } }); process.stdout.write(`Found the following projects: ${applicationProjectNames.join(', ')}\r\n`); const projects = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(graph); const applicationProjects = Object.keys(projects.projects).map((key) => applicationProjectNames.includes(key) && projects.projects[key]).filter(x => typeof x === 'object'); // Loop for (const project of applicationProjects) { // determine if valid e2e project exists const e2eProject = Object.keys(projects.projects).map(key => projects.projects[key]).filter(x => { var _a; return (_a = x.implicitDependencies) === null || _a === void 0 ? void 0 : _a.includes(project.name); }); const firebaseJson = await (0, devkit_1.globAsync)(tree, [(0, devkit_1.joinPathFragments)(project.root, firebaseJsonGlob)]); if (!e2eProject || e2eProject.length === 0) { if ((!e2eProject || e2eProject.length === 0) && firebaseJson.length > 0) { process.stdout.write(`The following project was found to not be covered by an e2e project and contain a firebase configuration: ${project.name}\r\nGenerating files for new E2E project ${project.name}-e2e\r\n`); options.js = false; } // generate new files await createE2EProject(project, tree, options); } else if (firebaseJson.length > 0) { // update existing files options = normalizeOptions(options, e2eProject[0], tree); await injectConfiguration(tree, project, e2eProject[0], options); } } if (cp !== undefined) { await waitForChildProcess(cp); } // end loop await (0, devkit_1.formatFiles)(tree); return () => { (0, devkit_1.installPackagesTask)(tree); }; } function waitForChildProcess(cp) { return new Promise((res) => { cp.on('exit', (code) => { if (code === 1) { throw new Error('Initialization of @nxextensions/nx-firebase failed'); } res(); }); if (cp.exitCode !== undefined && cp.exitCode !== null) { res(); } }); } async function createE2EProject(baseProject, tree, options) { const appsDir = (0, devkit_1.getWorkspaceLayout)(tree).appsDir; const newProjectName = `${baseProject.name}-e2e`; const newProjectDir = (0, devkit_1.joinPathFragments)(appsDir, newProjectName); const newProject = { name: newProjectName, projectType: 'application', root: newProjectDir, sourceRoot: (0, devkit_1.joinPathFragments)(newProjectDir, 'src'), implicitDependencies: [baseProject.name] }; options = normalizeOptions(options, newProject, tree); (0, devkit_1.addProjectConfiguration)(tree, newProjectName, newProject); await createCypressConfig(tree, newProject, options); await (0, devkit_1.formatFiles)(tree); await injectConfiguration(tree, baseProject, newProject, options); } async function createCypressConfig(tree, projectConfig, options) { if (tree.exists((0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress.config.ts')) || tree.exists((0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress.config.js'))) { return; } const templateVars = { ...options, jsx: !!options.jsx, offsetFromRoot: (0, devkit_1.offsetFromRoot)(projectConfig.root), offsetFromProjectRoot: options.hasTsConfig ? options.offsetFromProjectRoot : '', tsConfigPath: options.hasTsConfig ? `${options.offsetFromProjectRoot}tsconfig.json` : (0, js_1.getRelativePathToRootTsConfig)(tree, projectConfig.root), ext: '' }; (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files/common'), projectConfig.root, templateVars); if (options.js) { if (isEsmProject(tree, projectConfig.root)) { (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files/config-js-esm'), projectConfig.root, templateVars); } else { (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files/config-js-cjs'), projectConfig.root, templateVars); } } else { (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files/config-ts'), projectConfig.root, templateVars); } } async function injectConfiguration(tree, projectConfig, e2eProject, options) { var _a, _b, _c, _d; const projectServeTarget = (_a = projectConfig.targets) === null || _a === void 0 ? void 0 : _a['serve']; if (!projectServeTarget) { console.warn(`The current project: ${projectConfig.name} does not have a serve target. Skipping configuration for this project`); return; } const cyVersion = (0, cypress_version_1.installedCypressVersion)(); const filesToUse = cyVersion && cyVersion < 10 ? 'v9' : 'v10'; const hasTsConfig = tree.exists((0, devkit_1.joinPathFragments)(e2eProject.root, 'tsconfig.json')); const offsetFromProjectRoot = options.directory .split('/') // eslint-disable-next-line @typescript-eslint/no-unused-vars .map(_ => '..') .join('/'); const fileOpts = { ...options, project: projectConfig.name, dir: (_b = options.directory) !== null && _b !== void 0 ? _b : 'src', ext: options.js ? 'js' : 'ts', offsetFromRoot: (0, devkit_1.offsetFromRoot)(e2eProject.root), offsetFromProjectRoot, projectRoot: projectConfig.root, tsConfigPath: hasTsConfig ? `${offsetFromProjectRoot}/tsconfig.json` : (0, js_1.getRelativePathToRootTsConfig)(tree, e2eProject.root), tmpl: '' }; (0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files', filesToUse), e2eProject.root, fileOpts); if (filesToUse === 'v10') { // TODO: consider auto-detecting javascript const cyFile = (0, devkit_1.joinPathFragments)(e2eProject.root, options.js ? 'cypress.config.js' : 'cypress.config.ts'); const webServerCommands = {}; let ciWebServerCommand; const targetString = (0, devkit_1.targetToTargetString)({ project: projectConfig.name, target: 'serve' }); webServerCommands.default = `nx run ${targetString}`; if ((_c = projectServeTarget.configurations) === null || _c === void 0 ? void 0 : _c['production']) { webServerCommands.production = `nx run ${targetString}:production`; } if ((_d = projectConfig.targets) === null || _d === void 0 ? void 0 : _d['serve-static']) { ciWebServerCommand = `nx run ${projectConfig.name}:serve-static`; } const updatedCyConfig = await (0, config_1.addDefaultE2eConfig)(tree.read(cyFile, 'utf-8'), { cypressDir: options.directory, bundler: options.bundler === 'vite' ? 'vite' : undefined, webServerCommands, ciWebServerCommand: ciWebServerCommand }, options.baseUrl); tree.write(cyFile, updatedCyConfig); } } function addPlugin(tree, graph, updatePackageScripts) { return (0, add_plugin_1.addPlugin)(tree, graph, '@nxextensions/firebase-cypress', target_generator_1.createNodesV2, { targetName: ['e2e'], openTargetName: ['open-cypress'], componentTestingTargetName: ['component-test'], ciTargetName: ['e2e-ci'] }, updatePackageScripts); } function isEsmProject(tree, projectRoot) { // eslint-disable-next-line @typescript-eslint/no-explicit-any let packageJson; if (tree.exists((0, devkit_1.joinPathFragments)(projectRoot, 'package.json'))) { packageJson = (0, devkit_1.readJson)(tree, (0, devkit_1.joinPathFragments)(projectRoot, 'package.json')); } else { packageJson = (0, devkit_1.readJson)(tree, 'package.json'); } return packageJson.type === 'module'; } // noinspection JSUnusedGlobalSymbols exports.default = initGenerator; //# sourceMappingURL=generator.js.map