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": {
|
||||
"tags": [],
|
||||
"implicitDependencies": ["workspace"]
|
||||
"implicitDependencies": ["workspace", "linter"]
|
||||
},
|
||||
"jest": {
|
||||
"tags": [],
|
||||
|
||||
@ -60,10 +60,10 @@ Array [
|
||||
"/.storybook/main.js",
|
||||
"/.storybook/tsconfig.json",
|
||||
"/.storybook/webpack.config.js",
|
||||
"/apps/test-ui-lib-e2e/.eslintrc.json",
|
||||
"/apps/test-ui-lib-e2e/cypress.json",
|
||||
"/apps/test-ui-lib-e2e/tsconfig.e2e.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/plugins/index.js",
|
||||
"/apps/test-ui-lib-e2e/src/support/commands.ts",
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"rules": {},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.ts"],
|
||||
"excludedFiles": ["./src/migrations/**"],
|
||||
"rules": {
|
||||
"no-restricted-imports": ["error", "@nrwl/workspace"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": ["!**/*"]
|
||||
}
|
||||
|
||||
@ -3,15 +3,30 @@
|
||||
"version": "0.1",
|
||||
"schematics": {
|
||||
"init": {
|
||||
"factory": "./src/schematics/init/init",
|
||||
"schema": "./src/schematics/init/schema.json",
|
||||
"factory": "./src/generators/init/init#initSchematic",
|
||||
"schema": "./src/generators/init/schema.json",
|
||||
"description": "Initialize the @nrwl/cypress plugin",
|
||||
"aliases": ["ng-add"],
|
||||
"hidden": true
|
||||
},
|
||||
"cypress-project": {
|
||||
"factory": "./src/schematics/cypress-project/cypress-project",
|
||||
"schema": "./src/schematics/cypress-project/schema.json",
|
||||
"factory": "./src/generators/cypress-project/cypress-project#cypressProjectSchematic",
|
||||
"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",
|
||||
"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": {
|
||||
"@nrwl/devkit": "*",
|
||||
"@angular-devkit/architect": "~0.1100.1",
|
||||
"@angular-devkit/core": "~11.0.1",
|
||||
"@angular-devkit/schematics": "~11.0.1",
|
||||
"@nrwl/linter": "*",
|
||||
"@cypress/webpack-preprocessor": "~4.1.2",
|
||||
"tree-kill": "1.2.2",
|
||||
"ts-loader": "5.4.5",
|
||||
|
||||
@ -1,23 +1,26 @@
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import { runSchematic } from '../../utils/testing';
|
||||
import { readJsonInTree, Linter, NxJson } from '@nrwl/workspace';
|
||||
import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import { cypressProjectGenerator } from './cypress-project';
|
||||
import { Schema } from './schema';
|
||||
import { Linter } from '@nrwl/linter';
|
||||
|
||||
describe('schematic:cypress-project', () => {
|
||||
let appTree: Tree;
|
||||
let tree: Tree;
|
||||
const defaultOptions: Omit<Schema, 'name' | 'project'> = {
|
||||
linter: Linter.EsLint,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
appTree = Tree.empty();
|
||||
appTree = createEmptyWorkspace(appTree);
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
describe('Cypress Project', () => {
|
||||
it('should generate files', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app' },
|
||||
appTree
|
||||
);
|
||||
await cypressProjectGenerator(tree, {
|
||||
...defaultOptions,
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-app',
|
||||
});
|
||||
|
||||
expect(tree.exists('apps/my-app-e2e/cypress.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 () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.TsLint },
|
||||
appTree
|
||||
);
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
await cypressProjectGenerator(tree, {
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-app',
|
||||
linter: Linter.TsLint,
|
||||
});
|
||||
const workspaceJson = readJson(tree, 'workspace.json');
|
||||
const project = workspaceJson.projects['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 () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.EsLint },
|
||||
appTree
|
||||
);
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
await cypressProjectGenerator(tree, {
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-app',
|
||||
linter: Linter.EsLint,
|
||||
});
|
||||
const workspaceJson = readJson(tree, 'workspace.json');
|
||||
const project = workspaceJson.projects['my-app-e2e'];
|
||||
|
||||
expect(project.architect.lint).toEqual({
|
||||
@ -87,26 +90,24 @@ describe('schematic:cypress-project', () => {
|
||||
});
|
||||
|
||||
it('should update nx.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.EsLint },
|
||||
appTree
|
||||
);
|
||||
|
||||
const nxJson = readJsonInTree<NxJson>(tree, 'nx.json');
|
||||
expect(nxJson.projects['my-app-e2e']).toEqual({
|
||||
tags: [],
|
||||
implicitDependencies: ['my-app'],
|
||||
await cypressProjectGenerator(tree, {
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-app',
|
||||
linter: Linter.EsLint,
|
||||
});
|
||||
|
||||
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 () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app' },
|
||||
appTree
|
||||
);
|
||||
const cypressJson = readJsonInTree(tree, 'apps/my-app-e2e/cypress.json');
|
||||
await cypressProjectGenerator(tree, {
|
||||
...defaultOptions,
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-app',
|
||||
});
|
||||
const cypressJson = readJson(tree, 'apps/my-app-e2e/cypress.json');
|
||||
|
||||
expect(cypressJson).toEqual({
|
||||
fileServerFolder: '.',
|
||||
@ -123,15 +124,12 @@ describe('schematic:cypress-project', () => {
|
||||
});
|
||||
|
||||
it('should set right path names in `tsconfig.e2e.json`', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app' },
|
||||
appTree
|
||||
);
|
||||
const tsconfigJson = readJsonInTree(
|
||||
tree,
|
||||
'apps/my-app-e2e/tsconfig.e2e.json'
|
||||
);
|
||||
await cypressProjectGenerator(tree, {
|
||||
...defaultOptions,
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-app',
|
||||
});
|
||||
const tsconfigJson = readJson(tree, 'apps/my-app-e2e/tsconfig.e2e.json');
|
||||
|
||||
expect(tsconfigJson.extends).toEqual('./tsconfig.json');
|
||||
expect(tsconfigJson.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||
@ -139,17 +137,13 @@ describe('schematic:cypress-project', () => {
|
||||
|
||||
describe('nested', () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-dir-my-app',
|
||||
directory: 'my-dir',
|
||||
linter: Linter.TsLint,
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const projectConfig = readJsonInTree(tree, 'workspace.json').projects[
|
||||
await cypressProjectGenerator(tree, {
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-dir-my-app',
|
||||
directory: 'my-dir',
|
||||
linter: Linter.TsLint,
|
||||
});
|
||||
const projectConfig = readJson(tree, 'workspace.json').projects[
|
||||
'my-dir-my-app-e2e'
|
||||
];
|
||||
|
||||
@ -178,12 +172,13 @@ describe('schematic:cypress-project', () => {
|
||||
});
|
||||
|
||||
it('should set right path names in `cypress.json`', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-dir-my-app', directory: 'my-dir' },
|
||||
appTree
|
||||
);
|
||||
const cypressJson = readJsonInTree(
|
||||
await cypressProjectGenerator(tree, {
|
||||
...defaultOptions,
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-dir-my-app',
|
||||
directory: 'my-dir',
|
||||
});
|
||||
const cypressJson = readJson(
|
||||
tree,
|
||||
'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 () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-dir-my-app', directory: 'my-dir' },
|
||||
appTree
|
||||
);
|
||||
const tsconfigJson = readJsonInTree(
|
||||
await cypressProjectGenerator(tree, {
|
||||
...defaultOptions,
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-dir-my-app',
|
||||
directory: 'my-dir',
|
||||
});
|
||||
const tsconfigJson = readJson(
|
||||
tree,
|
||||
'apps/my-dir/my-app-e2e/tsconfig.e2e.json'
|
||||
);
|
||||
@ -223,13 +219,12 @@ describe('schematic:cypress-project', () => {
|
||||
describe('--project', () => {
|
||||
describe('none', () => {
|
||||
it('should not add any implicit dependencies', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e' },
|
||||
appTree
|
||||
);
|
||||
await cypressProjectGenerator(tree, {
|
||||
...defaultOptions,
|
||||
name: 'my-app-e2e',
|
||||
});
|
||||
|
||||
const nxJson = readJsonInTree(tree, 'nx.json');
|
||||
const nxJson = readJson(tree, 'nx.json');
|
||||
expect(nxJson.projects['my-app-e2e']).toEqual({ tags: [] });
|
||||
});
|
||||
});
|
||||
@ -238,16 +233,13 @@ describe('schematic:cypress-project', () => {
|
||||
describe('--linter', () => {
|
||||
describe('eslint', () => {
|
||||
it('should add eslint-plugin-cypress', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app', linter: Linter.EsLint },
|
||||
appTree
|
||||
);
|
||||
const packageJson = readJsonInTree(tree, 'package.json');
|
||||
const eslintrcJson = readJsonInTree(
|
||||
tree,
|
||||
'apps/my-app-e2e/.eslintrc.json'
|
||||
);
|
||||
await cypressProjectGenerator(tree, {
|
||||
name: 'my-app-e2e',
|
||||
project: 'my-app',
|
||||
linter: Linter.EsLint,
|
||||
});
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
const eslintrcJson = readJson(tree, 'apps/my-app-e2e/.eslintrc.json');
|
||||
|
||||
expect(
|
||||
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",
|
||||
"id": "Nx Cypress Project Generator Schema",
|
||||
"cli": "nx",
|
||||
"title": "Create Cypress Configuration for the workspace",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -34,6 +35,11 @@
|
||||
"description": "Generate JavaScript files rather than TypeScript files",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"id": "NxCypressInit",
|
||||
"cli": "nx",
|
||||
"title": "Add Cypress Configuration to the workspace",
|
||||
"type": "object",
|
||||
"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',
|
||||
],
|
||||
cli: ['@nrwl/cli'],
|
||||
cypress: ['cypress'],
|
||||
cypress: ['cypress', '@angular-devkit/schematics', '@nrwl/cypress'],
|
||||
devkit: ['@angular-devkit/architect', 'rxjs'],
|
||||
gatsby: ['@angular-devkit/architect', 'babel-preset-gatsby', 'rxjs'],
|
||||
jest: [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user