Skip to content

Commit

Permalink
feat(angular): support migrating angular cli workspaces using cypress…
Browse files Browse the repository at this point in the history
… for e2e tests (#9105)
  • Loading branch information
leosvelperez committed Feb 28, 2022
1 parent 40f0f3d commit 615955a
Show file tree
Hide file tree
Showing 5 changed files with 735 additions and 66 deletions.
32 changes: 19 additions & 13 deletions docs/shared/migration/migration-angular.md
Expand Up @@ -8,9 +8,9 @@ using a monorepo approach. If you are currently using an Angular CLI workspace,
- The major version of your `Angular CLI` must align with the version of `Nx` you are upgrading to. For example, if you're using Angular CLI version 7, you must transition using the latest version 7 release of Nx.
- Currently, transforming an Angular CLI workspace to an Nx workspace automatically only supports a single project. If you have more than one project in your Angular CLI workspace, you can still migrate manually.

## Using ng add and preserving your existing structure
## Using the Nx CLI while preserving the existing structure

To add Nx to an existing Angular CLI workspace to an Nx workspace, with keeping your existing file structure in place, use the `ng add` command with the `--preserveAngularCLILayout` option:
To use the Nx CLI in an existing Angular CLI workspace while keeping your existing file structure in place, use the `ng add` command with the `--preserveAngularCLILayout` option:

```bash
ng add @nrwl/workspace --preserveAngularCLILayout
Expand All @@ -19,23 +19,23 @@ ng add @nrwl/workspace --preserveAngularCLILayout
This installs the `@nrwl/workspace` package into your workspace and applies the following changes to your workspace:

- Adds and installs the `@nrwl/workspace` package in your development dependencies.
- Creates an nx.json file in the root of your workspace.
- Adds a `decorate-angular-cli.js` to the root of your workspace, and a `postinstall` script in your `package.json` to run the script when your dependencies are updated. The script forwards the `ng` commands to the Nx CLI(nx) to enable features such as Computation Caching.
- Creates an `nx.json` file in the root of your workspace.
- Adds a `decorate-angular-cli.js` to the root of your workspace, and a `postinstall` script in your `package.json` to run the script when your dependencies are updated. The script forwards the `ng` commands to the Nx CLI (`nx`) to enable features such as [Computation Caching](/using-nx/caching).

After the process completes, you continue using the same serve/build/lint/test commands.
After the process completes, you can continue using the same `serve/build/lint/test` commands you are used to.

## Using ng add
## Transforming an Angular CLI workspace to an Nx workspace

To transform a Angular CLI workspace to an Nx workspace, use the `ng add` command:
To transform an Angular CLI workspace to an Nx workspace, run the following command:

```bash
ng add @nrwl/workspace
```

This installs the `@nrwl/workspace` package into your workspace and runs a generator (or schematic) to transform your workspace. The generator applies the following changes to your workspace:

- Installs the packages for the `Nx` plugin `@nrwl/angular` in your package.json.
- Creates an nx.json file in the root of your workspace.
- Installs the packages for the `Nx` plugin `@nrwl/angular` in your `package.json`.
- Creates an `nx.json` file in the root of your workspace.
- Creates configuration files for Prettier.
- Creates an `apps` folder for generating applications.
- Creates a `libs` folder for generating libraries.
Expand All @@ -45,7 +45,7 @@ This installs the `@nrwl/workspace` package into your workspace and runs a gener
- Updates your `package.json` with scripts to run various `Nx` workspace commands.
- Updates your `angular.json` configuration to reflect the new paths.

After the changes are applied, your workspace file structure should look similar to below:
After the changes are applied, your workspace file structure should look similar to the one below:

```treeview
<workspace name>/
Expand All @@ -61,20 +61,26 @@ After the changes are applied, your workspace file structure should look similar
│ │ │ ├── polyfills.ts
│ │ │ ├── styles.css
│ │ │ └── test.ts
│ │ ├── browserslist
│ │ ├── .browserslistrc
│ │ ├── karma.conf.js
│ │ ├── tsconfig.app.json
│ │ └── tsconfig.spec.json
│ └── <app name>-e2e/
│ ├── src/
│ ├── protractor.conf.js
│ ├── protractor.conf.js | cypress.json
│ └── tsconfig.json
├── libs/
├── tools/
├── README.md
├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc
├── angular.json
├── decorate-angular-cli.js
├── karma.conf.js
├── nx.json
├── package.json
├── README.md
└── tsconfig.base.json
```

Expand Down
97 changes: 96 additions & 1 deletion e2e/angular-core/src/ng-add.test.ts
@@ -1,6 +1,7 @@
process.env.SELECTED_CLI = 'angular';

import {
checkFilesDoNotExist,
checkFilesExist,
cleanupProject,
getSelectedPackageManager,
Expand Down Expand Up @@ -50,6 +51,12 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
updateFile('angular.json', JSON.stringify(angularJson, null, 2));
}

function addCypress() {
runCommand(
'npx ng add @cypress/schematic --skip-confirmation --e2e-update'
);
}

beforeEach(() => {
project = uniq('proj');
packageManager = getSelectedPackageManager();
Expand Down Expand Up @@ -272,7 +279,7 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
// Remove e2e directory
runCommand('mv e2e e2e-bak');
expect(() => runNgAdd('--npm-scope projscope --skip-install')).toThrow(
'An e2e project was specified but e2e/protractor.conf.js could not be found.'
'An e2e project with Protractor was found but "e2e/protractor.conf.js" could not be found.'
);
// Restore e2e directory
runCommand('mv e2e-bak e2e');
Expand All @@ -288,6 +295,94 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
// runCommand('mv src-bak src');
});

it('should handle wrong cypress setup', () => {
addCypress();

// Remove cypress.json
runCommand('mv cypress.json cypress.json.bak');
expect(() => runNgAdd('--npm-scope projscope --skip-install')).toThrow(
'An e2e project with Cypress was found but "cypress.json" could not be found.'
);
// Restore cypress.json
runCommand('mv cypress.json.bak cypress.json');

// Remove cypress directory
runCommand('mv cypress cypress-bak');
expect(() => runNgAdd('--npm-scope projscope --skip-install')).toThrow(
'An e2e project with Cypress was found but the "cypress" directory could not be found.'
);
// Restore cypress.json
runCommand('mv cypress-bak cypress');
});

it('should handle a workspace with cypress', () => {
addCypress();

runNgAdd('--npm-scope projscope --skip-install');

const e2eProject = `${project}-e2e`;
//check e2e project files
checkFilesDoNotExist(
'cypress.json',
'cypress/tsconfig.json',
'cypress/integration/spec.ts',
'cypress/plugins/index.ts',
'cypress/support/commands.ts',
'cypress/support/index.ts'
);
checkFilesExist(
`apps/${e2eProject}/cypress.json`,
`apps/${e2eProject}/tsconfig.json`,
`apps/${e2eProject}/src/integration/spec.ts`,
`apps/${e2eProject}/src/plugins/index.ts`,
`apps/${e2eProject}/src/support/commands.ts`,
`apps/${e2eProject}/src/support/index.ts`
);

const angularJson = readJson('angular.json');
// check e2e project config
expect(
angularJson.projects[project].architect['cypress-run']
).toBeUndefined();
expect(
angularJson.projects[project].architect['cypress-open']
).toBeUndefined();
expect(angularJson.projects[project].architect.e2e).toBeUndefined();
expect(angularJson.projects[e2eProject].root).toEqual(`apps/${e2eProject}`);
expect(angularJson.projects[e2eProject].architect['cypress-run']).toEqual({
builder: '@nrwl/cypress:cypress',
options: {
devServerTarget: `${project}:serve`,
cypressConfig: `apps/${e2eProject}/cypress.json`,
},
configurations: {
production: {
devServerTarget: `${project}:serve:production`,
},
},
});
expect(angularJson.projects[e2eProject].architect['cypress-open']).toEqual({
builder: '@nrwl/cypress:cypress',
options: {
watch: true,
cypressConfig: `apps/${e2eProject}/cypress.json`,
},
});
expect(angularJson.projects[e2eProject].architect.e2e).toEqual({
builder: '@nrwl/cypress:cypress',
options: {
devServerTarget: `${project}:serve`,
watch: true,
cypressConfig: `apps/${e2eProject}/cypress.json`,
},
configurations: {
production: {
devServerTarget: `${project}:serve:production`,
},
},
});
});

it('should support preserveAngularCliLayout', () => {
runNgAdd('--preserve-angular-cli-layout');

Expand Down
156 changes: 156 additions & 0 deletions packages/workspace/src/generators/init/__snapshots__/init.spec.ts.snap
@@ -1,5 +1,161 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`workspace move to nx layout cypress should handle project configuration without cypress-run or cypress-open 1`] = `
Object {
"implicitDependencies": Array [
"myApp",
],
"projectType": "application",
"root": "apps/myApp-e2e",
"sourceRoot": "apps/myApp-e2e/src",
"tags": Array [],
"targets": Object {
"e2e": Object {
"configurations": Object {
"production": Object {
"devServerTarget": "ng-cypress:serve:production",
},
},
"executor": "@nrwl/cypress:cypress",
"options": Object {
"cypressConfig": "apps/myApp-e2e/cypress.json",
"devServerTarget": "ng-cypress:serve",
"watch": true,
},
},
},
}
`;

exports[`workspace move to nx layout cypress should migrate e2e tests correctly 1`] = `
Object {
"compilerOptions": Object {
"outDir": "../../dist/out-tsc",
},
"extends": "../../tsconfig.base.json",
}
`;

exports[`workspace move to nx layout cypress should migrate e2e tests correctly 2`] = `
Object {
"baseUrl": "http://localhost:4200",
"fileServerFolder": ".",
"fixturesFolder": "./src/fixtures",
"integrationFolder": "./src/integration",
"pluginsFile": "./src/plugins/index.ts",
"screenshotsFolder": "../../dist/cypress/apps/myApp-e2e/screenshots",
"supportFile": "./src/support/index.ts",
"videosFolder": "../../dist/cypress/apps/myApp-e2e/videos",
}
`;

exports[`workspace move to nx layout cypress should migrate e2e tests correctly 3`] = `
Object {
"implicitDependencies": Array [
"myApp",
],
"projectType": "application",
"root": "apps/myApp-e2e",
"sourceRoot": "apps/myApp-e2e/src",
"tags": Array [],
"targets": Object {
"cypress-open": Object {
"executor": "@nrwl/cypress:cypress",
"options": Object {
"cypressConfig": "apps/myApp-e2e/cypress.json",
"watch": true,
},
},
"cypress-run": Object {
"configurations": Object {
"production": Object {
"devServerTarget": "ng-cypress:serve:production",
},
},
"executor": "@nrwl/cypress:cypress",
"options": Object {
"cypressConfig": "apps/myApp-e2e/cypress.json",
"devServerTarget": "ng-cypress:serve",
},
},
"e2e": Object {
"configurations": Object {
"production": Object {
"devServerTarget": "ng-cypress:serve:production",
},
},
"executor": "@nrwl/cypress:cypress",
"options": Object {
"cypressConfig": "apps/myApp-e2e/cypress.json",
"devServerTarget": "ng-cypress:serve",
"watch": true,
},
},
},
}
`;

exports[`workspace move to nx layout cypress should migrate e2e tests when configFile is set to false and there is no cypress.json 1`] = `
Object {
"chromeWebSecurity": false,
"fileServerFolder": ".",
"fixturesFolder": "./src/fixtures",
"integrationFolder": "./src/integration",
"modifyObstructiveCode": false,
"pluginsFile": "./src/plugins/index.ts",
"screenshotsFolder": "../../dist/cypress/apps/myApp-e2e/screenshots",
"supportFile": "./src/support/index.ts",
"video": true,
"videosFolder": "../../dist/cypress/apps/myApp-e2e/videos",
}
`;

exports[`workspace move to nx layout cypress should migrate e2e tests when configFile is set to false and there is no cypress.json 2`] = `
Object {
"implicitDependencies": Array [
"myApp",
],
"projectType": "application",
"root": "apps/myApp-e2e",
"sourceRoot": "apps/myApp-e2e/src",
"tags": Array [],
"targets": Object {
"cypress-open": Object {
"executor": "@nrwl/cypress:cypress",
"options": Object {
"cypressConfig": "apps/myApp-e2e/cypress.json",
"watch": true,
},
},
"cypress-run": Object {
"configurations": Object {
"production": Object {
"devServerTarget": "ng-cypress:serve:production",
},
},
"executor": "@nrwl/cypress:cypress",
"options": Object {
"cypressConfig": "apps/myApp-e2e/cypress.json",
"devServerTarget": "ng-cypress:serve",
},
},
"e2e": Object {
"configurations": Object {
"production": Object {
"devServerTarget": "ng-cypress:serve:production",
},
},
"executor": "@nrwl/cypress:cypress",
"options": Object {
"cypressConfig": "apps/myApp-e2e/cypress.json",
"devServerTarget": "ng-cypress:serve",
"watch": true,
},
},
},
}
`;

exports[`workspace move to nx layout should create nx.json 1`] = `
Object {
"affected": Object {
Expand Down

1 comment on commit 615955a

@vercel
Copy link

@vercel vercel bot commented on 615955a Feb 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.