feat(testing): use createNodesV2 for cypress and playwright (#26301)
This commit is contained in:
parent
92718fd52b
commit
1e7cd7e9e6
@ -1 +1 @@
|
|||||||
export { createNodes, createDependencies } from './src/plugins/plugin';
|
export { createNodesV2, createNodes } from './src/plugins/plugin';
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
CreateNodesContext,
|
|
||||||
createProjectGraphAsync,
|
createProjectGraphAsync,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
joinPathFragments,
|
|
||||||
type TargetConfiguration,
|
type TargetConfiguration,
|
||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import { createNodes } from '../../plugins/plugin';
|
import { createNodesV2 } from '../../plugins/plugin';
|
||||||
import { targetOptionsToCliMap } from './lib/target-options-map';
|
import { targetOptionsToCliMap } from './lib/target-options-map';
|
||||||
import { upsertBaseUrl } from './lib/upsert-baseUrl';
|
import { upsertBaseUrl } from './lib/upsert-baseUrl';
|
||||||
import { addDevServerTargetToConfig } from './lib/add-dev-server-target-to-config';
|
import { addDevServerTargetToConfig } from './lib/add-dev-server-target-to-config';
|
||||||
@ -31,7 +29,7 @@ export async function convertToInferred(tree: Tree, options: Schema) {
|
|||||||
ciTargetName: 'e2e-ci',
|
ciTargetName: 'e2e-ci',
|
||||||
}),
|
}),
|
||||||
postTargetTransformer,
|
postTargetTransformer,
|
||||||
createNodes,
|
createNodesV2,
|
||||||
options.project
|
options.project
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -45,7 +43,7 @@ export async function convertToInferred(tree: Tree, options: Schema) {
|
|||||||
ciTargetName: 'e2e-ci',
|
ciTargetName: 'e2e-ci',
|
||||||
}),
|
}),
|
||||||
postTargetTransformer,
|
postTargetTransformer,
|
||||||
createNodes,
|
createNodesV2,
|
||||||
options.project
|
options.project
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -10,14 +10,10 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import { addPlugin as _addPlugin } from '@nx/devkit/src/utils/add-plugin';
|
||||||
addPluginV1 as _addPlugin,
|
import { createNodesV2 } from '../../plugins/plugin';
|
||||||
generateCombinations,
|
|
||||||
} from '@nx/devkit/src/utils/add-plugin';
|
|
||||||
import { createNodes } from '../../plugins/plugin';
|
|
||||||
import { cypressVersion, nxVersion } from '../../utils/versions';
|
import { cypressVersion, nxVersion } from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { CypressPluginOptions } from '../../plugins/plugin';
|
|
||||||
|
|
||||||
function setupE2ETargetDefaults(tree: Tree) {
|
function setupE2ETargetDefaults(tree: Tree) {
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
@ -69,7 +65,7 @@ export function addPlugin(
|
|||||||
tree,
|
tree,
|
||||||
graph,
|
graph,
|
||||||
'@nx/cypress/plugin',
|
'@nx/cypress/plugin',
|
||||||
createNodes,
|
createNodesV2,
|
||||||
{
|
{
|
||||||
targetName: ['e2e', 'cypress:e2e', 'cypress-e2e'],
|
targetName: ['e2e', 'cypress:e2e', 'cypress-e2e'],
|
||||||
openTargetName: ['open-cypress', 'cypress-open'],
|
openTargetName: ['open-cypress', 'cypress-open'],
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { CreateNodesContext } from '@nx/devkit';
|
import { CreateNodesContext } from '@nx/devkit';
|
||||||
import { defineConfig } from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
|
|
||||||
import { createNodes } from './plugin';
|
import { createNodesV2 } from './plugin';
|
||||||
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
|
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
|
||||||
import { resetWorkspaceContext } from 'nx/src/utils/workspace-context';
|
import { resetWorkspaceContext } from 'nx/src/utils/workspace-context';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { nxE2EPreset } from '../../plugins/cypress-preset';
|
import { nxE2EPreset } from '../../plugins/cypress-preset';
|
||||||
|
|
||||||
describe('@nx/cypress/plugin', () => {
|
describe('@nx/cypress/plugin', () => {
|
||||||
let createNodesFunction = createNodes[1];
|
let createNodesFunction = createNodesV2[1];
|
||||||
let context: CreateNodesContext;
|
let context: CreateNodesContext;
|
||||||
let tempFs: TempFs;
|
let tempFs: TempFs;
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
const nodes = await createNodesFunction(
|
const nodes = await createNodesFunction(
|
||||||
'cypress.config.js',
|
['cypress.config.js'],
|
||||||
{
|
{
|
||||||
targetName: 'e2e',
|
targetName: 'e2e',
|
||||||
},
|
},
|
||||||
@ -73,59 +73,64 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(nodes).toMatchInlineSnapshot(`
|
expect(nodes).toMatchInlineSnapshot(`
|
||||||
{
|
[
|
||||||
"projects": {
|
[
|
||||||
".": {
|
"cypress.config.js",
|
||||||
"metadata": undefined,
|
{
|
||||||
"projectType": "application",
|
"projects": {
|
||||||
"targets": {
|
".": {
|
||||||
"e2e": {
|
"metadata": undefined,
|
||||||
"cache": true,
|
"projectType": "application",
|
||||||
"command": "cypress run",
|
"targets": {
|
||||||
"configurations": {
|
"e2e": {
|
||||||
"production": {
|
"cache": true,
|
||||||
"command": "cypress run --env webServerCommand="nx run my-app:serve:production"",
|
"command": "cypress run",
|
||||||
},
|
"configurations": {
|
||||||
},
|
"production": {
|
||||||
"inputs": [
|
"command": "cypress run --env webServerCommand="nx run my-app:serve:production"",
|
||||||
"default",
|
},
|
||||||
"^production",
|
},
|
||||||
{
|
"inputs": [
|
||||||
"externalDependencies": [
|
"default",
|
||||||
"cypress",
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"cypress",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Runs Cypress Tests",
|
||||||
|
"technologies": [
|
||||||
|
"cypress",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/dist/videos",
|
||||||
|
"{projectRoot}/dist/screenshots",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
"open-cypress": {
|
||||||
"metadata": {
|
"command": "cypress open",
|
||||||
"description": "Runs Cypress Tests",
|
"metadata": {
|
||||||
"technologies": [
|
"description": "Opens Cypress",
|
||||||
"cypress",
|
"technologies": [
|
||||||
],
|
"cypress",
|
||||||
},
|
],
|
||||||
"options": {
|
},
|
||||||
"cwd": ".",
|
"options": {
|
||||||
},
|
"cwd": ".",
|
||||||
"outputs": [
|
},
|
||||||
"{projectRoot}/dist/videos",
|
},
|
||||||
"{projectRoot}/dist/screenshots",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"open-cypress": {
|
|
||||||
"command": "cypress open",
|
|
||||||
"metadata": {
|
|
||||||
"description": "Opens Cypress",
|
|
||||||
"technologies": [
|
|
||||||
"cypress",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"cwd": ".",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
}
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -143,7 +148,7 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
const nodes = await createNodesFunction(
|
const nodes = await createNodesFunction(
|
||||||
'cypress.config.js',
|
['cypress.config.js'],
|
||||||
{
|
{
|
||||||
componentTestingTargetName: 'component-test',
|
componentTestingTargetName: 'component-test',
|
||||||
},
|
},
|
||||||
@ -151,54 +156,59 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(nodes).toMatchInlineSnapshot(`
|
expect(nodes).toMatchInlineSnapshot(`
|
||||||
{
|
[
|
||||||
"projects": {
|
[
|
||||||
".": {
|
"cypress.config.js",
|
||||||
"metadata": undefined,
|
{
|
||||||
"projectType": "application",
|
"projects": {
|
||||||
"targets": {
|
".": {
|
||||||
"component-test": {
|
"metadata": undefined,
|
||||||
"cache": true,
|
"projectType": "application",
|
||||||
"command": "cypress run --component",
|
"targets": {
|
||||||
"inputs": [
|
"component-test": {
|
||||||
"default",
|
"cache": true,
|
||||||
"^production",
|
"command": "cypress run --component",
|
||||||
{
|
"inputs": [
|
||||||
"externalDependencies": [
|
"default",
|
||||||
"cypress",
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"cypress",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Runs Cypress Component Tests",
|
||||||
|
"technologies": [
|
||||||
|
"cypress",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/dist/videos",
|
||||||
|
"{projectRoot}/dist/screenshots",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
"open-cypress": {
|
||||||
"metadata": {
|
"command": "cypress open",
|
||||||
"description": "Runs Cypress Component Tests",
|
"metadata": {
|
||||||
"technologies": [
|
"description": "Opens Cypress",
|
||||||
"cypress",
|
"technologies": [
|
||||||
],
|
"cypress",
|
||||||
},
|
],
|
||||||
"options": {
|
},
|
||||||
"cwd": ".",
|
"options": {
|
||||||
},
|
"cwd": ".",
|
||||||
"outputs": [
|
},
|
||||||
"{projectRoot}/dist/videos",
|
},
|
||||||
"{projectRoot}/dist/screenshots",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"open-cypress": {
|
|
||||||
"command": "cypress open",
|
|
||||||
"metadata": {
|
|
||||||
"description": "Opens Cypress",
|
|
||||||
"technologies": [
|
|
||||||
"cypress",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"cwd": ".",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
}
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -220,7 +230,7 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
const nodes = await createNodesFunction(
|
const nodes = await createNodesFunction(
|
||||||
'cypress.config.js',
|
['cypress.config.js'],
|
||||||
{
|
{
|
||||||
componentTestingTargetName: 'component-test',
|
componentTestingTargetName: 'component-test',
|
||||||
},
|
},
|
||||||
@ -228,122 +238,127 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(nodes).toMatchInlineSnapshot(`
|
expect(nodes).toMatchInlineSnapshot(`
|
||||||
{
|
[
|
||||||
"projects": {
|
[
|
||||||
".": {
|
"cypress.config.js",
|
||||||
"metadata": {
|
{
|
||||||
"targetGroups": {
|
"projects": {
|
||||||
"E2E (CI)": [
|
".": {
|
||||||
"e2e-ci--src/test.cy.ts",
|
"metadata": {
|
||||||
"e2e-ci",
|
"targetGroups": {
|
||||||
],
|
"E2E (CI)": [
|
||||||
},
|
"e2e-ci--src/test.cy.ts",
|
||||||
},
|
"e2e-ci",
|
||||||
"projectType": "application",
|
|
||||||
"targets": {
|
|
||||||
"e2e": {
|
|
||||||
"cache": true,
|
|
||||||
"command": "cypress run",
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"command": "cypress run --env webServerCommand="my-app:serve:production"",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production",
|
|
||||||
{
|
|
||||||
"externalDependencies": [
|
|
||||||
"cypress",
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"description": "Runs Cypress Tests",
|
|
||||||
"technologies": [
|
|
||||||
"cypress",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"options": {
|
"projectType": "application",
|
||||||
"cwd": ".",
|
"targets": {
|
||||||
},
|
"e2e": {
|
||||||
"outputs": [
|
"cache": true,
|
||||||
"{projectRoot}/dist/videos",
|
"command": "cypress run",
|
||||||
"{projectRoot}/dist/screenshots",
|
"configurations": {
|
||||||
],
|
"production": {
|
||||||
},
|
"command": "cypress run --env webServerCommand="my-app:serve:production"",
|
||||||
"e2e-ci": {
|
},
|
||||||
"cache": true,
|
},
|
||||||
"dependsOn": [
|
"inputs": [
|
||||||
{
|
"default",
|
||||||
"params": "forward",
|
"^production",
|
||||||
"projects": "self",
|
{
|
||||||
"target": "e2e-ci--src/test.cy.ts",
|
"externalDependencies": [
|
||||||
},
|
"cypress",
|
||||||
],
|
],
|
||||||
"executor": "nx:noop",
|
},
|
||||||
"inputs": [
|
],
|
||||||
"default",
|
"metadata": {
|
||||||
"^production",
|
"description": "Runs Cypress Tests",
|
||||||
{
|
"technologies": [
|
||||||
"externalDependencies": [
|
"cypress",
|
||||||
"cypress",
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/dist/videos",
|
||||||
|
"{projectRoot}/dist/screenshots",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
"e2e-ci": {
|
||||||
"metadata": {
|
"cache": true,
|
||||||
"description": "Runs Cypress Tests in CI",
|
"dependsOn": [
|
||||||
"technologies": [
|
{
|
||||||
"cypress",
|
"params": "forward",
|
||||||
],
|
"projects": "self",
|
||||||
},
|
"target": "e2e-ci--src/test.cy.ts",
|
||||||
"outputs": [
|
},
|
||||||
"{projectRoot}/dist/videos",
|
],
|
||||||
"{projectRoot}/dist/screenshots",
|
"executor": "nx:noop",
|
||||||
],
|
"inputs": [
|
||||||
},
|
"default",
|
||||||
"e2e-ci--src/test.cy.ts": {
|
"^production",
|
||||||
"cache": true,
|
{
|
||||||
"command": "cypress run --env webServerCommand="my-app:serve-static" --spec src/test.cy.ts",
|
"externalDependencies": [
|
||||||
"inputs": [
|
"cypress",
|
||||||
"default",
|
],
|
||||||
"^production",
|
},
|
||||||
{
|
],
|
||||||
"externalDependencies": [
|
"metadata": {
|
||||||
"cypress",
|
"description": "Runs Cypress Tests in CI",
|
||||||
|
"technologies": [
|
||||||
|
"cypress",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/dist/videos",
|
||||||
|
"{projectRoot}/dist/screenshots",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
"e2e-ci--src/test.cy.ts": {
|
||||||
"metadata": {
|
"cache": true,
|
||||||
"description": "Runs Cypress Tests in src/test.cy.ts in CI",
|
"command": "cypress run --env webServerCommand="my-app:serve-static" --spec src/test.cy.ts",
|
||||||
"technologies": [
|
"inputs": [
|
||||||
"cypress",
|
"default",
|
||||||
],
|
"^production",
|
||||||
},
|
{
|
||||||
"options": {
|
"externalDependencies": [
|
||||||
"cwd": ".",
|
"cypress",
|
||||||
},
|
],
|
||||||
"outputs": [
|
},
|
||||||
"{projectRoot}/dist/videos",
|
],
|
||||||
"{projectRoot}/dist/screenshots",
|
"metadata": {
|
||||||
],
|
"description": "Runs Cypress Tests in src/test.cy.ts in CI",
|
||||||
},
|
"technologies": [
|
||||||
"open-cypress": {
|
"cypress",
|
||||||
"command": "cypress open",
|
],
|
||||||
"metadata": {
|
},
|
||||||
"description": "Opens Cypress",
|
"options": {
|
||||||
"technologies": [
|
"cwd": ".",
|
||||||
"cypress",
|
},
|
||||||
],
|
"outputs": [
|
||||||
},
|
"{projectRoot}/dist/videos",
|
||||||
"options": {
|
"{projectRoot}/dist/screenshots",
|
||||||
"cwd": ".",
|
],
|
||||||
|
},
|
||||||
|
"open-cypress": {
|
||||||
|
"command": "cypress open",
|
||||||
|
"metadata": {
|
||||||
|
"description": "Opens Cypress",
|
||||||
|
"technologies": [
|
||||||
|
"cypress",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
}
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
CreateDependencies,
|
|
||||||
CreateNodes,
|
CreateNodes,
|
||||||
CreateNodesContext,
|
CreateNodesContext,
|
||||||
|
createNodesFromFiles,
|
||||||
|
CreateNodesV2,
|
||||||
detectPackageManager,
|
detectPackageManager,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
logger,
|
||||||
normalizePath,
|
normalizePath,
|
||||||
NxJsonConfiguration,
|
NxJsonConfiguration,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
@ -22,6 +24,7 @@ import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash
|
|||||||
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
||||||
import { NX_PLUGIN_OPTIONS } from '../utils/constants';
|
import { NX_PLUGIN_OPTIONS } from '../utils/constants';
|
||||||
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
||||||
|
import { hashObject } from 'nx/src/devkit-internals';
|
||||||
|
|
||||||
export interface CypressPluginOptions {
|
export interface CypressPluginOptions {
|
||||||
ciTargetName?: string;
|
ciTargetName?: string;
|
||||||
@ -30,67 +33,96 @@ export interface CypressPluginOptions {
|
|||||||
componentTestingTargetName?: string;
|
componentTestingTargetName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachePath = join(projectGraphCacheDirectory, 'cypress.hash');
|
function readTargetsCache(cachePath: string): Record<string, CypressTargets> {
|
||||||
const targetsCache = readTargetsCache();
|
|
||||||
|
|
||||||
function readTargetsCache(): Record<string, CypressTargets> {
|
|
||||||
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeTargetsToCache() {
|
function writeTargetsToCache(cachePath: string, results: CypressTargets) {
|
||||||
const oldCache = readTargetsCache();
|
writeJsonFile(cachePath, results);
|
||||||
writeJsonFile(cachePath, {
|
|
||||||
...oldCache,
|
|
||||||
targetsCache,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createDependencies: CreateDependencies = () => {
|
const cypressConfigGlob = '**/cypress.config.{js,ts,mjs,cjs}';
|
||||||
writeTargetsToCache();
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createNodes: CreateNodes<CypressPluginOptions> = [
|
export const createNodesV2: CreateNodesV2<CypressPluginOptions> = [
|
||||||
'**/cypress.config.{js,ts,mjs,cjs}',
|
cypressConfigGlob,
|
||||||
async (configFilePath, options, context) => {
|
async (configFiles, options, context) => {
|
||||||
options = normalizeOptions(options);
|
const optionsHash = hashObject(options);
|
||||||
const projectRoot = dirname(configFilePath);
|
const cachePath = join(
|
||||||
|
projectGraphCacheDirectory,
|
||||||
// Do not create a project if package.json and project.json isn't there.
|
`cypress-${optionsHash}.hash`
|
||||||
const siblingFiles = readdirSync(join(context.workspaceRoot, projectRoot));
|
|
||||||
if (
|
|
||||||
!siblingFiles.includes('package.json') &&
|
|
||||||
!siblingFiles.includes('project.json')
|
|
||||||
) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
|
||||||
]);
|
|
||||||
|
|
||||||
targetsCache[hash] ??= await buildCypressTargets(
|
|
||||||
configFilePath,
|
|
||||||
projectRoot,
|
|
||||||
options,
|
|
||||||
context
|
|
||||||
);
|
);
|
||||||
const { targets, metadata } = targetsCache[hash];
|
const targetsCache = readTargetsCache(cachePath);
|
||||||
|
try {
|
||||||
const project: Omit<ProjectConfiguration, 'root'> = {
|
return await createNodesFromFiles(
|
||||||
projectType: 'application',
|
(configFile, options, context) =>
|
||||||
targets,
|
createNodesInternal(configFile, options, context, targetsCache),
|
||||||
metadata,
|
configFiles,
|
||||||
};
|
options,
|
||||||
|
context
|
||||||
return {
|
);
|
||||||
projects: {
|
} finally {
|
||||||
[projectRoot]: project,
|
writeTargetsToCache(cachePath, targetsCache);
|
||||||
},
|
}
|
||||||
};
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This is replaced with {@link createNodesV2}. Update your plugin to export its own `createNodesV2` function that wraps this one instead.
|
||||||
|
* This function will change to the v2 function in Nx 20.
|
||||||
|
*/
|
||||||
|
export const createNodes: CreateNodes<CypressPluginOptions> = [
|
||||||
|
cypressConfigGlob,
|
||||||
|
(configFile, options, context) => {
|
||||||
|
logger.warn(
|
||||||
|
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
|
||||||
|
);
|
||||||
|
return createNodesInternal(configFile, options, context, {});
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function createNodesInternal(
|
||||||
|
configFilePath: string,
|
||||||
|
options: CypressPluginOptions,
|
||||||
|
context: CreateNodesContext,
|
||||||
|
targetsCache: CypressTargets
|
||||||
|
) {
|
||||||
|
options = normalizeOptions(options);
|
||||||
|
const projectRoot = dirname(configFilePath);
|
||||||
|
|
||||||
|
// Do not create a project if package.json and project.json isn't there.
|
||||||
|
const siblingFiles = readdirSync(join(context.workspaceRoot, projectRoot));
|
||||||
|
if (
|
||||||
|
!siblingFiles.includes('package.json') &&
|
||||||
|
!siblingFiles.includes('project.json')
|
||||||
|
) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
||||||
|
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
||||||
|
]);
|
||||||
|
|
||||||
|
targetsCache[hash] ??= await buildCypressTargets(
|
||||||
|
configFilePath,
|
||||||
|
projectRoot,
|
||||||
|
options,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
const { targets, metadata } = targetsCache[hash];
|
||||||
|
|
||||||
|
const project: Omit<ProjectConfiguration, 'root'> = {
|
||||||
|
projectType: 'application',
|
||||||
|
targets,
|
||||||
|
metadata,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
projects: {
|
||||||
|
[projectRoot]: project,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function getOutputs(
|
function getOutputs(
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
cypressConfig: any,
|
cypressConfig: any,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
CreateNodes,
|
CreateNodes,
|
||||||
|
CreateNodesV2,
|
||||||
} from 'nx/src/devkit-exports';
|
} from 'nx/src/devkit-exports';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -52,8 +53,8 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
#targetDefaultsForExecutor: Partial<TargetConfiguration>;
|
#targetDefaultsForExecutor: Partial<TargetConfiguration>;
|
||||||
#targetAndProjectsToMigrate: Map<string, Set<string>>;
|
#targetAndProjectsToMigrate: Map<string, Set<string>>;
|
||||||
#pluginToAddForTarget: Map<string, ExpandedPluginConfiguration<T>>;
|
#pluginToAddForTarget: Map<string, ExpandedPluginConfiguration<T>>;
|
||||||
#createNodes: CreateNodes<T>;
|
#createNodes?: CreateNodes<T>;
|
||||||
#configFiles: string[];
|
#createNodesV2?: CreateNodesV2<T>;
|
||||||
#createNodesResultsForTargets: Map<string, ConfigurationResult>;
|
#createNodesResultsForTargets: Map<string, ConfigurationResult>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -63,7 +64,8 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
pluginPath: string,
|
pluginPath: string,
|
||||||
pluginOptionsBuilder: PluginOptionsBuilder<T>,
|
pluginOptionsBuilder: PluginOptionsBuilder<T>,
|
||||||
postTargetTransformer: PostTargetTransformer,
|
postTargetTransformer: PostTargetTransformer,
|
||||||
createNodes: CreateNodes<T>,
|
createNodes?: CreateNodes<T>,
|
||||||
|
createNodesV2?: CreateNodesV2<T>,
|
||||||
specificProjectToMigrate?: string,
|
specificProjectToMigrate?: string,
|
||||||
skipTargetFilter?: SkipTargetFilter
|
skipTargetFilter?: SkipTargetFilter
|
||||||
) {
|
) {
|
||||||
@ -74,6 +76,7 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
this.#pluginOptionsBuilder = pluginOptionsBuilder;
|
this.#pluginOptionsBuilder = pluginOptionsBuilder;
|
||||||
this.#postTargetTransformer = postTargetTransformer;
|
this.#postTargetTransformer = postTargetTransformer;
|
||||||
this.#createNodes = createNodes;
|
this.#createNodes = createNodes;
|
||||||
|
this.#createNodesV2 = createNodesV2;
|
||||||
this.#specificProjectToMigrate = specificProjectToMigrate;
|
this.#specificProjectToMigrate = specificProjectToMigrate;
|
||||||
this.#skipTargetFilter = skipTargetFilter ?? ((...args) => [false, '']);
|
this.#skipTargetFilter = skipTargetFilter ?? ((...args) => [false, '']);
|
||||||
}
|
}
|
||||||
@ -224,6 +227,7 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
) {
|
) {
|
||||||
const loadedPlugin = new LoadedNxPlugin(
|
const loadedPlugin = new LoadedNxPlugin(
|
||||||
{
|
{
|
||||||
|
createNodesV2: this.#createNodesV2,
|
||||||
createNodes: this.#createNodes,
|
createNodes: this.#createNodes,
|
||||||
name: this.#pluginPath,
|
name: this.#pluginPath,
|
||||||
},
|
},
|
||||||
@ -373,6 +377,7 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
||||||
const loadedPlugin = new LoadedNxPlugin(
|
const loadedPlugin = new LoadedNxPlugin(
|
||||||
{
|
{
|
||||||
|
createNodesV2: this.#createNodesV2,
|
||||||
createNodes: this.#createNodes,
|
createNodes: this.#createNodes,
|
||||||
name: this.#pluginPath,
|
name: this.#pluginPath,
|
||||||
},
|
},
|
||||||
@ -396,13 +401,38 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#configFiles = Array.from(projectConfigs.matchingProjectFiles);
|
|
||||||
this.#createNodesResultsForTargets.set(targetName, projectConfigs);
|
this.#createNodesResultsForTargets.set(targetName, projectConfigs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function migrateExecutorToPlugin<T>(
|
export async function migrateExecutorToPlugin<T>(
|
||||||
|
tree: Tree,
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
executor: string,
|
||||||
|
pluginPath: string,
|
||||||
|
pluginOptionsBuilder: PluginOptionsBuilder<T>,
|
||||||
|
postTargetTransformer: PostTargetTransformer,
|
||||||
|
createNodes: CreateNodesV2<T>,
|
||||||
|
specificProjectToMigrate?: string,
|
||||||
|
skipTargetFilter?: SkipTargetFilter
|
||||||
|
): Promise<Map<string, Set<string>>> {
|
||||||
|
const migrator = new ExecutorToPluginMigrator<T>(
|
||||||
|
tree,
|
||||||
|
projectGraph,
|
||||||
|
executor,
|
||||||
|
pluginPath,
|
||||||
|
pluginOptionsBuilder,
|
||||||
|
postTargetTransformer,
|
||||||
|
undefined,
|
||||||
|
createNodes,
|
||||||
|
specificProjectToMigrate,
|
||||||
|
skipTargetFilter
|
||||||
|
);
|
||||||
|
return await migrator.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function migrateExecutorToPluginV1<T>(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
projectGraph: ProjectGraph,
|
projectGraph: ProjectGraph,
|
||||||
executor: string,
|
executor: string,
|
||||||
@ -421,6 +451,7 @@ export async function migrateExecutorToPlugin<T>(
|
|||||||
pluginOptionsBuilder,
|
pluginOptionsBuilder,
|
||||||
postTargetTransformer,
|
postTargetTransformer,
|
||||||
createNodes,
|
createNodes,
|
||||||
|
undefined,
|
||||||
specificProjectToMigrate,
|
specificProjectToMigrate,
|
||||||
skipTargetFilter
|
skipTargetFilter
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createNodes, EslintPluginOptions } from '../../plugins/plugin';
|
import { createNodes, EslintPluginOptions } from '../../plugins/plugin';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateExecutorToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import { targetOptionsToCliMap } from './lib/target-options-map';
|
import { targetOptionsToCliMap } from './lib/target-options-map';
|
||||||
import { interpolate } from 'nx/src/tasks-runner/utils';
|
import { interpolate } from 'nx/src/tasks-runner/utils';
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ export async function convertToInferred(tree: Tree, options: Schema) {
|
|||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
|
|
||||||
const migratedProjectsModern =
|
const migratedProjectsModern =
|
||||||
await migrateExecutorToPlugin<EslintPluginOptions>(
|
await migrateExecutorToPluginV1<EslintPluginOptions>(
|
||||||
tree,
|
tree,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
'@nx/eslint:lint',
|
'@nx/eslint:lint',
|
||||||
@ -31,7 +31,7 @@ export async function convertToInferred(tree: Tree, options: Schema) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const migratedProjectsLegacy =
|
const migratedProjectsLegacy =
|
||||||
await migrateExecutorToPlugin<EslintPluginOptions>(
|
await migrateExecutorToPluginV1<EslintPluginOptions>(
|
||||||
tree,
|
tree,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
'@nrwl/linter:eslint',
|
'@nrwl/linter:eslint',
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export {
|
export {
|
||||||
createNodes,
|
createNodes,
|
||||||
|
createNodesV2,
|
||||||
PlaywrightPluginOptions,
|
PlaywrightPluginOptions,
|
||||||
createDependencies,
|
|
||||||
} from './src/plugins/plugin';
|
} from './src/plugins/plugin';
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
type TargetConfiguration,
|
type TargetConfiguration,
|
||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createNodes, PlaywrightPluginOptions } from '../../plugins/plugin';
|
import { createNodesV2, PlaywrightPluginOptions } from '../../plugins/plugin';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
|
|
||||||
interface Schema {
|
interface Schema {
|
||||||
@ -24,7 +24,7 @@ export async function convertToInferred(tree: Tree, options: Schema) {
|
|||||||
'@nx/playwright/plugin',
|
'@nx/playwright/plugin',
|
||||||
(targetName) => ({ targetName, ciTargetName: 'e2e-ci' }),
|
(targetName) => ({ targetName, ciTargetName: 'e2e-ci' }),
|
||||||
postTargetTransformer,
|
postTargetTransformer,
|
||||||
createNodes,
|
createNodesV2,
|
||||||
options.project
|
options.project
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import {
|
|||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
import { addPlugin } from '@nx/devkit/src/utils/add-plugin';
|
||||||
import { createNodes } from '../../plugins/plugin';
|
import { createNodesV2 } from '../../plugins/plugin';
|
||||||
import { nxVersion, playwrightVersion } from '../../utils/versions';
|
import { nxVersion, playwrightVersion } from '../../utils/versions';
|
||||||
import { InitGeneratorSchema } from './schema';
|
import { InitGeneratorSchema } from './schema';
|
||||||
|
|
||||||
@ -45,11 +45,11 @@ export async function initGeneratorInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.addPlugin) {
|
if (options.addPlugin) {
|
||||||
await addPluginV1(
|
await addPlugin(
|
||||||
tree,
|
tree,
|
||||||
await createProjectGraphAsync(),
|
await createProjectGraphAsync(),
|
||||||
'@nx/playwright/plugin',
|
'@nx/playwright/plugin',
|
||||||
createNodes,
|
createNodesV2,
|
||||||
{ targetName: ['e2e', 'playwright:e2e', 'playwright-e2e'] },
|
{ targetName: ['e2e', 'playwright:e2e', 'playwright-e2e'] },
|
||||||
options.updatePackageScripts
|
options.updatePackageScripts
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { CreateNodesContext } from '@nx/devkit';
|
import { CreateNodesContext } from '@nx/devkit';
|
||||||
import { TempFs } from '@nx/devkit/internal-testing-utils';
|
import { TempFs } from '@nx/devkit/internal-testing-utils';
|
||||||
|
|
||||||
import { createNodes } from './plugin';
|
import { createNodesV2 } from './plugin';
|
||||||
import { PlaywrightTestConfig } from '@playwright/test';
|
import { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
|
||||||
describe('@nx/playwright/plugin', () => {
|
describe('@nx/playwright/plugin', () => {
|
||||||
let createNodesFunction = createNodes[1];
|
let createNodesFunction = createNodesV2[1];
|
||||||
let context: CreateNodesContext;
|
let context: CreateNodesContext;
|
||||||
let tempFs: TempFs;
|
let tempFs: TempFs;
|
||||||
|
|
||||||
@ -35,77 +35,84 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
|
|
||||||
it('should create nodes with default playwright configuration', async () => {
|
it('should create nodes with default playwright configuration', async () => {
|
||||||
await mockPlaywrightConfig(tempFs, {});
|
await mockPlaywrightConfig(tempFs, {});
|
||||||
const { projects } = await createNodesFunction(
|
const results = await createNodesFunction(
|
||||||
'playwright.config.js',
|
['playwright.config.js'],
|
||||||
{
|
{
|
||||||
targetName: 'e2e',
|
targetName: 'e2e',
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(projects).toMatchInlineSnapshot(`
|
expect(results).toMatchInlineSnapshot(`
|
||||||
{
|
[
|
||||||
".": {
|
[
|
||||||
"metadata": {
|
"playwright.config.js",
|
||||||
"targetGroups": {
|
{
|
||||||
"E2E (CI)": [
|
"projects": {
|
||||||
"e2e-ci",
|
".": {
|
||||||
],
|
"metadata": {
|
||||||
|
"targetGroups": {
|
||||||
|
"E2E (CI)": [
|
||||||
|
"e2e-ci",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"root": ".",
|
||||||
|
"targets": {
|
||||||
|
"e2e": {
|
||||||
|
"cache": true,
|
||||||
|
"command": "playwright test",
|
||||||
|
"inputs": [
|
||||||
|
"default",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@playwright/test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Runs Playwright Tests",
|
||||||
|
"technologies": [
|
||||||
|
"playwright",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": "{projectRoot}",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/test-results",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"e2e-ci": {
|
||||||
|
"cache": true,
|
||||||
|
"dependsOn": [],
|
||||||
|
"executor": "nx:noop",
|
||||||
|
"inputs": [
|
||||||
|
"default",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@playwright/test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Runs Playwright Tests in CI",
|
||||||
|
"technologies": [
|
||||||
|
"playwright",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/test-results",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"root": ".",
|
],
|
||||||
"targets": {
|
]
|
||||||
"e2e": {
|
|
||||||
"cache": true,
|
|
||||||
"command": "playwright test",
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production",
|
|
||||||
{
|
|
||||||
"externalDependencies": [
|
|
||||||
"@playwright/test",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"description": "Runs Playwright Tests",
|
|
||||||
"technologies": [
|
|
||||||
"playwright",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"cwd": "{projectRoot}",
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
"{projectRoot}/test-results",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"e2e-ci": {
|
|
||||||
"cache": true,
|
|
||||||
"dependsOn": [],
|
|
||||||
"executor": "nx:noop",
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production",
|
|
||||||
{
|
|
||||||
"externalDependencies": [
|
|
||||||
"@playwright/test",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"description": "Runs Playwright Tests in CI",
|
|
||||||
"technologies": [
|
|
||||||
"playwright",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
"{projectRoot}/test-results",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -117,83 +124,90 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
['html', { outputFolder: 'test-results/html' }],
|
['html', { outputFolder: 'test-results/html' }],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
const { projects } = await createNodesFunction(
|
const results = await createNodesFunction(
|
||||||
'playwright.config.js',
|
['playwright.config.js'],
|
||||||
{
|
{
|
||||||
targetName: 'e2e',
|
targetName: 'e2e',
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(projects).toMatchInlineSnapshot(`
|
expect(results).toMatchInlineSnapshot(`
|
||||||
{
|
[
|
||||||
".": {
|
[
|
||||||
"metadata": {
|
"playwright.config.js",
|
||||||
"targetGroups": {
|
{
|
||||||
"E2E (CI)": [
|
"projects": {
|
||||||
"e2e-ci",
|
".": {
|
||||||
],
|
"metadata": {
|
||||||
|
"targetGroups": {
|
||||||
|
"E2E (CI)": [
|
||||||
|
"e2e-ci",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"root": ".",
|
||||||
|
"targets": {
|
||||||
|
"e2e": {
|
||||||
|
"cache": true,
|
||||||
|
"command": "playwright test",
|
||||||
|
"inputs": [
|
||||||
|
"default",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@playwright/test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Runs Playwright Tests",
|
||||||
|
"technologies": [
|
||||||
|
"playwright",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": "{projectRoot}",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/playwright-report",
|
||||||
|
"{projectRoot}/test-results/report.json",
|
||||||
|
"{projectRoot}/test-results/html",
|
||||||
|
"{projectRoot}/test-results",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"e2e-ci": {
|
||||||
|
"cache": true,
|
||||||
|
"dependsOn": [],
|
||||||
|
"executor": "nx:noop",
|
||||||
|
"inputs": [
|
||||||
|
"default",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@playwright/test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Runs Playwright Tests in CI",
|
||||||
|
"technologies": [
|
||||||
|
"playwright",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/playwright-report",
|
||||||
|
"{projectRoot}/test-results/report.json",
|
||||||
|
"{projectRoot}/test-results/html",
|
||||||
|
"{projectRoot}/test-results",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"root": ".",
|
],
|
||||||
"targets": {
|
]
|
||||||
"e2e": {
|
|
||||||
"cache": true,
|
|
||||||
"command": "playwright test",
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production",
|
|
||||||
{
|
|
||||||
"externalDependencies": [
|
|
||||||
"@playwright/test",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"description": "Runs Playwright Tests",
|
|
||||||
"technologies": [
|
|
||||||
"playwright",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"cwd": "{projectRoot}",
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
"{projectRoot}/playwright-report",
|
|
||||||
"{projectRoot}/test-results/report.json",
|
|
||||||
"{projectRoot}/test-results/html",
|
|
||||||
"{projectRoot}/test-results",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"e2e-ci": {
|
|
||||||
"cache": true,
|
|
||||||
"dependsOn": [],
|
|
||||||
"executor": "nx:noop",
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production",
|
|
||||||
{
|
|
||||||
"externalDependencies": [
|
|
||||||
"@playwright/test",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"description": "Runs Playwright Tests in CI",
|
|
||||||
"technologies": [
|
|
||||||
"playwright",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
"{projectRoot}/playwright-report",
|
|
||||||
"{projectRoot}/test-results/report.json",
|
|
||||||
"{projectRoot}/test-results/html",
|
|
||||||
"{projectRoot}/test-results",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -213,16 +227,17 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
'not-tests/run-me.spec.ts': '',
|
'not-tests/run-me.spec.ts': '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const { projects } = await createNodesFunction(
|
const results = await createNodesFunction(
|
||||||
'playwright.config.js',
|
['playwright.config.js'],
|
||||||
{
|
{
|
||||||
targetName: 'e2e',
|
targetName: 'e2e',
|
||||||
ciTargetName: 'e2e-ci',
|
ciTargetName: 'e2e-ci',
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
);
|
);
|
||||||
const { targets } = projects['.'];
|
const project = results[0][1].projects['.'];
|
||||||
expect(projects['.'].metadata.targetGroups).toMatchInlineSnapshot(`
|
const { targets } = project;
|
||||||
|
expect(project.metadata.targetGroups).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"E2E (CI)": [
|
"E2E (CI)": [
|
||||||
"e2e-ci--tests/run-me-2.spec.ts",
|
"e2e-ci--tests/run-me-2.spec.ts",
|
||||||
|
|||||||
@ -2,11 +2,13 @@ import { existsSync, readdirSync } from 'fs';
|
|||||||
import { dirname, join, relative } from 'path';
|
import { dirname, join, relative } from 'path';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CreateDependencies,
|
|
||||||
CreateNodes,
|
CreateNodes,
|
||||||
CreateNodesContext,
|
CreateNodesContext,
|
||||||
|
createNodesFromFiles,
|
||||||
|
CreateNodesV2,
|
||||||
detectPackageManager,
|
detectPackageManager,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
logger,
|
||||||
normalizePath,
|
normalizePath,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
readJsonFile,
|
readJsonFile,
|
||||||
@ -22,6 +24,7 @@ import { minimatch } from 'minimatch';
|
|||||||
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
||||||
import { getLockFileName } from '@nx/js';
|
import { getLockFileName } from '@nx/js';
|
||||||
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
||||||
|
import { hashObject } from 'nx/src/hasher/file-hasher';
|
||||||
|
|
||||||
export interface PlaywrightPluginOptions {
|
export interface PlaywrightPluginOptions {
|
||||||
targetName?: string;
|
targetName?: string;
|
||||||
@ -33,69 +36,101 @@ interface NormalizedOptions {
|
|||||||
ciTargetName?: string;
|
ciTargetName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachePath = join(projectGraphCacheDirectory, 'playwright.hash');
|
|
||||||
|
|
||||||
const targetsCache = readTargetsCache();
|
|
||||||
|
|
||||||
type PlaywrightTargets = Pick<ProjectConfiguration, 'targets' | 'metadata'>;
|
type PlaywrightTargets = Pick<ProjectConfiguration, 'targets' | 'metadata'>;
|
||||||
|
|
||||||
function readTargetsCache(): Record<string, PlaywrightTargets> {
|
function readTargetsCache(
|
||||||
|
cachePath: string
|
||||||
|
): Record<string, PlaywrightTargets> {
|
||||||
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeTargetsToCache() {
|
function writeTargetsToCache(
|
||||||
const oldCache = readTargetsCache();
|
cachePath: string,
|
||||||
writeJsonFile(cachePath, {
|
results: Record<string, PlaywrightTargets>
|
||||||
...readTargetsCache,
|
) {
|
||||||
targetsCache,
|
writeJsonFile(cachePath, results);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createDependencies: CreateDependencies = () => {
|
const playwrightConfigGlob = '**/playwright.config.{js,ts,cjs,cts,mjs,mts}';
|
||||||
writeTargetsToCache();
|
export const createNodesV2: CreateNodesV2<PlaywrightPluginOptions> = [
|
||||||
return [];
|
playwrightConfigGlob,
|
||||||
};
|
async (configFilePaths, options, context) => {
|
||||||
|
const optionsHash = hashObject(options);
|
||||||
export const createNodes: CreateNodes<PlaywrightPluginOptions> = [
|
const cachePath = join(
|
||||||
'**/playwright.config.{js,ts,cjs,cts,mjs,mts}',
|
projectGraphCacheDirectory,
|
||||||
async (configFilePath, options, context) => {
|
`playwright-${optionsHash}.hash`
|
||||||
const projectRoot = dirname(configFilePath);
|
|
||||||
|
|
||||||
// Do not create a project if package.json and project.json isn't there.
|
|
||||||
const siblingFiles = readdirSync(join(context.workspaceRoot, projectRoot));
|
|
||||||
if (
|
|
||||||
!siblingFiles.includes('package.json') &&
|
|
||||||
!siblingFiles.includes('project.json')
|
|
||||||
) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizedOptions = normalizeOptions(options);
|
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
|
||||||
]);
|
|
||||||
|
|
||||||
targetsCache[hash] ??= await buildPlaywrightTargets(
|
|
||||||
configFilePath,
|
|
||||||
projectRoot,
|
|
||||||
normalizedOptions,
|
|
||||||
context
|
|
||||||
);
|
);
|
||||||
const { targets, metadata } = targetsCache[hash];
|
const targetsCache = readTargetsCache(cachePath);
|
||||||
|
try {
|
||||||
return {
|
return await createNodesFromFiles(
|
||||||
projects: {
|
(configFile, options, context) =>
|
||||||
[projectRoot]: {
|
createNodesInternal(configFile, options, context, targetsCache),
|
||||||
root: projectRoot,
|
configFilePaths,
|
||||||
targets,
|
options,
|
||||||
metadata,
|
context
|
||||||
},
|
);
|
||||||
},
|
} finally {
|
||||||
};
|
writeTargetsToCache(cachePath, targetsCache);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This is replaced with {@link createNodesV2}. Update your plugin to export its own `createNodesV2` function that wraps this one instead.
|
||||||
|
* This function will change to the v2 function in Nx 20.
|
||||||
|
*/
|
||||||
|
export const createNodes: CreateNodes<PlaywrightPluginOptions> = [
|
||||||
|
playwrightConfigGlob,
|
||||||
|
async (configFile, options, context) => {
|
||||||
|
logger.warn(
|
||||||
|
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
|
||||||
|
);
|
||||||
|
return createNodesInternal(configFile, options, context, {});
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function createNodesInternal(
|
||||||
|
configFilePath: string,
|
||||||
|
options: PlaywrightPluginOptions,
|
||||||
|
context: CreateNodesContext,
|
||||||
|
targetsCache: Record<string, PlaywrightTargets>
|
||||||
|
) {
|
||||||
|
const projectRoot = dirname(configFilePath);
|
||||||
|
|
||||||
|
// Do not create a project if package.json and project.json isn't there.
|
||||||
|
const siblingFiles = readdirSync(join(context.workspaceRoot, projectRoot));
|
||||||
|
if (
|
||||||
|
!siblingFiles.includes('package.json') &&
|
||||||
|
!siblingFiles.includes('project.json')
|
||||||
|
) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedOptions = normalizeOptions(options);
|
||||||
|
|
||||||
|
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
||||||
|
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
||||||
|
]);
|
||||||
|
|
||||||
|
targetsCache[hash] ??= await buildPlaywrightTargets(
|
||||||
|
configFilePath,
|
||||||
|
projectRoot,
|
||||||
|
normalizedOptions,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
const { targets, metadata } = targetsCache[hash];
|
||||||
|
|
||||||
|
return {
|
||||||
|
projects: {
|
||||||
|
[projectRoot]: {
|
||||||
|
root: projectRoot,
|
||||||
|
targets,
|
||||||
|
metadata,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function buildPlaywrightTargets(
|
async function buildPlaywrightTargets(
|
||||||
configFilePath: string,
|
configFilePath: string,
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user