@nx/playwright 0.0.0-pr-22179-271588f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +66 -0
- package/executors.json +9 -0
- package/generators.json +16 -0
- package/index.d.ts +3 -0
- package/index.js +9 -0
- package/migrations.json +16 -0
- package/package.json +66 -0
- package/plugin.d.ts +1 -0
- package/plugin.js +6 -0
- package/preset.d.ts +1 -0
- package/preset.js +4 -0
- package/src/executors/playwright/playwright.impl.d.ts +37 -0
- package/src/executors/playwright/playwright.impl.js +77 -0
- package/src/executors/playwright/schema.json +168 -0
- package/src/generators/configuration/configuration.d.ts +5 -0
- package/src/generators/configuration/configuration.js +153 -0
- package/src/generators/configuration/files/__directory__/example.spec.ts.template +8 -0
- package/src/generators/configuration/files/playwright.config.ts.template +75 -0
- package/src/generators/configuration/schema.d.ts +27 -0
- package/src/generators/configuration/schema.json +73 -0
- package/src/generators/init/init.d.ts +5 -0
- package/src/generators/init/init.js +51 -0
- package/src/generators/init/schema.d.ts +7 -0
- package/src/generators/init/schema.json +34 -0
- package/src/migrations/update-17-3-1/add-project-to-config.d.ts +2 -0
- package/src/migrations/update-17-3-1/add-project-to-config.js +95 -0
- package/src/migrations/update-18-1-0/remove-baseUrl-from-project-json.d.ts +2 -0
- package/src/migrations/update-18-1-0/remove-baseUrl-from-project-json.js +42 -0
- package/src/plugins/plugin.d.ts +7 -0
- package/src/plugins/plugin.js +205 -0
- package/src/utils/add-linter.d.ts +16 -0
- package/src/utils/add-linter.js +52 -0
- package/src/utils/preset.d.ts +30 -0
- package/src/utils/preset.js +60 -0
- package/src/utils/versions.d.ts +3 -0
- package/src/utils/versions.js +6 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configurationGeneratorInternal = exports.configurationGenerator = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const js_1 = require("@nx/js");
|
|
6
|
+
const versions_1 = require("@nx/js/src/utils/versions");
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const add_linter_1 = require("../../utils/add-linter");
|
|
10
|
+
const versions_2 = require("../../utils/versions");
|
|
11
|
+
const init_1 = require("../init/init");
|
|
12
|
+
function configurationGenerator(tree, options) {
|
|
13
|
+
return configurationGeneratorInternal(tree, { addPlugin: false, ...options });
|
|
14
|
+
}
|
|
15
|
+
exports.configurationGenerator = configurationGenerator;
|
|
16
|
+
async function configurationGeneratorInternal(tree, options) {
|
|
17
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
18
|
+
options.addPlugin ??=
|
|
19
|
+
process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
20
|
+
nxJson.useInferencePlugins !== false;
|
|
21
|
+
const tasks = [];
|
|
22
|
+
tasks.push(await (0, init_1.initGenerator)(tree, {
|
|
23
|
+
skipFormat: true,
|
|
24
|
+
skipPackageJson: options.skipPackageJson,
|
|
25
|
+
addPlugin: options.addPlugin,
|
|
26
|
+
}));
|
|
27
|
+
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
28
|
+
const hasTsConfig = tree.exists((0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json'));
|
|
29
|
+
const offsetFromProjectRoot = (0, devkit_1.offsetFromRoot)(projectConfig.root);
|
|
30
|
+
(0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files'), projectConfig.root, {
|
|
31
|
+
offsetFromRoot: offsetFromProjectRoot,
|
|
32
|
+
projectRoot: projectConfig.root,
|
|
33
|
+
webServerCommand: options.webServerCommand ?? null,
|
|
34
|
+
webServerAddress: options.webServerAddress ?? null,
|
|
35
|
+
...options,
|
|
36
|
+
});
|
|
37
|
+
if (!hasTsConfig) {
|
|
38
|
+
tree.write(`${projectConfig.root}/tsconfig.json`, JSON.stringify({
|
|
39
|
+
extends: (0, js_1.getRelativePathToRootTsConfig)(tree, projectConfig.root),
|
|
40
|
+
compilerOptions: {
|
|
41
|
+
allowJs: true,
|
|
42
|
+
outDir: `${offsetFromProjectRoot}dist/out-tsc`,
|
|
43
|
+
module: 'commonjs',
|
|
44
|
+
sourceMap: false,
|
|
45
|
+
},
|
|
46
|
+
include: [
|
|
47
|
+
'**/*.ts',
|
|
48
|
+
'**/*.js',
|
|
49
|
+
'playwright.config.ts',
|
|
50
|
+
'src/**/*.spec.ts',
|
|
51
|
+
'src/**/*.spec.js',
|
|
52
|
+
'src/**/*.test.ts',
|
|
53
|
+
'src/**/*.test.js',
|
|
54
|
+
'src/**/*.d.ts',
|
|
55
|
+
],
|
|
56
|
+
}, null, 2));
|
|
57
|
+
}
|
|
58
|
+
const hasPlugin = (0, devkit_1.readNxJson)(tree).plugins?.some((p) => typeof p === 'string'
|
|
59
|
+
? p === '@nx/playwright/plugin'
|
|
60
|
+
: p.plugin === '@nx/playwright/plugin');
|
|
61
|
+
if (!hasPlugin) {
|
|
62
|
+
addE2eTarget(tree, options);
|
|
63
|
+
setupE2ETargetDefaults(tree);
|
|
64
|
+
}
|
|
65
|
+
tasks.push(await (0, add_linter_1.addLinterToPlaywrightProject)(tree, {
|
|
66
|
+
project: options.project,
|
|
67
|
+
linter: options.linter,
|
|
68
|
+
skipPackageJson: options.skipPackageJson,
|
|
69
|
+
js: options.js,
|
|
70
|
+
directory: options.directory,
|
|
71
|
+
setParserOptionsProject: options.setParserOptionsProject,
|
|
72
|
+
rootProject: options.rootProject ?? projectConfig.root === '.',
|
|
73
|
+
addPlugin: options.addPlugin,
|
|
74
|
+
}));
|
|
75
|
+
if (options.js) {
|
|
76
|
+
const { ModuleKind } = (0, devkit_1.ensurePackage)('typescript', versions_1.typescriptVersion);
|
|
77
|
+
(0, devkit_1.toJS)(tree, { extension: '.cjs', module: ModuleKind.CommonJS });
|
|
78
|
+
}
|
|
79
|
+
recommendVsCodeExtensions(tree);
|
|
80
|
+
if (!options.skipPackageJson) {
|
|
81
|
+
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
82
|
+
// required since used in playwright config
|
|
83
|
+
'@nx/devkit': versions_2.nxVersion,
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
if (!options.skipInstall) {
|
|
87
|
+
tasks.push(getBrowsersInstallTask());
|
|
88
|
+
}
|
|
89
|
+
if (!options.skipFormat) {
|
|
90
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
91
|
+
}
|
|
92
|
+
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
93
|
+
}
|
|
94
|
+
exports.configurationGeneratorInternal = configurationGeneratorInternal;
|
|
95
|
+
function getBrowsersInstallTask() {
|
|
96
|
+
return () => {
|
|
97
|
+
devkit_1.output.log({
|
|
98
|
+
title: 'Ensuring Playwright is installed.',
|
|
99
|
+
bodyLines: ['use --skipInstall to skip installation.'],
|
|
100
|
+
});
|
|
101
|
+
const pmc = (0, devkit_1.getPackageManagerCommand)();
|
|
102
|
+
(0, child_process_1.execSync)(`${pmc.exec} playwright install`, { cwd: devkit_1.workspaceRoot });
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function recommendVsCodeExtensions(tree) {
|
|
106
|
+
if (tree.exists('.vscode/extensions.json')) {
|
|
107
|
+
(0, devkit_1.updateJson)(tree, '.vscode/extensions.json', (json) => {
|
|
108
|
+
json.recommendations ??= [];
|
|
109
|
+
const recs = new Set(json.recommendations);
|
|
110
|
+
recs.add('ms-playwright.playwright');
|
|
111
|
+
json.recommendations = Array.from(recs);
|
|
112
|
+
return json;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
(0, devkit_1.writeJson)(tree, '.vscode/extensions.json', {
|
|
117
|
+
recommendations: ['ms-playwright.playwright'],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function setupE2ETargetDefaults(tree) {
|
|
122
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
123
|
+
if (!nxJson.namedInputs) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// E2e targets depend on all their project's sources + production sources of dependencies
|
|
127
|
+
nxJson.targetDefaults ??= {};
|
|
128
|
+
const productionFileSet = !!nxJson.namedInputs?.production;
|
|
129
|
+
nxJson.targetDefaults.e2e ??= {};
|
|
130
|
+
nxJson.targetDefaults.e2e.cache ??= true;
|
|
131
|
+
nxJson.targetDefaults.e2e.inputs ??= [
|
|
132
|
+
'default',
|
|
133
|
+
productionFileSet ? '^production' : '^default',
|
|
134
|
+
];
|
|
135
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
136
|
+
}
|
|
137
|
+
function addE2eTarget(tree, options) {
|
|
138
|
+
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
139
|
+
if (projectConfig?.targets?.e2e) {
|
|
140
|
+
throw new Error(`Project ${options.project} already has an e2e target.
|
|
141
|
+
Rename or remove the existing e2e target.`);
|
|
142
|
+
}
|
|
143
|
+
projectConfig.targets ??= {};
|
|
144
|
+
projectConfig.targets.e2e = {
|
|
145
|
+
executor: '@nx/playwright:playwright',
|
|
146
|
+
outputs: [`{workspaceRoot}/dist/.playwright/${projectConfig.root}`],
|
|
147
|
+
options: {
|
|
148
|
+
config: `${projectConfig.root}/playwright.config.${options.js ? 'cjs' : 'ts'}`,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
(0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
|
|
152
|
+
}
|
|
153
|
+
exports.default = configurationGenerator;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
import { nxE2EPreset } from '@nx/playwright/preset';
|
|
3
|
+
<% if(!webServerCommand || !webServerAddress) { %>// eslint-disable-next-line @typescript-eslint/no-unused-vars <% } %>
|
|
4
|
+
import { workspaceRoot } from '@nx/devkit';
|
|
5
|
+
|
|
6
|
+
// For CI, you may want to set BASE_URL to the deployed application.
|
|
7
|
+
const baseURL = process.env['BASE_URL'] || '<% if(webServerAddress) {%><%= webServerAddress %><% } else {%>http://localhost:3000<% } %>';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Read environment variables from file.
|
|
11
|
+
* https://github.com/motdotla/dotenv
|
|
12
|
+
*/
|
|
13
|
+
// require('dotenv').config();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* See https://playwright.dev/docs/test-configuration.
|
|
17
|
+
*/
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
...nxE2EPreset(__filename, { testDir: './<%= directory %>' }),
|
|
20
|
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
21
|
+
use: {
|
|
22
|
+
baseURL,
|
|
23
|
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
24
|
+
trace: 'on-first-retry',
|
|
25
|
+
},
|
|
26
|
+
/* Run your local dev server before starting the tests */<% if(webServerCommand && webServerAddress) {%>
|
|
27
|
+
webServer: {
|
|
28
|
+
command: '<%= webServerCommand %>',
|
|
29
|
+
url: '<%= webServerAddress %>',
|
|
30
|
+
reuseExistingServer: !process.env.CI,
|
|
31
|
+
cwd: workspaceRoot
|
|
32
|
+
},<% } else {%>
|
|
33
|
+
// webServer: {
|
|
34
|
+
// command: 'npm run start',
|
|
35
|
+
// url: 'http://127.0.0.1:3000',
|
|
36
|
+
// reuseExistingServer: !process.env.CI,
|
|
37
|
+
// cwd: workspaceRoot,
|
|
38
|
+
// },<% } %>
|
|
39
|
+
projects: [
|
|
40
|
+
{
|
|
41
|
+
name: "chromium",
|
|
42
|
+
use: { ...devices["Desktop Chrome"] },
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
name: "firefox",
|
|
47
|
+
use: { ...devices["Desktop Firefox"] },
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
name: "webkit",
|
|
52
|
+
use: { ...devices["Desktop Safari"] },
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Uncomment for mobile browsers support
|
|
56
|
+
/* {
|
|
57
|
+
name: 'Mobile Chrome',
|
|
58
|
+
use: { ...devices['Pixel 5'] },
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'Mobile Safari',
|
|
62
|
+
use: { ...devices['iPhone 12'] },
|
|
63
|
+
}, */
|
|
64
|
+
|
|
65
|
+
// Uncomment for branded browsers
|
|
66
|
+
/* {
|
|
67
|
+
name: 'Microsoft Edge',
|
|
68
|
+
use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Google Chrome',
|
|
72
|
+
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
73
|
+
} */
|
|
74
|
+
],
|
|
75
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Linter } from '@nx/eslint';
|
|
2
|
+
|
|
3
|
+
export interface ConfigurationGeneratorSchema {
|
|
4
|
+
project: string;
|
|
5
|
+
/**
|
|
6
|
+
* this is relative to the projectRoot
|
|
7
|
+
**/
|
|
8
|
+
directory: string;
|
|
9
|
+
js: boolean; // default is false
|
|
10
|
+
skipFormat: boolean;
|
|
11
|
+
skipPackageJson: boolean;
|
|
12
|
+
skipInstall?: boolean;
|
|
13
|
+
linter: Linter;
|
|
14
|
+
setParserOptionsProject: boolean; // default is false
|
|
15
|
+
/**
|
|
16
|
+
* command to give playwright to run the web server
|
|
17
|
+
* @example: "npx nx serve my-fe-app"
|
|
18
|
+
**/
|
|
19
|
+
webServerCommand?: string;
|
|
20
|
+
/**
|
|
21
|
+
* address
|
|
22
|
+
* @example: "http://localhost:4200"
|
|
23
|
+
**/
|
|
24
|
+
webServerAddress?: string;
|
|
25
|
+
rootProject?: boolean;
|
|
26
|
+
addPlugin?: boolean;
|
|
27
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "NxPlaywrightConfiguration",
|
|
4
|
+
"description": "Add a Playwright configuration.",
|
|
5
|
+
"title": "Add a Playwright configuration",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"project": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "The project to add a Playwright configuration to.",
|
|
11
|
+
"$default": {
|
|
12
|
+
"$source": "projectName"
|
|
13
|
+
},
|
|
14
|
+
"x-priority": "important",
|
|
15
|
+
"x-prompt": "What is the name of the project to set up Playwright for?"
|
|
16
|
+
},
|
|
17
|
+
"directory": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "A directory where the project is placed relative from the project root.",
|
|
20
|
+
"x-priority": "important",
|
|
21
|
+
"default": "e2e"
|
|
22
|
+
},
|
|
23
|
+
"js": {
|
|
24
|
+
"type": "boolean",
|
|
25
|
+
"description": "Generate JavaScript files rather than TypeScript files.",
|
|
26
|
+
"default": false
|
|
27
|
+
},
|
|
28
|
+
"webServerCommand": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "The command to start the web server."
|
|
31
|
+
},
|
|
32
|
+
"webServerAddress": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "The address of the web server."
|
|
35
|
+
},
|
|
36
|
+
"linter": {
|
|
37
|
+
"description": "The tool to use for running lint checks.",
|
|
38
|
+
"type": "string",
|
|
39
|
+
"enum": ["eslint", "none"],
|
|
40
|
+
"default": "eslint"
|
|
41
|
+
},
|
|
42
|
+
"setParserOptionsProject": {
|
|
43
|
+
"type": "boolean",
|
|
44
|
+
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
|
|
45
|
+
"default": false
|
|
46
|
+
},
|
|
47
|
+
"skipFormat": {
|
|
48
|
+
"description": "Skip formatting files.",
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"default": false,
|
|
51
|
+
"x-priority": "internal"
|
|
52
|
+
},
|
|
53
|
+
"skipPackageJson": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"default": false,
|
|
56
|
+
"description": "Do not add dependencies to `package.json`.",
|
|
57
|
+
"x-priority": "internal"
|
|
58
|
+
},
|
|
59
|
+
"rootProject": {
|
|
60
|
+
"description": "Create a application at the root of the workspace",
|
|
61
|
+
"type": "boolean",
|
|
62
|
+
"default": false,
|
|
63
|
+
"hidden": true,
|
|
64
|
+
"x-priority": "internal"
|
|
65
|
+
},
|
|
66
|
+
"skipInstall": {
|
|
67
|
+
"type": "boolean",
|
|
68
|
+
"description": "Skip running `playwright install`. This is to ensure that playwright browsers are installed.",
|
|
69
|
+
"default": false
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"required": ["project"]
|
|
73
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { GeneratorCallback, Tree } from '@nx/devkit';
|
|
2
|
+
import { InitGeneratorSchema } from './schema';
|
|
3
|
+
export declare function initGenerator(tree: Tree, options: InitGeneratorSchema): Promise<GeneratorCallback>;
|
|
4
|
+
export declare function initGeneratorInternal(tree: Tree, options: InitGeneratorSchema): Promise<GeneratorCallback>;
|
|
5
|
+
export default initGenerator;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initGeneratorInternal = exports.initGenerator = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const update_package_scripts_1 = require("@nx/devkit/src/utils/update-package-scripts");
|
|
6
|
+
const plugin_1 = require("../../plugins/plugin");
|
|
7
|
+
const versions_1 = require("../../utils/versions");
|
|
8
|
+
function initGenerator(tree, options) {
|
|
9
|
+
return initGeneratorInternal(tree, { addPlugin: false, ...options });
|
|
10
|
+
}
|
|
11
|
+
exports.initGenerator = initGenerator;
|
|
12
|
+
async function initGeneratorInternal(tree, options) {
|
|
13
|
+
const tasks = [];
|
|
14
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
15
|
+
const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
16
|
+
nxJson.useInferencePlugins !== false;
|
|
17
|
+
options.addPlugin ??= addPluginDefault;
|
|
18
|
+
if (!options.skipPackageJson) {
|
|
19
|
+
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
20
|
+
'@nx/playwright': versions_1.nxVersion,
|
|
21
|
+
'@playwright/test': versions_1.playwrightVersion,
|
|
22
|
+
}, undefined, options.keepExistingVersions));
|
|
23
|
+
}
|
|
24
|
+
if (options.addPlugin) {
|
|
25
|
+
addPlugin(tree);
|
|
26
|
+
}
|
|
27
|
+
if (options.updatePackageScripts) {
|
|
28
|
+
await (0, update_package_scripts_1.updatePackageScripts)(tree, plugin_1.createNodes);
|
|
29
|
+
}
|
|
30
|
+
if (!options.skipFormat) {
|
|
31
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
32
|
+
}
|
|
33
|
+
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
34
|
+
}
|
|
35
|
+
exports.initGeneratorInternal = initGeneratorInternal;
|
|
36
|
+
function addPlugin(tree) {
|
|
37
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
38
|
+
nxJson.plugins ??= [];
|
|
39
|
+
if (!nxJson.plugins.some((p) => typeof p === 'string'
|
|
40
|
+
? p === '@nx/playwright/plugin'
|
|
41
|
+
: p.plugin === '@nx/playwright/plugin')) {
|
|
42
|
+
nxJson.plugins.push({
|
|
43
|
+
plugin: '@nx/playwright/plugin',
|
|
44
|
+
options: {
|
|
45
|
+
targetName: 'e2e',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.default = initGenerator;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "NxPlaywrightInit",
|
|
4
|
+
"title": "Playwright Init Generator",
|
|
5
|
+
"description": "Initializes a Playwright project in the current workspace.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"skipFormat": {
|
|
9
|
+
"description": "Skip formatting files.",
|
|
10
|
+
"type": "boolean",
|
|
11
|
+
"default": false,
|
|
12
|
+
"x-priority": "internal"
|
|
13
|
+
},
|
|
14
|
+
"skipPackageJson": {
|
|
15
|
+
"type": "boolean",
|
|
16
|
+
"default": false,
|
|
17
|
+
"description": "Do not add dependencies to `package.json`.",
|
|
18
|
+
"x-priority": "internal"
|
|
19
|
+
},
|
|
20
|
+
"keepExistingVersions": {
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"x-priority": "internal",
|
|
23
|
+
"description": "Keep existing dependencies versions",
|
|
24
|
+
"default": false
|
|
25
|
+
},
|
|
26
|
+
"updatePackageScripts": {
|
|
27
|
+
"type": "boolean",
|
|
28
|
+
"x-priority": "internal",
|
|
29
|
+
"description": "Update `package.json` scripts with inferred targets",
|
|
30
|
+
"default": false
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"required": []
|
|
34
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const devkit_1 = require("@nx/devkit");
|
|
4
|
+
const ts = require("typescript");
|
|
5
|
+
const tsquery_1 = require("@phenomnomnominal/tsquery");
|
|
6
|
+
async function update(tree) {
|
|
7
|
+
const projects = (0, devkit_1.getProjects)(tree);
|
|
8
|
+
projects.forEach((project) => {
|
|
9
|
+
// Check if the project contains playwright config
|
|
10
|
+
const configPath = (0, devkit_1.joinPathFragments)(project.root, 'playwright.config.ts');
|
|
11
|
+
if (tree.exists(configPath)) {
|
|
12
|
+
addProjectIfExists(tree, (0, devkit_1.joinPathFragments)(configPath));
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
exports.default = update;
|
|
17
|
+
function addProjectIfExists(tree, configFilePath) {
|
|
18
|
+
const configFileContent = tree.read(configFilePath, 'utf-8');
|
|
19
|
+
const sourceFile = tsquery_1.tsquery.ast(configFileContent);
|
|
20
|
+
const printer = ts.createPrinter();
|
|
21
|
+
const updatedStatements = updateOrCreateImportStatement(sourceFile, '@playwright/test', ['devices']);
|
|
22
|
+
const exportAssignment = tsquery_1.tsquery.query(sourceFile, 'ExportAssignment')[0];
|
|
23
|
+
if (!exportAssignment) {
|
|
24
|
+
// No export found in the file
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const exportAssignemntObject = exportAssignment.expression;
|
|
28
|
+
if (!(ts.isCallExpression(exportAssignemntObject) &&
|
|
29
|
+
exportAssignemntObject.getText(sourceFile).startsWith('defineConfig') &&
|
|
30
|
+
exportAssignemntObject.arguments.length > 0)) {
|
|
31
|
+
// Export is not a call expression with defineConfig ex. export default defineConfig({ ... })
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
let firstArgument = exportAssignemntObject.arguments[0];
|
|
35
|
+
if (!ts.isObjectLiteralExpression(firstArgument)) {
|
|
36
|
+
// First argument is not an object literal ex. defineConfig('foo')
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const projectProperty = tsquery_1.tsquery.query(exportAssignemntObject, 'PropertyAssignment > Identifier[name="projects"]')[0];
|
|
40
|
+
if (projectProperty) {
|
|
41
|
+
// Projects property already exists in the config
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Add projects property to the config
|
|
45
|
+
const projectsArray = ts.factory.createArrayLiteralExpression([
|
|
46
|
+
createProperty('chromium', 'Desktop Chrome'),
|
|
47
|
+
createProperty('firefox', 'Desktop Firefox'),
|
|
48
|
+
createProperty('webkit', 'Desktop Safari'),
|
|
49
|
+
], true);
|
|
50
|
+
const newProjectsProperty = ts.factory.createPropertyAssignment('projects', projectsArray);
|
|
51
|
+
const newObj = ts.factory.createObjectLiteralExpression([
|
|
52
|
+
...firstArgument.properties,
|
|
53
|
+
newProjectsProperty,
|
|
54
|
+
]);
|
|
55
|
+
const newCallExpression = ts.factory.updateCallExpression(exportAssignemntObject, exportAssignemntObject.expression, exportAssignemntObject.typeArguments, [newObj]);
|
|
56
|
+
const newExportAssignment = ts.factory.updateExportAssignment(exportAssignment, exportAssignment.modifiers, newCallExpression);
|
|
57
|
+
const transformedStatements = updatedStatements.map((statement) => {
|
|
58
|
+
return statement === exportAssignment ? newExportAssignment : statement;
|
|
59
|
+
});
|
|
60
|
+
const transformedSourceFile = ts.factory.updateSourceFile(sourceFile, transformedStatements);
|
|
61
|
+
const updatedConfigFileContent = printer.printFile(transformedSourceFile);
|
|
62
|
+
tree.write(configFilePath, updatedConfigFileContent);
|
|
63
|
+
}
|
|
64
|
+
function createProperty(name, device) {
|
|
65
|
+
return ts.factory.createObjectLiteralExpression([
|
|
66
|
+
ts.factory.createPropertyAssignment('name', ts.factory.createStringLiteral(name)),
|
|
67
|
+
ts.factory.createPropertyAssignment('use', ts.factory.createObjectLiteralExpression([
|
|
68
|
+
ts.factory.createSpreadAssignment(ts.factory.createElementAccessExpression(ts.factory.createIdentifier('devices'), ts.factory.createStringLiteral(device))),
|
|
69
|
+
])),
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
function updateOrCreateImportStatement(sourceFile, moduleName, importNames) {
|
|
73
|
+
let importDeclarationFound = false;
|
|
74
|
+
const newStatements = sourceFile.statements.map((statement) => {
|
|
75
|
+
if (ts.isImportDeclaration(statement) &&
|
|
76
|
+
statement.moduleSpecifier.getText(sourceFile) === `'${moduleName}'`) {
|
|
77
|
+
importDeclarationFound = true;
|
|
78
|
+
const existingSpecifiers = statement.importClause?.namedBindings &&
|
|
79
|
+
ts.isNamedImports(statement.importClause.namedBindings)
|
|
80
|
+
? statement.importClause.namedBindings.elements.map((e) => e.name.text)
|
|
81
|
+
: [];
|
|
82
|
+
// Merge with new import names, avoiding duplicates
|
|
83
|
+
const mergedImportNames = Array.from(new Set([...existingSpecifiers, ...importNames]));
|
|
84
|
+
// Create new import specifiers
|
|
85
|
+
const importSpecifiers = mergedImportNames.map((name) => ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(name)));
|
|
86
|
+
return ts.factory.updateImportDeclaration(statement, statement.modifiers, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(importSpecifiers)), statement.moduleSpecifier, undefined);
|
|
87
|
+
}
|
|
88
|
+
return statement;
|
|
89
|
+
});
|
|
90
|
+
if (!importDeclarationFound) {
|
|
91
|
+
const importDeclaration = ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(importNames.map((name) => ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(name))))), ts.factory.createStringLiteral(moduleName));
|
|
92
|
+
newStatements.push(importDeclaration);
|
|
93
|
+
}
|
|
94
|
+
return newStatements;
|
|
95
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const devkit_1 = require("@nx/devkit");
|
|
4
|
+
const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
|
|
5
|
+
async function default_1(tree) {
|
|
6
|
+
(0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/playwright:playwright', (options, projectName, targetName, configurationName) => {
|
|
7
|
+
if (options?.['baseUrl']) {
|
|
8
|
+
const project = (0, devkit_1.readProjectConfiguration)(tree, projectName);
|
|
9
|
+
if (configurationName) {
|
|
10
|
+
delete project.targets[targetName].configurations[configurationName]['baseUrl'];
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
delete project.targets[targetName].options['baseUrl'];
|
|
14
|
+
}
|
|
15
|
+
(0, devkit_1.updateProjectConfiguration)(tree, projectName, project);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
19
|
+
for (const [targetNameOrExecutor, target] of Object.entries(nxJson.targetDefaults)) {
|
|
20
|
+
if (targetNameOrExecutor === '@nx/playwright:playwright' ||
|
|
21
|
+
(target.executor && target.executor === '@nx/playwright:playwright')) {
|
|
22
|
+
let updated = false;
|
|
23
|
+
if (target.options?.['baseUrl']) {
|
|
24
|
+
delete nxJson.targetDefaults[targetNameOrExecutor].options['baseUrl'];
|
|
25
|
+
updated = true;
|
|
26
|
+
}
|
|
27
|
+
if (target.configurations) {
|
|
28
|
+
for (const [configurationName, configuration] of Object.entries(target.configurations)) {
|
|
29
|
+
if (configuration['baseUrl']) {
|
|
30
|
+
delete nxJson.targetDefaults[targetNameOrExecutor].configurations[configurationName]['baseUrl'];
|
|
31
|
+
updated = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (updated) {
|
|
36
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
41
|
+
}
|
|
42
|
+
exports.default = default_1;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CreateDependencies, CreateNodes } from '@nx/devkit';
|
|
2
|
+
export interface PlaywrightPluginOptions {
|
|
3
|
+
targetName?: string;
|
|
4
|
+
ciTargetName?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const createDependencies: CreateDependencies;
|
|
7
|
+
export declare const createNodes: CreateNodes<PlaywrightPluginOptions>;
|