@nx/playwright 17.3.0-canary.20231219-9d7a724 → 17.3.0-canary.20231221-2374d8e

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/executors.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "executors": {
3
3
  "playwright": {
4
- "implementation": "./src/executors/playwright/playwright",
4
+ "implementation": "./src/executors/playwright/playwright.impl",
5
5
  "schema": "./src/executors/playwright/schema.json",
6
6
  "description": "Run Playwright tests."
7
7
  }
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { playwrightExecutor, PlaywrightExecutorSchema, } from './src/executors/playwright/playwright';
1
+ export { playwrightExecutor, PlaywrightExecutorSchema, } from './src/executors/playwright/playwright.impl';
2
2
  export { initGenerator } from './src/generators/init/init';
3
3
  export { configurationGenerator } from './src/generators/configuration/configuration';
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.configurationGenerator = exports.initGenerator = exports.playwrightExecutor = void 0;
4
- var playwright_1 = require("./src/executors/playwright/playwright");
5
- Object.defineProperty(exports, "playwrightExecutor", { enumerable: true, get: function () { return playwright_1.playwrightExecutor; } });
4
+ var playwright_impl_1 = require("./src/executors/playwright/playwright.impl");
5
+ Object.defineProperty(exports, "playwrightExecutor", { enumerable: true, get: function () { return playwright_impl_1.playwrightExecutor; } });
6
6
  var init_1 = require("./src/generators/init/init");
7
7
  Object.defineProperty(exports, "initGenerator", { enumerable: true, get: function () { return init_1.initGenerator; } });
8
8
  var configuration_1 = require("./src/generators/configuration/configuration");
@@ -0,0 +1,3 @@
1
+ {
2
+ "generators": {}
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/playwright",
3
- "version": "17.3.0-canary.20231219-9d7a724",
3
+ "version": "17.3.0-canary.20231221-2374d8e",
4
4
  "type": "commonjs",
5
5
  "homepage": "https://nx.dev",
6
6
  "private": false,
@@ -32,9 +32,11 @@
32
32
  "directory": "packages/playwright"
33
33
  },
34
34
  "dependencies": {
35
- "@nx/devkit": "17.3.0-canary.20231219-9d7a724",
36
- "@nx/eslint": "17.3.0-canary.20231219-9d7a724",
37
- "tslib": "^2.3.0"
35
+ "@nx/devkit": "17.3.0-canary.20231221-2374d8e",
36
+ "@nx/eslint": "17.3.0-canary.20231221-2374d8e",
37
+ "@nx/js": "17.3.0-canary.20231221-2374d8e",
38
+ "tslib": "^2.3.0",
39
+ "minimatch": "3.0.5"
38
40
  },
39
41
  "peerDependencies": {
40
42
  "@playwright/test": "^1.36.0"
@@ -54,6 +56,10 @@
54
56
  "./generators/*/schema.json": "./src/generators/*/schema.json",
55
57
  "./executors.json": "./executors.json",
56
58
  "./executors/*/schema.json": "./src/executors/*/schema.json",
59
+ "./plugin": "./plugin.js",
57
60
  "./preset": "./src/utils/preset.js"
61
+ },
62
+ "nx-migrations": {
63
+ "migrations": "./migrations.json"
58
64
  }
59
65
  }
package/plugin.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { createNodes, PlaywrightPluginOptions } from './src/plugins/plugin';
package/plugin.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNodes = void 0;
4
+ var plugin_1 = require("./src/plugins/plugin");
5
+ Object.defineProperty(exports, "createNodes", { enumerable: true, get: function () { return plugin_1.createNodes; } });
@@ -43,7 +43,7 @@ function createArgs(opts, exclude = ['skipInstall']) {
43
43
  // NOTE: playwright doesn't accept pascalCase args, only kebab-case
44
44
  const arg = (0, devkit_1.names)(key).fileName;
45
45
  if (Array.isArray(value)) {
46
- args.push(`--${arg}=${value.map((v) => v.trim()).join(',')}`);
46
+ args.push(...value.map((v) => `--${arg}=${v.trim()}`));
47
47
  }
48
48
  else if (typeof value === 'boolean') {
49
49
  // NOTE: playwright don't accept --arg=false, instead just don't pass the arg.
@@ -5,6 +5,7 @@ const devkit_1 = require("@nx/devkit");
5
5
  const path = require("path");
6
6
  const init_1 = require("../init/init");
7
7
  const add_linter_1 = require("../../utils/add-linter");
8
+ const versions_1 = require("@nx/js/src/utils/versions");
8
9
  async function configurationGenerator(tree, options) {
9
10
  const tasks = [];
10
11
  tasks.push(await (0, init_1.default)(tree, {
@@ -19,8 +20,13 @@ async function configurationGenerator(tree, options) {
19
20
  webServerAddress: options.webServerAddress ?? null,
20
21
  ...options,
21
22
  });
22
- addE2eTarget(tree, options);
23
- setupE2ETargetDefaults(tree);
23
+ const hasPlugin = (0, devkit_1.readNxJson)(tree).plugins?.some((p) => typeof p === 'string'
24
+ ? p === '@nx/playwright/plugin'
25
+ : p.plugin === '@nx/playwright/plugin');
26
+ if (!hasPlugin) {
27
+ addE2eTarget(tree, options);
28
+ setupE2ETargetDefaults(tree);
29
+ }
24
30
  tasks.push(await (0, add_linter_1.addLinterToPlaywrightProject)(tree, {
25
31
  project: options.project,
26
32
  linter: options.linter,
@@ -31,7 +37,8 @@ async function configurationGenerator(tree, options) {
31
37
  rootProject: options.rootProject ?? projectConfig.root === '.',
32
38
  }));
33
39
  if (options.js) {
34
- (0, devkit_1.toJS)(tree);
40
+ const { ModuleKind } = (0, devkit_1.ensurePackage)('typescript', versions_1.typescriptVersion);
41
+ (0, devkit_1.toJS)(tree, { extension: '.cjs', module: ModuleKind.CommonJS });
35
42
  }
36
43
  if (!options.skipFormat) {
37
44
  await (0, devkit_1.formatFiles)(tree);
@@ -66,7 +73,7 @@ Rename or remove the existing e2e target.`);
66
73
  executor: '@nx/playwright:playwright',
67
74
  outputs: [`{workspaceRoot}/dist/.playwright/${projectConfig.root}`],
68
75
  options: {
69
- config: `${projectConfig.root}/playwright.config.${options.js ? 'js' : 'ts'}`,
76
+ config: `${projectConfig.root}/playwright.config.${options.js ? 'cjs' : 'ts'}`,
70
77
  },
71
78
  };
72
79
  (0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
@@ -31,6 +31,9 @@ async function initGenerator(tree, options) {
31
31
  recommendations: ['ms-playwright.playwright'],
32
32
  }, null, 2));
33
33
  }
34
+ if (process.env.NX_PCV3 === 'true') {
35
+ addPlugin(tree);
36
+ }
34
37
  if (!options.skipInstall) {
35
38
  tasks.push(() => {
36
39
  devkit_1.output.log({
@@ -44,4 +47,19 @@ async function initGenerator(tree, options) {
44
47
  return (0, devkit_1.runTasksInSerial)(...tasks);
45
48
  }
46
49
  exports.initGenerator = initGenerator;
50
+ function addPlugin(tree) {
51
+ const nxJson = (0, devkit_1.readNxJson)(tree);
52
+ nxJson.plugins ??= [];
53
+ if (!nxJson.plugins.some((p) => typeof p === 'string'
54
+ ? p === '@nx/playwright/plugin'
55
+ : p.plugin === '@nx/playwright/plugin')) {
56
+ nxJson.plugins.push({
57
+ plugin: '@nx/playwright/plugin',
58
+ options: {
59
+ targetName: 'e2e',
60
+ },
61
+ });
62
+ (0, devkit_1.updateNxJson)(tree, nxJson);
63
+ }
64
+ }
47
65
  exports.default = initGenerator;
@@ -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>;
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNodes = exports.createDependencies = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const devkit_1 = require("@nx/devkit");
7
+ const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
8
+ const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
9
+ const workspace_context_1 = require("nx/src/utils/workspace-context");
10
+ const minimatch = require("minimatch");
11
+ const load_config_file_1 = require("../utils/load-config-file");
12
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
13
+ const js_1 = require("@nx/js");
14
+ const cachePath = (0, path_1.join)(cache_directory_1.projectGraphCacheDirectory, 'playwright.hash');
15
+ const targetsCache = (0, fs_1.existsSync)(cachePath) ? readTargetsCache() : {};
16
+ const calculatedTargets = {};
17
+ function readTargetsCache() {
18
+ return (0, devkit_1.readJsonFile)(cachePath);
19
+ }
20
+ function writeTargetsToCache(targets) {
21
+ (0, devkit_1.writeJsonFile)(cachePath, targets);
22
+ }
23
+ const createDependencies = () => {
24
+ writeTargetsToCache(calculatedTargets);
25
+ return [];
26
+ };
27
+ exports.createDependencies = createDependencies;
28
+ exports.createNodes = [
29
+ '**/playwright.config.{js,ts,cjs,cts,mjs,mts}',
30
+ async (configFilePath, options, context) => {
31
+ const projectRoot = (0, path_1.dirname)(configFilePath);
32
+ // Do not create a project if package.json and project.json isn't there.
33
+ const siblingFiles = (0, fs_1.readdirSync)(projectRoot);
34
+ if (!siblingFiles.includes('package.json') &&
35
+ !siblingFiles.includes('project.json')) {
36
+ return {};
37
+ }
38
+ const normalizedOptions = normalizeOptions(options);
39
+ const hash = (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, options, context, [
40
+ (0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot)),
41
+ ]);
42
+ const targets = targetsCache[hash] ??
43
+ (await buildPlaywrightTargets(configFilePath, projectRoot, normalizedOptions, context));
44
+ calculatedTargets[hash] = targets;
45
+ return {
46
+ projects: {
47
+ [projectRoot]: {
48
+ root: projectRoot,
49
+ targets,
50
+ },
51
+ },
52
+ };
53
+ },
54
+ ];
55
+ async function buildPlaywrightTargets(configFilePath, projectRoot, options, context) {
56
+ const playwrightConfig = await (0, load_config_file_1.loadPlaywrightConfig)((0, path_1.join)(context.workspaceRoot, configFilePath));
57
+ const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
58
+ const targets = {};
59
+ const baseTargetConfig = {
60
+ command: 'playwright test',
61
+ options: {
62
+ cwd: '{projectRoot}',
63
+ },
64
+ };
65
+ targets[options.targetName] = {
66
+ ...baseTargetConfig,
67
+ cache: true,
68
+ inputs: 'production' in namedInputs
69
+ ? ['default', '^production']
70
+ : ['default', '^default'],
71
+ outputs: getOutputs(projectRoot, playwrightConfig),
72
+ };
73
+ if (options.ciTargetName) {
74
+ const ciBaseTargetConfig = {
75
+ ...baseTargetConfig,
76
+ cache: true,
77
+ inputs: 'production' in namedInputs
78
+ ? ['default', '^production']
79
+ : ['default', '^default'],
80
+ outputs: getOutputs(projectRoot, playwrightConfig),
81
+ };
82
+ const testDir = playwrightConfig.testDir
83
+ ? (0, devkit_1.joinPathFragments)(projectRoot, playwrightConfig.testDir)
84
+ : projectRoot;
85
+ // Playwright defaults to the following pattern.
86
+ playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)';
87
+ const dependsOn = [];
88
+ forEachTestFile((testFile) => {
89
+ const relativeToProjectRoot = (0, path_1.relative)(projectRoot, testFile);
90
+ const targetName = `${options.ciTargetName}--${relativeToProjectRoot}`;
91
+ targets[targetName] = {
92
+ ...ciBaseTargetConfig,
93
+ command: `${baseTargetConfig.command} ${relativeToProjectRoot}`,
94
+ };
95
+ dependsOn.push({
96
+ target: targetName,
97
+ projects: 'self',
98
+ params: 'forward',
99
+ });
100
+ }, {
101
+ context,
102
+ path: testDir,
103
+ config: playwrightConfig,
104
+ });
105
+ targets[options.ciTargetName] ??= {};
106
+ targets[options.ciTargetName] = {
107
+ executor: 'nx:noop',
108
+ cache: ciBaseTargetConfig.cache,
109
+ inputs: ciBaseTargetConfig.inputs,
110
+ outputs: ciBaseTargetConfig.outputs,
111
+ dependsOn,
112
+ };
113
+ }
114
+ return targets;
115
+ }
116
+ async function forEachTestFile(cb, opts) {
117
+ const files = (0, workspace_context_1.getFilesInDirectoryUsingContext)(opts.context.workspaceRoot, opts.path);
118
+ const matcher = createMatcher(opts.config.testMatch);
119
+ const ignoredMatcher = opts.config.testIgnore
120
+ ? createMatcher(opts.config.testIgnore)
121
+ : () => false;
122
+ for (const file of files) {
123
+ if (matcher(file) && !ignoredMatcher(file)) {
124
+ cb(file);
125
+ }
126
+ }
127
+ }
128
+ function createMatcher(pattern) {
129
+ if (Array.isArray(pattern)) {
130
+ const matchers = pattern.map((p) => createMatcher(p));
131
+ return (path) => matchers.some((m) => m(path));
132
+ }
133
+ else if (pattern instanceof RegExp) {
134
+ return (path) => pattern.test(path);
135
+ }
136
+ else {
137
+ return (path) => {
138
+ try {
139
+ return minimatch(path, pattern);
140
+ }
141
+ catch (e) {
142
+ throw new Error(`Error matching ${path} with ${pattern}: ${e.message}`);
143
+ }
144
+ };
145
+ }
146
+ }
147
+ function getOutputs(projectRoot, playwrightConfig) {
148
+ function getOutput(path) {
149
+ if (path.startsWith('..')) {
150
+ return (0, path_1.join)('{workspaceRoot}', (0, path_1.join)(projectRoot, path));
151
+ }
152
+ else {
153
+ return (0, path_1.join)('{projectRoot}', path);
154
+ }
155
+ }
156
+ const outputs = [];
157
+ const { reporter, outputDir } = playwrightConfig;
158
+ if (reporter) {
159
+ const DEFAULT_REPORTER_OUTPUT = getOutput('playwright-report');
160
+ if (reporter === 'html' || reporter === 'json') {
161
+ // Reporter is a string, so it uses the default output directory.
162
+ outputs.push(DEFAULT_REPORTER_OUTPUT);
163
+ }
164
+ else if (Array.isArray(reporter)) {
165
+ for (const r of reporter) {
166
+ const [, opts] = r;
167
+ // There are a few different ways to specify an output file or directory
168
+ // depending on the reporter. This is a best effort to find the output.
169
+ if (!opts) {
170
+ outputs.push(DEFAULT_REPORTER_OUTPUT);
171
+ }
172
+ else if (opts.outputFile) {
173
+ outputs.push(getOutput(opts.outputFile));
174
+ }
175
+ else if (opts.outputDir) {
176
+ outputs.push(getOutput(opts.outputDir));
177
+ }
178
+ else if (opts.outputFolder) {
179
+ outputs.push(getOutput(opts.outputFolder));
180
+ }
181
+ else {
182
+ outputs.push(DEFAULT_REPORTER_OUTPUT);
183
+ }
184
+ }
185
+ }
186
+ }
187
+ if (outputDir) {
188
+ outputs.push(getOutput(outputDir));
189
+ }
190
+ else {
191
+ outputs.push(getOutput('./test-results'));
192
+ }
193
+ return outputs;
194
+ }
195
+ function normalizeOptions(options) {
196
+ return {
197
+ ...options,
198
+ targetName: options.targetName ?? 'e2e',
199
+ ciTargetName: options.ciTargetName ?? 'e2e-ci',
200
+ };
201
+ }
@@ -0,0 +1,3 @@
1
+ import type { PlaywrightTestConfig } from '@playwright/test';
2
+ export declare let dynamicImport: Function;
3
+ export declare function loadPlaywrightConfig(configFilePath: any): Promise<PlaywrightTestConfig>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadPlaywrightConfig = exports.dynamicImport = void 0;
4
+ const path_1 = require("path");
5
+ const js_1 = require("@nx/js");
6
+ const internal_1 = require("@nx/js/src/internal");
7
+ exports.dynamicImport = new Function('modulePath', 'return import(modulePath);');
8
+ async function loadPlaywrightConfig(configFilePath) {
9
+ {
10
+ let module;
11
+ if ((0, path_1.extname)(configFilePath) === '.ts') {
12
+ const tsConfigPath = (0, js_1.getRootTsConfigPath)();
13
+ if (tsConfigPath) {
14
+ const unregisterTsProject = (0, internal_1.registerTsProject)(tsConfigPath);
15
+ try {
16
+ // Require's cache doesn't notice when the file is updated, and
17
+ // this function is ran during daemon operation. If the config file
18
+ // is updated, we need to read its new contents, so we need to clear the cache.
19
+ // We can't just delete the cache entry for the config file, because
20
+ // it might have imports that need to be updated as well.
21
+ clearRequireCache();
22
+ // ts-node doesn't support dynamic import, so we need to use require
23
+ module = require(configFilePath);
24
+ }
25
+ finally {
26
+ unregisterTsProject();
27
+ }
28
+ }
29
+ else {
30
+ module = await (0, exports.dynamicImport)(configFilePath);
31
+ }
32
+ }
33
+ else {
34
+ module = await (0, exports.dynamicImport)(configFilePath);
35
+ }
36
+ return module.default ?? module;
37
+ }
38
+ }
39
+ exports.loadPlaywrightConfig = loadPlaywrightConfig;
40
+ const packageInstallationDirectories = ['node_modules', '.yarn'];
41
+ function clearRequireCache() {
42
+ Object.keys(require.cache).forEach((key) => {
43
+ // We don't want to clear the require cache of installed packages.
44
+ // Clearing them can cause some issues when running Nx without the daemon
45
+ // and may cause issues for other packages that use the module state
46
+ // in some to store cached information.
47
+ if (!packageInstallationDirectories.some((dir) => key.includes(dir))) {
48
+ delete require.cache[key];
49
+ }
50
+ });
51
+ }