feat(testing): migrate cypress to devkit
This commit is contained in:
parent
402f5069ad
commit
037c1b94b8
2
nx.json
2
nx.json
@ -51,7 +51,7 @@
|
|||||||
},
|
},
|
||||||
"cypress": {
|
"cypress": {
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"implicitDependencies": ["workspace"]
|
"implicitDependencies": ["workspace", "linter"]
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"tags": [],
|
"tags": [],
|
||||||
|
|||||||
@ -60,10 +60,10 @@ Array [
|
|||||||
"/.storybook/main.js",
|
"/.storybook/main.js",
|
||||||
"/.storybook/tsconfig.json",
|
"/.storybook/tsconfig.json",
|
||||||
"/.storybook/webpack.config.js",
|
"/.storybook/webpack.config.js",
|
||||||
"/apps/test-ui-lib-e2e/.eslintrc.json",
|
|
||||||
"/apps/test-ui-lib-e2e/cypress.json",
|
"/apps/test-ui-lib-e2e/cypress.json",
|
||||||
"/apps/test-ui-lib-e2e/tsconfig.e2e.json",
|
"/apps/test-ui-lib-e2e/tsconfig.e2e.json",
|
||||||
"/apps/test-ui-lib-e2e/tsconfig.json",
|
"/apps/test-ui-lib-e2e/tsconfig.json",
|
||||||
|
"/apps/test-ui-lib-e2e/.eslintrc.json",
|
||||||
"/apps/test-ui-lib-e2e/src/fixtures/example.json",
|
"/apps/test-ui-lib-e2e/src/fixtures/example.json",
|
||||||
"/apps/test-ui-lib-e2e/src/plugins/index.js",
|
"/apps/test-ui-lib-e2e/src/plugins/index.js",
|
||||||
"/apps/test-ui-lib-e2e/src/support/commands.ts",
|
"/apps/test-ui-lib-e2e/src/support/commands.ts",
|
||||||
|
|||||||
@ -1,5 +1,14 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../.eslintrc",
|
"extends": "../../.eslintrc",
|
||||||
"rules": {},
|
"rules": {},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["**/*.ts"],
|
||||||
|
"excludedFiles": ["./src/migrations/**"],
|
||||||
|
"rules": {
|
||||||
|
"no-restricted-imports": ["error", "@nrwl/workspace"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"ignorePatterns": ["!**/*"]
|
"ignorePatterns": ["!**/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,15 +3,30 @@
|
|||||||
"version": "0.1",
|
"version": "0.1",
|
||||||
"schematics": {
|
"schematics": {
|
||||||
"init": {
|
"init": {
|
||||||
"factory": "./src/schematics/init/init",
|
"factory": "./src/generators/init/init#initSchematic",
|
||||||
"schema": "./src/schematics/init/schema.json",
|
"schema": "./src/generators/init/schema.json",
|
||||||
"description": "Initialize the @nrwl/cypress plugin",
|
"description": "Initialize the @nrwl/cypress plugin",
|
||||||
"aliases": ["ng-add"],
|
"aliases": ["ng-add"],
|
||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
"cypress-project": {
|
"cypress-project": {
|
||||||
"factory": "./src/schematics/cypress-project/cypress-project",
|
"factory": "./src/generators/cypress-project/cypress-project#cypressProjectSchematic",
|
||||||
"schema": "./src/schematics/cypress-project/schema.json",
|
"schema": "./src/generators/cypress-project/schema.json",
|
||||||
|
"description": "Add a Cypress E2E Project",
|
||||||
|
"hidden": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"generators": {
|
||||||
|
"init": {
|
||||||
|
"factory": "./src/generators/init/init#initGenerator",
|
||||||
|
"schema": "./src/generators/init/schema.json",
|
||||||
|
"description": "Initialize the @nrwl/cypress plugin",
|
||||||
|
"aliases": ["ng-add"],
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
"cypress-project": {
|
||||||
|
"factory": "./src/generators/cypress-project/cypress-project#cypressProjectGenerator",
|
||||||
|
"schema": "./src/generators/cypress-project/schema.json",
|
||||||
"description": "Add a Cypress E2E Project",
|
"description": "Add a Cypress E2E Project",
|
||||||
"hidden": true
|
"hidden": true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { cypressProjectGenerator } from './src/schematics/cypress-project/cypress-project';
|
export { cypressProjectGenerator } from './src/generators/cypress-project/cypress-project';
|
||||||
|
|||||||
@ -36,9 +36,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nrwl/devkit": "*",
|
"@nrwl/devkit": "*",
|
||||||
"@angular-devkit/architect": "~0.1100.1",
|
"@nrwl/linter": "*",
|
||||||
"@angular-devkit/core": "~11.0.1",
|
|
||||||
"@angular-devkit/schematics": "~11.0.1",
|
|
||||||
"@cypress/webpack-preprocessor": "~4.1.2",
|
"@cypress/webpack-preprocessor": "~4.1.2",
|
||||||
"tree-kill": "1.2.2",
|
"tree-kill": "1.2.2",
|
||||||
"ts-loader": "5.4.5",
|
"ts-loader": "5.4.5",
|
||||||
|
|||||||
@ -1,23 +1,26 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit';
|
||||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import { runSchematic } from '../../utils/testing';
|
import { cypressProjectGenerator } from './cypress-project';
|
||||||
import { readJsonInTree, Linter, NxJson } from '@nrwl/workspace';
|
import { Schema } from './schema';
|
||||||
|
import { Linter } from '@nrwl/linter';
|
||||||
|
|
||||||
describe('schematic:cypress-project', () => {
|
describe('schematic:cypress-project', () => {
|
||||||
let appTree: Tree;
|
let tree: Tree;
|
||||||
|
const defaultOptions: Omit<Schema, 'name' | 'project'> = {
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
appTree = Tree.empty();
|
tree = createTreeWithEmptyWorkspace();
|
||||||
appTree = createEmptyWorkspace(appTree);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Cypress Project', () => {
|
describe('Cypress Project', () => {
|
||||||
it('should generate files', async () => {
|
it('should generate files', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
...defaultOptions,
|
||||||
{ name: 'my-app-e2e', project: 'my-app' },
|
name: 'my-app-e2e',
|
||||||
appTree
|
project: 'my-app',
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(tree.exists('apps/my-app-e2e/cypress.json')).toBeTruthy();
|
expect(tree.exists('apps/my-app-e2e/cypress.json')).toBeTruthy();
|
||||||
expect(tree.exists('apps/my-app-e2e/tsconfig.e2e.json')).toBeTruthy();
|
expect(tree.exists('apps/my-app-e2e/tsconfig.e2e.json')).toBeTruthy();
|
||||||
@ -37,12 +40,12 @@ describe('schematic:cypress-project', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add update `workspace.json` file', async () => {
|
it('should add update `workspace.json` file', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
name: 'my-app-e2e',
|
||||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.TsLint },
|
project: 'my-app',
|
||||||
appTree
|
linter: Linter.TsLint,
|
||||||
);
|
});
|
||||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
const project = workspaceJson.projects['my-app-e2e'];
|
const project = workspaceJson.projects['my-app-e2e'];
|
||||||
|
|
||||||
expect(project.root).toEqual('apps/my-app-e2e');
|
expect(project.root).toEqual('apps/my-app-e2e');
|
||||||
@ -70,12 +73,12 @@ describe('schematic:cypress-project', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add update `workspace.json` file properly when eslint is passed', async () => {
|
it('should add update `workspace.json` file properly when eslint is passed', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
name: 'my-app-e2e',
|
||||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.EsLint },
|
project: 'my-app',
|
||||||
appTree
|
linter: Linter.EsLint,
|
||||||
);
|
});
|
||||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
const workspaceJson = readJson(tree, 'workspace.json');
|
||||||
const project = workspaceJson.projects['my-app-e2e'];
|
const project = workspaceJson.projects['my-app-e2e'];
|
||||||
|
|
||||||
expect(project.architect.lint).toEqual({
|
expect(project.architect.lint).toEqual({
|
||||||
@ -87,26 +90,24 @@ describe('schematic:cypress-project', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
name: 'my-app-e2e',
|
||||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.EsLint },
|
project: 'my-app',
|
||||||
appTree
|
linter: Linter.EsLint,
|
||||||
);
|
|
||||||
|
|
||||||
const nxJson = readJsonInTree<NxJson>(tree, 'nx.json');
|
|
||||||
expect(nxJson.projects['my-app-e2e']).toEqual({
|
|
||||||
tags: [],
|
|
||||||
implicitDependencies: ['my-app'],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const project = readProjectConfiguration(tree, 'my-app-e2e');
|
||||||
|
expect(project.tags).toEqual([]);
|
||||||
|
expect(project.implicitDependencies).toEqual(['my-app']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set right path names in `cypress.json`', async () => {
|
it('should set right path names in `cypress.json`', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
...defaultOptions,
|
||||||
{ name: 'my-app-e2e', project: 'my-app' },
|
name: 'my-app-e2e',
|
||||||
appTree
|
project: 'my-app',
|
||||||
);
|
});
|
||||||
const cypressJson = readJsonInTree(tree, 'apps/my-app-e2e/cypress.json');
|
const cypressJson = readJson(tree, 'apps/my-app-e2e/cypress.json');
|
||||||
|
|
||||||
expect(cypressJson).toEqual({
|
expect(cypressJson).toEqual({
|
||||||
fileServerFolder: '.',
|
fileServerFolder: '.',
|
||||||
@ -123,15 +124,12 @@ describe('schematic:cypress-project', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set right path names in `tsconfig.e2e.json`', async () => {
|
it('should set right path names in `tsconfig.e2e.json`', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
...defaultOptions,
|
||||||
{ name: 'my-app-e2e', project: 'my-app' },
|
name: 'my-app-e2e',
|
||||||
appTree
|
project: 'my-app',
|
||||||
);
|
});
|
||||||
const tsconfigJson = readJsonInTree(
|
const tsconfigJson = readJson(tree, 'apps/my-app-e2e/tsconfig.e2e.json');
|
||||||
tree,
|
|
||||||
'apps/my-app-e2e/tsconfig.e2e.json'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(tsconfigJson.extends).toEqual('./tsconfig.json');
|
expect(tsconfigJson.extends).toEqual('./tsconfig.json');
|
||||||
expect(tsconfigJson.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
expect(tsconfigJson.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||||
@ -139,17 +137,13 @@ describe('schematic:cypress-project', () => {
|
|||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update workspace.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
name: 'my-app-e2e',
|
||||||
{
|
project: 'my-dir-my-app',
|
||||||
name: 'my-app-e2e',
|
directory: 'my-dir',
|
||||||
project: 'my-dir-my-app',
|
linter: Linter.TsLint,
|
||||||
directory: 'my-dir',
|
});
|
||||||
linter: Linter.TsLint,
|
const projectConfig = readJson(tree, 'workspace.json').projects[
|
||||||
},
|
|
||||||
appTree
|
|
||||||
);
|
|
||||||
const projectConfig = readJsonInTree(tree, 'workspace.json').projects[
|
|
||||||
'my-dir-my-app-e2e'
|
'my-dir-my-app-e2e'
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -178,12 +172,13 @@ describe('schematic:cypress-project', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set right path names in `cypress.json`', async () => {
|
it('should set right path names in `cypress.json`', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
...defaultOptions,
|
||||||
{ name: 'my-app-e2e', project: 'my-dir-my-app', directory: 'my-dir' },
|
name: 'my-app-e2e',
|
||||||
appTree
|
project: 'my-dir-my-app',
|
||||||
);
|
directory: 'my-dir',
|
||||||
const cypressJson = readJsonInTree(
|
});
|
||||||
|
const cypressJson = readJson(
|
||||||
tree,
|
tree,
|
||||||
'apps/my-dir/my-app-e2e/cypress.json'
|
'apps/my-dir/my-app-e2e/cypress.json'
|
||||||
);
|
);
|
||||||
@ -204,12 +199,13 @@ describe('schematic:cypress-project', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set right path names in `tsconfig.e2e.json`', async () => {
|
it('should set right path names in `tsconfig.e2e.json`', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
...defaultOptions,
|
||||||
{ name: 'my-app-e2e', project: 'my-dir-my-app', directory: 'my-dir' },
|
name: 'my-app-e2e',
|
||||||
appTree
|
project: 'my-dir-my-app',
|
||||||
);
|
directory: 'my-dir',
|
||||||
const tsconfigJson = readJsonInTree(
|
});
|
||||||
|
const tsconfigJson = readJson(
|
||||||
tree,
|
tree,
|
||||||
'apps/my-dir/my-app-e2e/tsconfig.e2e.json'
|
'apps/my-dir/my-app-e2e/tsconfig.e2e.json'
|
||||||
);
|
);
|
||||||
@ -223,13 +219,12 @@ describe('schematic:cypress-project', () => {
|
|||||||
describe('--project', () => {
|
describe('--project', () => {
|
||||||
describe('none', () => {
|
describe('none', () => {
|
||||||
it('should not add any implicit dependencies', async () => {
|
it('should not add any implicit dependencies', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
...defaultOptions,
|
||||||
{ name: 'my-app-e2e' },
|
name: 'my-app-e2e',
|
||||||
appTree
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const nxJson = readJsonInTree(tree, 'nx.json');
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
expect(nxJson.projects['my-app-e2e']).toEqual({ tags: [] });
|
expect(nxJson.projects['my-app-e2e']).toEqual({ tags: [] });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -238,16 +233,13 @@ describe('schematic:cypress-project', () => {
|
|||||||
describe('--linter', () => {
|
describe('--linter', () => {
|
||||||
describe('eslint', () => {
|
describe('eslint', () => {
|
||||||
it('should add eslint-plugin-cypress', async () => {
|
it('should add eslint-plugin-cypress', async () => {
|
||||||
const tree = await runSchematic(
|
await cypressProjectGenerator(tree, {
|
||||||
'cypress-project',
|
name: 'my-app-e2e',
|
||||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.EsLint },
|
project: 'my-app',
|
||||||
appTree
|
linter: Linter.EsLint,
|
||||||
);
|
});
|
||||||
const packageJson = readJsonInTree(tree, 'package.json');
|
const packageJson = readJson(tree, 'package.json');
|
||||||
const eslintrcJson = readJsonInTree(
|
const eslintrcJson = readJson(tree, 'apps/my-app-e2e/.eslintrc.json');
|
||||||
tree,
|
|
||||||
'apps/my-app-e2e/.eslintrc.json'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
packageJson.devDependencies['eslint-plugin-cypress']
|
packageJson.devDependencies['eslint-plugin-cypress']
|
||||||
@ -0,0 +1,140 @@
|
|||||||
|
import {
|
||||||
|
addDependenciesToPackageJson,
|
||||||
|
addProjectConfiguration,
|
||||||
|
convertNxGenerator,
|
||||||
|
formatFiles,
|
||||||
|
generateFiles,
|
||||||
|
getWorkspaceLayout,
|
||||||
|
joinPathFragments,
|
||||||
|
names,
|
||||||
|
offsetFromRoot,
|
||||||
|
toJS,
|
||||||
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||||
|
|
||||||
|
import { join } from 'path';
|
||||||
|
// app
|
||||||
|
import { Schema } from './schema';
|
||||||
|
import { eslintPluginCypressVersion } from '../../utils/versions';
|
||||||
|
|
||||||
|
export interface CypressProjectSchema extends Schema {
|
||||||
|
projectName: string;
|
||||||
|
projectRoot: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFiles(host: Tree, options: CypressProjectSchema) {
|
||||||
|
generateFiles(host, join(__dirname, './files'), options.projectRoot, {
|
||||||
|
tmpl: '',
|
||||||
|
...options,
|
||||||
|
project: options.project || 'Project',
|
||||||
|
ext: options.js ? 'js' : 'ts',
|
||||||
|
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.js) {
|
||||||
|
toJS(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addProject(host: Tree, options: CypressProjectSchema) {
|
||||||
|
addProjectConfiguration(host, options.projectName, {
|
||||||
|
root: options.projectRoot,
|
||||||
|
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||||
|
projectType: 'application',
|
||||||
|
targets: {
|
||||||
|
e2e: {
|
||||||
|
executor: '@nrwl/cypress:cypress',
|
||||||
|
options: {
|
||||||
|
cypressConfig: joinPathFragments(options.projectRoot, 'cypress.json'),
|
||||||
|
tsConfig: joinPathFragments(options.projectRoot, 'tsconfig.e2e.json'),
|
||||||
|
devServerTarget: `${options.project}:serve`,
|
||||||
|
},
|
||||||
|
configurations: {
|
||||||
|
production: {
|
||||||
|
devServerTarget: `${options.project}:serve:production`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tags: [],
|
||||||
|
implicitDependencies: options.project ? [options.project] : undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addLinter(host: Tree, options: CypressProjectSchema) {
|
||||||
|
const installTask = await lintProjectGenerator(host, {
|
||||||
|
project: options.projectName,
|
||||||
|
linter: options.linter,
|
||||||
|
skipFormat: true,
|
||||||
|
tsConfigPaths: [
|
||||||
|
joinPathFragments(options.projectRoot, 'tsconfig.e2e.json'),
|
||||||
|
],
|
||||||
|
eslintFilePatterns: [
|
||||||
|
`${options.projectRoot}/**/*.${options.js ? 'js' : '{js,ts}'}`,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.linter !== Linter.EsLint) {
|
||||||
|
return installTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
const installTask2 = addDependenciesToPackageJson(
|
||||||
|
host,
|
||||||
|
{},
|
||||||
|
{ 'eslint-plugin-cypress': eslintPluginCypressVersion }
|
||||||
|
);
|
||||||
|
|
||||||
|
updateJson(host, join(options.projectRoot, '.eslintrc.json'), (json) => {
|
||||||
|
json.extends = ['plugin:cypress/recommended', ...json.extends];
|
||||||
|
json.overrides = [
|
||||||
|
{
|
||||||
|
files: ['src/plugins/index.js'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
|
'no-undef': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
return installTask || installTask2;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function cypressProjectGenerator(host: Tree, schema: Schema) {
|
||||||
|
const options = normalizeOptions(host, schema);
|
||||||
|
createFiles(host, options);
|
||||||
|
addProject(host, options);
|
||||||
|
const installTask = await addLinter(host, options);
|
||||||
|
if (!options.skipFormat) {
|
||||||
|
await formatFiles(host);
|
||||||
|
}
|
||||||
|
return installTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeOptions(host: Tree, options: Schema): CypressProjectSchema {
|
||||||
|
const { appsDir } = getWorkspaceLayout(host);
|
||||||
|
const projectName = options.directory
|
||||||
|
? names(options.directory).fileName + '-' + options.name
|
||||||
|
: options.name;
|
||||||
|
const projectRoot = options.directory
|
||||||
|
? joinPathFragments(
|
||||||
|
appsDir,
|
||||||
|
names(options.directory).fileName,
|
||||||
|
options.name
|
||||||
|
)
|
||||||
|
: join(appsDir, options.name);
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
projectName,
|
||||||
|
projectRoot,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default cypressProjectGenerator;
|
||||||
|
export const cypressProjectSchematic = convertNxGenerator(
|
||||||
|
cypressProjectGenerator
|
||||||
|
);
|
||||||
10
packages/cypress/src/generators/cypress-project/schema.d.ts
vendored
Normal file
10
packages/cypress/src/generators/cypress-project/schema.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Linter } from '@nrwl/linter';
|
||||||
|
|
||||||
|
export interface Schema {
|
||||||
|
project?: string;
|
||||||
|
name: string;
|
||||||
|
directory?: string;
|
||||||
|
linter: Linter;
|
||||||
|
js?: boolean;
|
||||||
|
skipFormat?: boolean;
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"id": "Nx Cypress Project Generator Schema",
|
"id": "Nx Cypress Project Generator Schema",
|
||||||
|
"cli": "nx",
|
||||||
"title": "Create Cypress Configuration for the workspace",
|
"title": "Create Cypress Configuration for the workspace",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -34,6 +35,11 @@
|
|||||||
"description": "Generate JavaScript files rather than TypeScript files",
|
"description": "Generate JavaScript files rather than TypeScript files",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name"]
|
"required": ["name"]
|
||||||
33
packages/cypress/src/generators/init/init.spec.ts
Normal file
33
packages/cypress/src/generators/init/init.spec.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { readJson, Tree, updateJson } from '@nrwl/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
|
||||||
|
import { cypressVersion } from '../../utils/versions';
|
||||||
|
import initGenerator from './init';
|
||||||
|
|
||||||
|
describe('init', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add dependencies into `package.json` file', async () => {
|
||||||
|
const existing = 'existing';
|
||||||
|
const existingVersion = '1.0.0';
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.dependencies['@nrwl/cypress'] = cypressVersion;
|
||||||
|
|
||||||
|
json.dependencies[existing] = existingVersion;
|
||||||
|
json.devDependencies[existing] = existingVersion;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
initGenerator(tree);
|
||||||
|
const packageJson = readJson(tree, 'package.json');
|
||||||
|
|
||||||
|
expect(packageJson.devDependencies.cypress).toBeDefined();
|
||||||
|
expect(packageJson.devDependencies['@nrwl/cypress']).toBeDefined();
|
||||||
|
expect(packageJson.devDependencies[existing]).toBeDefined();
|
||||||
|
expect(packageJson.dependencies['@nrwl/cypress']).toBeUndefined();
|
||||||
|
expect(packageJson.dependencies[existing]).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
32
packages/cypress/src/generators/init/init.ts
Normal file
32
packages/cypress/src/generators/init/init.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
addDependenciesToPackageJson,
|
||||||
|
convertNxGenerator,
|
||||||
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
|
||||||
|
import { cypressVersion, nxVersion } from '../../utils/versions';
|
||||||
|
|
||||||
|
function updateDependencies(host: Tree) {
|
||||||
|
updateJson(host, 'package.json', (json) => {
|
||||||
|
json.dependencies = json.dependencies || {};
|
||||||
|
delete json.dependencies['@nrwl/cypress'];
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
return addDependenciesToPackageJson(
|
||||||
|
host,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
['@nrwl/cypress']: nxVersion,
|
||||||
|
cypress: cypressVersion,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initGenerator(host: Tree) {
|
||||||
|
return updateDependencies(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default initGenerator;
|
||||||
|
export const initSchematic = convertNxGenerator(initGenerator);
|
||||||
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"id": "NxCypressInit",
|
"id": "NxCypressInit",
|
||||||
|
"cli": "nx",
|
||||||
"title": "Add Cypress Configuration to the workspace",
|
"title": "Add Cypress Configuration to the workspace",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
@ -1,169 +0,0 @@
|
|||||||
import {
|
|
||||||
apply,
|
|
||||||
chain,
|
|
||||||
mergeWith,
|
|
||||||
move,
|
|
||||||
noop,
|
|
||||||
Rule,
|
|
||||||
SchematicContext,
|
|
||||||
template,
|
|
||||||
Tree,
|
|
||||||
url,
|
|
||||||
} from '@angular-devkit/schematics';
|
|
||||||
import { join, normalize } from '@angular-devkit/core';
|
|
||||||
// app
|
|
||||||
import {
|
|
||||||
NxJson,
|
|
||||||
Linter,
|
|
||||||
addDepsToPackageJson,
|
|
||||||
addLintFiles,
|
|
||||||
generateProjectLint,
|
|
||||||
updateJsonInTree,
|
|
||||||
updateWorkspaceInTree,
|
|
||||||
} from '@nrwl/workspace';
|
|
||||||
import { Schema } from './schema';
|
|
||||||
import { toJS } from '@nrwl/workspace/src/utils/rules/to-js';
|
|
||||||
import { appsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
|
||||||
import { eslintPluginCypressVersion } from '../../utils/versions';
|
|
||||||
import { names, offsetFromRoot } from '@nrwl/devkit';
|
|
||||||
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
|
|
||||||
|
|
||||||
export interface CypressProjectSchema extends Schema {
|
|
||||||
projectName: string;
|
|
||||||
projectRoot: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateFiles(options: CypressProjectSchema): Rule {
|
|
||||||
return (): Rule => {
|
|
||||||
return mergeWith(
|
|
||||||
apply(url('./files'), [
|
|
||||||
template({
|
|
||||||
tmpl: '',
|
|
||||||
...options,
|
|
||||||
ext: options.js ? 'js' : 'ts',
|
|
||||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
|
||||||
}),
|
|
||||||
move(options.projectRoot),
|
|
||||||
options.js ? toJS() : noop(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateNxJson(options: CypressProjectSchema): Rule {
|
|
||||||
return updateJsonInTree<NxJson>('nx.json', (json) => {
|
|
||||||
json.projects[options.projectName] = {
|
|
||||||
tags: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.project) {
|
|
||||||
json.projects[options.projectName].implicitDependencies = [
|
|
||||||
options.project,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateWorkspaceJson(options: CypressProjectSchema): Rule {
|
|
||||||
return updateWorkspaceInTree((json) => {
|
|
||||||
const architect: any = {};
|
|
||||||
|
|
||||||
architect.e2e = {
|
|
||||||
builder: '@nrwl/cypress:cypress',
|
|
||||||
options: {
|
|
||||||
cypressConfig: join(normalize(options.projectRoot), 'cypress.json'),
|
|
||||||
tsConfig: join(normalize(options.projectRoot), 'tsconfig.e2e.json'),
|
|
||||||
devServerTarget: `${options.project}:serve`,
|
|
||||||
},
|
|
||||||
configurations: {
|
|
||||||
production: {
|
|
||||||
devServerTarget: `${options.project}:serve:production`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
architect.lint = generateProjectLint(
|
|
||||||
normalize(options.projectRoot),
|
|
||||||
join(normalize(options.projectRoot), 'tsconfig.e2e.json'),
|
|
||||||
options.linter,
|
|
||||||
[`${options.projectRoot}/**/*.${options.js ? 'js' : '{js,ts}'}`]
|
|
||||||
);
|
|
||||||
|
|
||||||
json.projects[options.projectName] = {
|
|
||||||
root: options.projectRoot,
|
|
||||||
sourceRoot: join(normalize(options.projectRoot), 'src'),
|
|
||||||
projectType: 'application',
|
|
||||||
architect,
|
|
||||||
};
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addLinter(options: CypressProjectSchema): Rule {
|
|
||||||
return chain([
|
|
||||||
options.linter === Linter.EsLint
|
|
||||||
? addDepsToPackageJson(
|
|
||||||
{},
|
|
||||||
{ 'eslint-plugin-cypress': eslintPluginCypressVersion }
|
|
||||||
)
|
|
||||||
: noop(),
|
|
||||||
addLintFiles(options.projectRoot, options.linter, {
|
|
||||||
localConfig: {
|
|
||||||
extends: ['plugin:cypress/recommended'],
|
|
||||||
// we need this overrides because we enabled
|
|
||||||
// allowJS in the tsconfig to allow for JS based
|
|
||||||
// Cypress tests. That however leads to issues
|
|
||||||
// with the CommonJS Cypress plugin file
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['src/plugins/index.js'],
|
|
||||||
rules: {
|
|
||||||
'@typescript-eslint/no-var-requires': 'off',
|
|
||||||
'no-undef': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function (options: CypressProjectSchema): Rule {
|
|
||||||
return (host: Tree, context: SchematicContext) => {
|
|
||||||
options = normalizeOptions(host, options);
|
|
||||||
return chain([
|
|
||||||
addLinter(options),
|
|
||||||
generateFiles(options),
|
|
||||||
updateWorkspaceJson(options),
|
|
||||||
updateNxJson(options),
|
|
||||||
])(host, context);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeOptions(
|
|
||||||
host: Tree,
|
|
||||||
options: CypressProjectSchema
|
|
||||||
): CypressProjectSchema {
|
|
||||||
const projectName = options.directory
|
|
||||||
? names(options.directory).fileName + '-' + options.name
|
|
||||||
: options.name;
|
|
||||||
const projectRoot = options.directory
|
|
||||||
? join(
|
|
||||||
normalize(appsDir(host)),
|
|
||||||
names(options.directory).fileName,
|
|
||||||
options.name
|
|
||||||
)
|
|
||||||
: join(normalize(appsDir(host)), options.name);
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
projectName,
|
|
||||||
projectRoot,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const cypressProjectGenerator = wrapAngularDevkitSchematic(
|
|
||||||
'@nrwl/cypress',
|
|
||||||
'cypress-project'
|
|
||||||
);
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import { Linter } from '@nrwl/workspace';
|
|
||||||
|
|
||||||
export interface Schema {
|
|
||||||
project: string;
|
|
||||||
name: string;
|
|
||||||
directory: string;
|
|
||||||
linter: Linter;
|
|
||||||
js?: boolean;
|
|
||||||
}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
|
||||||
|
|
||||||
import { addDepsToPackageJson, readJsonInTree } from '@nrwl/workspace';
|
|
||||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
|
||||||
|
|
||||||
import { callRule, runSchematic } from '../../utils/testing';
|
|
||||||
import { cypressVersion } from '../../utils/versions';
|
|
||||||
|
|
||||||
describe('init', () => {
|
|
||||||
let appTree: Tree;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
appTree = Tree.empty();
|
|
||||||
appTree = createEmptyWorkspace(appTree);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add dependencies into `package.json` file', async () => {
|
|
||||||
const existing = 'existing';
|
|
||||||
const existingVersion = '1.0.0';
|
|
||||||
await callRule(
|
|
||||||
addDepsToPackageJson(
|
|
||||||
{ '@nrwl/cypress': cypressVersion, [existing]: existingVersion },
|
|
||||||
{ [existing]: existingVersion },
|
|
||||||
false
|
|
||||||
),
|
|
||||||
appTree
|
|
||||||
);
|
|
||||||
const tree = await runSchematic('init', {}, appTree);
|
|
||||||
const packageJson = readJsonInTree(tree, 'package.json');
|
|
||||||
|
|
||||||
expect(packageJson.devDependencies.cypress).toBeDefined();
|
|
||||||
expect(packageJson.devDependencies['@nrwl/cypress']).toBeDefined();
|
|
||||||
expect(packageJson.devDependencies[existing]).toBeDefined();
|
|
||||||
expect(packageJson.dependencies['@nrwl/cypress']).toBeUndefined();
|
|
||||||
expect(packageJson.dependencies[existing]).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import { Rule, Tree } from '@angular-devkit/schematics';
|
|
||||||
|
|
||||||
import { Schema } from './schema';
|
|
||||||
import { cypressVersion, nxVersion } from '../../utils/versions';
|
|
||||||
import { readJsonInTree, updateJsonInTree } from '@nrwl/workspace';
|
|
||||||
|
|
||||||
function updateDependencies(): Rule {
|
|
||||||
return (host: Tree): Rule => {
|
|
||||||
const packageJson = readJsonInTree(host, 'package.json');
|
|
||||||
const devDependencies = { ...packageJson.devDependencies };
|
|
||||||
const dependencies = { ...packageJson.dependencies };
|
|
||||||
if (!devDependencies['cypress']) {
|
|
||||||
devDependencies['cypress'] = cypressVersion;
|
|
||||||
}
|
|
||||||
if (!devDependencies['@nrwl/cypress']) {
|
|
||||||
devDependencies['@nrwl/cypress'] = nxVersion;
|
|
||||||
}
|
|
||||||
if (packageJson.dependencies['@nrwl/cypress']) {
|
|
||||||
delete dependencies['@nrwl/cypress'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateJsonInTree('package.json', (json) => {
|
|
||||||
json.dependencies = dependencies;
|
|
||||||
json.devDependencies = devDependencies;
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function (schema: Schema) {
|
|
||||||
return updateDependencies();
|
|
||||||
}
|
|
||||||
@ -18,7 +18,7 @@ const IGNORE_MATCHES = {
|
|||||||
'rxjs',
|
'rxjs',
|
||||||
],
|
],
|
||||||
cli: ['@nrwl/cli'],
|
cli: ['@nrwl/cli'],
|
||||||
cypress: ['cypress'],
|
cypress: ['cypress', '@angular-devkit/schematics', '@nrwl/cypress'],
|
||||||
devkit: ['@angular-devkit/architect', 'rxjs'],
|
devkit: ['@angular-devkit/architect', 'rxjs'],
|
||||||
gatsby: ['@angular-devkit/architect', 'babel-preset-gatsby', 'rxjs'],
|
gatsby: ['@angular-devkit/architect', 'babel-preset-gatsby', 'rxjs'],
|
||||||
jest: [
|
jest: [
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user