UNPKG

@nx/playwright

Version:

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

176 lines (175 loc) • 9.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = default_1; const devkit_1 = require("@nx/devkit"); const tsquery_1 = require("@phenomnomnominal/tsquery"); const add_e2e_ci_target_defaults_1 = require("./add-e2e-ci-target-defaults"); const loaded_nx_plugin_1 = require("nx/src/project-graph/plugins/loaded-nx-plugin"); const retrieve_workspace_files_1 = require("nx/src/project-graph/utils/retrieve-workspace-files"); const error_types_1 = require("nx/src/project-graph/error-types"); async function default_1(tree) { const graph = await (0, devkit_1.createProjectGraphAsync)(); const collectedProjects = []; (0, devkit_1.visitNotIgnoredFiles)(tree, '', async (path) => { if (!path.endsWith('playwright.config.ts')) { return; } let playwrightConfigFileContents = tree.read(path, 'utf-8'); const WEBSERVER_COMMAND_SELECTOR = 'PropertyAssignment:has(Identifier[name=webServer]) PropertyAssignment:has(Identifier[name=command]) > StringLiteral'; let ast = tsquery_1.tsquery.ast(playwrightConfigFileContents); const nodes = (0, tsquery_1.tsquery)(ast, WEBSERVER_COMMAND_SELECTOR, { visitAllChildren: true, }); if (!nodes.length) { return; } const commandValueNode = nodes[0]; const command = commandValueNode.getText(); let project; let portFlagValue; if (command.includes('nx run')) { const NX_RUN_TARGET_REGEX = /(?<=nx run )([^' ]+)(?: [^']*--port[= ](\d+))?/; const matches = command.match(NX_RUN_TARGET_REGEX); if (!matches) { return; } const targetString = matches[1]; const parsedTargetString = (0, devkit_1.parseTargetString)(targetString, graph); if (parsedTargetString.target === 'serve-static' || parsedTargetString.target === 'preview') { return; } project = parsedTargetString.project; portFlagValue = matches[2]; } else { const NX_PROJECT_REGEX = /(?<=nx [^ ]+ )([^' ]+)(?: [^']*--port[= ](\d+))?/; const matches = command.match(NX_PROJECT_REGEX); if (!matches) { return; } project = matches[1]; portFlagValue = matches[2]; } if (!project || !graph.nodes[project]) { return; } const pathToViteConfig = [ (0, devkit_1.joinPathFragments)(graph.nodes[project].data.root, 'vite.config.ts'), (0, devkit_1.joinPathFragments)(graph.nodes[project].data.root, 'vite.config.js'), ].find((p) => tree.exists(p)); const pathToWebpackConfig = [ (0, devkit_1.joinPathFragments)(graph.nodes[project].data.root, 'webpack.config.ts'), (0, devkit_1.joinPathFragments)(graph.nodes[project].data.root, 'webpack.config.js'), ].find((p) => tree.exists(p)); const configFile = pathToWebpackConfig ?? pathToViteConfig; // Only migrate projects that have a webpack or vite config file if (configFile) { collectedProjects.push({ projectName: project, configFile, configFileType: pathToWebpackConfig ? 'webpack' : 'vite', playwrightConfigFile: path, commandValueNode, portFlagValue, }); } }); for (const projectToMigrate of collectedProjects) { let playwrightConfigFileContents = tree.read(projectToMigrate.playwrightConfigFile, 'utf-8'); const targetName = (await getServeStaticTargetNameForConfigFile(tree, projectToMigrate.configFileType === 'webpack' ? '@nx/webpack/plugin' : '@nx/vite/plugin', projectToMigrate.configFile, projectToMigrate.configFileType === 'webpack' ? 'serve-static' : 'preview', projectToMigrate.configFileType === 'webpack' ? 'serveStaticTargetName' : 'previewTargetName', projectToMigrate.configFileType === 'webpack' ? require('@nx/webpack/plugin').createNodesV2 : require('@nx/vite/plugin') .createNodesV2)) ?? getServeStaticLikeTarget(tree, graph, projectToMigrate.projectName, projectToMigrate.configFileType === 'webpack' ? '@nx/web:file-server' : '@nx/vite:preview-server'); if (!targetName) { continue; } const oldCommand = projectToMigrate.commandValueNode.getText(); const newCommand = oldCommand.replace(/nx.*[^"']/, `nx run ${projectToMigrate.projectName}:${targetName}${projectToMigrate.portFlagValue ? ` --port=${projectToMigrate.portFlagValue}` : ''}`); if (projectToMigrate.configFileType === 'webpack') { tree.write(projectToMigrate.playwrightConfigFile, `${playwrightConfigFileContents.slice(0, projectToMigrate.commandValueNode.getStart())}${newCommand}${playwrightConfigFileContents.slice(projectToMigrate.commandValueNode.getEnd())}`); } else { tree.write(projectToMigrate.playwrightConfigFile, `${playwrightConfigFileContents.slice(0, projectToMigrate.commandValueNode.getStart())}${newCommand}${playwrightConfigFileContents.slice(projectToMigrate.commandValueNode.getEnd())}`); playwrightConfigFileContents = tree.read(projectToMigrate.playwrightConfigFile, 'utf-8'); let ast = tsquery_1.tsquery.ast(playwrightConfigFileContents); const BASE_URL_SELECTOR = 'VariableDeclaration:has(Identifier[name=baseURL])'; const baseUrlNodes = (0, tsquery_1.tsquery)(ast, BASE_URL_SELECTOR, { visitAllChildren: true, }); if (!baseUrlNodes.length) { return; } const serverUrl = `http://localhost:${projectToMigrate.portFlagValue ?? '4300'}`; const baseUrlNode = baseUrlNodes[0]; const newBaseUrlVariableDeclaration = `baseURL = process.env['BASE_URL'] || '${serverUrl}';`; tree.write(projectToMigrate.playwrightConfigFile, `${playwrightConfigFileContents.slice(0, baseUrlNode.getStart())}${newBaseUrlVariableDeclaration}${playwrightConfigFileContents.slice(baseUrlNode.getEnd())}`); playwrightConfigFileContents = tree.read(projectToMigrate.playwrightConfigFile, 'utf-8'); ast = tsquery_1.tsquery.ast(playwrightConfigFileContents); const WEB_SERVER_URL_SELECTOR = 'PropertyAssignment:has(Identifier[name=webServer]) PropertyAssignment:has(Identifier[name=url]) > StringLiteral'; const webServerUrlNodes = (0, tsquery_1.tsquery)(ast, WEB_SERVER_URL_SELECTOR, { visitAllChildren: true, }); if (!webServerUrlNodes.length) { return; } const webServerUrlNode = webServerUrlNodes[0]; const newWebServerUrl = `'${serverUrl}'`; tree.write(projectToMigrate.playwrightConfigFile, `${playwrightConfigFileContents.slice(0, webServerUrlNode.getStart())}${newWebServerUrl}${playwrightConfigFileContents.slice(webServerUrlNode.getEnd())}`); } } await (0, add_e2e_ci_target_defaults_1.default)(tree); await (0, devkit_1.formatFiles)(tree); } async function getServeStaticTargetNameForConfigFile(tree, pluginName, configFile, defaultTargetName, targetNamePluginOption, createNodesV2) { const nxJson = (0, devkit_1.readNxJson)(tree); const matchingPluginRegistrations = nxJson.plugins?.filter((p) => typeof p === 'string' ? p === pluginName : p.plugin === pluginName); if (!matchingPluginRegistrations) { return undefined; } let targetName = undefined; for (const plugin of matchingPluginRegistrations) { let projectConfigs; try { const loadedPlugin = new loaded_nx_plugin_1.LoadedNxPlugin({ createNodesV2, name: pluginName }, plugin); projectConfigs = await (0, retrieve_workspace_files_1.retrieveProjectConfigurations)([loadedPlugin], tree.root, nxJson); } catch (e) { if (e instanceof error_types_1.ProjectConfigurationsError) { projectConfigs = e.partialProjectConfigurationsResult; } else { throw e; } } if (projectConfigs.matchingProjectFiles.includes(configFile)) { targetName = typeof plugin === 'string' ? defaultTargetName : plugin.options?.[targetNamePluginOption] ?? defaultTargetName; } } return targetName; } function getServeStaticLikeTarget(tree, graph, projectName, executorName) { if (!graph.nodes[projectName]?.data?.targets) { return; } for (const [targetName, targetOptions] of Object.entries(graph.nodes[projectName].data.targets)) { if (targetOptions.executor && targetOptions.executor === executorName) { return targetName; } } }