feat(nx-plugin): replace @nx/plugin:e2e with @nx/jest:jest (#16866)

This commit is contained in:
Jason Jean 2023-05-08 16:10:30 -04:00 committed by GitHub
parent 1e8e84777c
commit 318b1cf584
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 181 additions and 33 deletions

View File

@ -201,6 +201,7 @@
"presets": []
},
"description": "Creates and runs the E2E tests for an Nx Plugin.",
"x-deprecated": "@nx/plugin:e2e is deprecated and will be removed in Nx 18. Use @nx/jest:jest instead.",
"aliases": [],
"hidden": false,
"path": "/packages/plugin/src/executors/e2e/schema.json",

View File

@ -3,14 +3,16 @@
"e2e": {
"implementation": "./src/executors/e2e/compat",
"schema": "./src/executors/e2e/schema.json",
"description": "Creates and runs the E2E tests for an Nx Plugin."
"description": "Creates and runs the E2E tests for an Nx Plugin.",
"x-deprecated": "@nx/plugin:e2e is deprecated and will be removed in Nx 18. Use @nx/jest:jest instead."
}
},
"executors": {
"e2e": {
"implementation": "./src/executors/e2e/e2e.impl",
"schema": "./src/executors/e2e/schema.json",
"description": "Creates and runs the E2E tests for an Nx Plugin."
"description": "Creates and runs the E2E tests for an Nx Plugin.",
"x-deprecated": "@nx/plugin:e2e is deprecated and will be removed in Nx 18. Use @nx/jest:jest instead."
}
}
}

View File

@ -41,6 +41,12 @@
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/nx-plugin with @nx/plugin",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-2-0-replace-e2e-executor": {
"cli": "nx",
"version": "16.2.0-beta.0",
"description": "Replace @nx/plugin:e2e with @nx/jest",
"implementation": "./src/migrations/update-16-2-0/replace-e2e-executor"
}
}
}

View File

@ -3,7 +3,9 @@ import 'dotenv/config';
import type { ExecutorContext } from '@nx/devkit';
import {
createProjectGraphAsync,
logger,
output,
parseTargetString,
readTargetOptions,
runExecutor,
@ -12,13 +14,21 @@ import { JestExecutorOptions } from '@nx/jest/src/executors/jest/schema';
import { jestExecutor } from '@nx/jest/src/executors/jest/jest.impl';
import type { NxPluginE2EExecutorOptions } from './schema';
// TODO(Caleb & Craigory): can we get rid of this and just use @nx/jest directly?
// TODO(v18): remove this
export async function* nxPluginE2EExecutor(
options: NxPluginE2EExecutorOptions,
context: ExecutorContext
): AsyncGenerator<{ success: boolean }> {
const { target, ...jestOptions } = options;
output.warn({
title: `"@nx/plugin:e2e" is deprecated and will be removed in Nx 18`,
bodyLines: [
'Use the "@nx/jest:jest" executor instead and set the following:',
`"dependsOn": ["${target}"]`,
],
});
let success: boolean;
for await (const _ of runBuildTarget(target, context)) {
try {
@ -36,7 +46,11 @@ async function* runBuildTarget(
buildTarget: string,
context: ExecutorContext
): AsyncGenerator<boolean> {
const { project, target, configuration } = parseTargetString(buildTarget);
const graph = await createProjectGraphAsync();
const { project, target, configuration } = parseTargetString(
buildTarget,
graph
);
const buildTargetOptions = readTargetOptions(
{ project, target, configuration },
context

View File

@ -4,7 +4,6 @@ import {
readProjectConfiguration,
readJson,
getProjects,
joinPathFragments,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { e2eProjectGenerator } from './e2e';
@ -88,7 +87,7 @@ describe('NxPlugin e2e-project Generator', () => {
expect(project.root).toBe('apps/namespace/my-plugin-e2e');
});
it('should update the tags and implicit dependencies', async () => {
it('should update the implicit dependencies', async () => {
await e2eProjectGenerator(tree, {
pluginName: 'my-plugin',
pluginOutputPath: `dist/libs/my-plugin`,
@ -97,7 +96,6 @@ describe('NxPlugin e2e-project Generator', () => {
const projects = Object.fromEntries(getProjects(tree));
expect(projects).toMatchObject({
'my-plugin-e2e': {
tags: [],
implicitDependencies: ['my-plugin'],
},
});
@ -115,10 +113,28 @@ describe('NxPlugin e2e-project Generator', () => {
expect(project).toBeTruthy();
expect(project.root).toEqual('apps/my-plugin-e2e');
expect(project.targets.e2e).toBeTruthy();
expect(project.targets.e2e).toMatchObject({
executor: '@nx/plugin:e2e',
options: expect.objectContaining({ target: 'my-plugin:build' }),
});
expect(project.targets.e2e).toMatchInlineSnapshot(`
{
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true,
},
},
"dependsOn": [
"^build",
],
"executor": "@nx/jest:jest",
"options": {
"jestConfig": "apps/my-plugin-e2e/jest.config.ts",
"passWithNoTests": true,
"runInBand": true,
},
"outputs": [
"{workspaceRoot}/coverage/{projectRoot}",
],
}
`);
});
it('should add jest support', async () => {

View File

@ -70,24 +70,16 @@ function addFiles(host: Tree, options: NormalizedSchema) {
});
}
function updateWorkspaceConfiguration(host: Tree, options: NormalizedSchema) {
async function addJest(host: Tree, options: NormalizedSchema) {
addProjectConfiguration(host, options.projectName, {
root: options.projectRoot,
projectType: 'application',
sourceRoot: `${options.projectRoot}/tests`,
targets: {
e2e: {
executor: '@nx/plugin:e2e',
options: { target: `${options.pluginName}:build` },
},
},
tags: [],
targets: {},
implicitDependencies: [options.pluginName],
});
}
async function addJest(host: Tree, options: NormalizedSchema) {
await jestProjectGenerator(host, {
const jestTask = await jestProjectGenerator(host, {
project: options.projectName,
setupFile: 'none',
supportTsx: false,
@ -96,17 +88,24 @@ async function addJest(host: Tree, options: NormalizedSchema) {
});
const project = readProjectConfiguration(host, options.projectName);
const testOptions = project.targets.test.options;
const e2eOptions = project.targets.e2e.options;
project.targets.e2e.options = {
...e2eOptions,
jestConfig: testOptions.jestConfig,
const testTarget = project.targets.test;
project.targets.e2e = {
...testTarget,
dependsOn: [`^build`],
options: {
...testTarget.options,
runInBand: true,
},
configurations: testTarget.configurations,
};
// remove the jest build target
delete project.targets.test;
updateProjectConfiguration(host, options.projectName, project);
return jestTask;
}
async function addLintingToApplication(
@ -134,14 +133,14 @@ export async function e2eProjectGenerator(host: Tree, schema: Schema) {
validatePlugin(host, schema.pluginName);
const options = normalizeOptions(host, schema);
addFiles(host, options);
updateWorkspaceConfiguration(host, options);
await addJest(host, options);
tasks.push(await addJest(host, options));
if (options.linter !== Linter.None) {
const lintTask = await addLintingToApplication(host, {
...options,
});
tasks.push(lintTask);
tasks.push(
await addLintingToApplication(host, {
...options,
})
);
}
if (!options.skipFormat) {

View File

@ -0,0 +1,68 @@
import {
Tree,
readJson,
updateJson,
addProjectConfiguration,
readProjectConfiguration,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replaceE2EExecutor from './replace-e2e-executor';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'proj1', {
root: 'proj1',
targets: {
build: {
executor: '@nx/js:rollup',
},
e2e: {
executor: '@nx/plugin:e2e',
options: {
target: 'proj1:build',
},
configurations: {
ci: {
ci: true,
},
},
},
},
});
});
it('should replace @nrwl/nx-plugin:e2e with @nx/jest:jest', async () => {
await replaceE2EExecutor(tree);
expect(readProjectConfiguration(tree, 'proj1')).toMatchInlineSnapshot(`
{
"$schema": "../node_modules/nx/schemas/project-schema.json",
"name": "proj1",
"root": "proj1",
"targets": {
"build": {
"executor": "@nx/js:rollup",
},
"e2e": {
"configurations": {
"ci": {
"ci": true,
"runInBand": true,
},
},
"dependsOn": [
"proj1:build",
],
"executor": "@nx/jest:jest",
"options": {
"runInBand": true,
},
},
},
}
`);
});
});

View File

@ -0,0 +1,42 @@
import {
Tree,
formatFiles,
getProjects,
updateProjectConfiguration,
} from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
import type { NxPluginE2EExecutorOptions } from '@nx/plugin/src/executors/e2e/schema';
export default async function replaceE2EExecutor(tree: Tree): Promise<void> {
const projects = getProjects(tree);
for (const executor of ['@nx/plugin:e2e', '@nrwl/nx-plugin:e2e']) {
forEachExecutorOptions<NxPluginE2EExecutorOptions>(
tree,
executor,
(options, project, target, configuration) => {
const projectConfiguration = projects.get(project);
const config = {
...options,
target: undefined,
runInBand: true,
};
if (configuration) {
projectConfiguration.targets[target].configurations[configuration] =
config;
} else {
projectConfiguration.targets[target].dependsOn = [
...(projectConfiguration.targets[target].dependsOn ?? []),
options.target,
];
projectConfiguration.targets[target].executor = '@nx/jest:jest';
projectConfiguration.targets[target].options = config;
}
updateProjectConfiguration(tree, project, projectConfiguration);
}
);
}
await formatFiles(tree);
}