Skip to content

Commit

Permalink
feat: add ng generate to @cypress/schematic to generate e2e spec files (
Browse files Browse the repository at this point in the history
  • Loading branch information
admah committed Jun 25, 2021
1 parent b2bf4cf commit 96a9db4
Show file tree
Hide file tree
Showing 27 changed files with 223 additions and 34 deletions.
4 changes: 2 additions & 2 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1449,8 +1449,8 @@ jobs:
command: yarn launch:test
working_directory: npm/cypress-schematic
- run:
name: Test Schematics
command: yarn test:schematics
name: Run unit tests
command: yarn test
working_directory: npm/cypress-schematic
- store-npm-logs

Expand Down
1 change: 0 additions & 1 deletion npm/cypress-schematic/.releaserc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ module.exports = {
...require('../../.releaserc.base'),
branches: [
{ name: 'master', channel: 'latest' },
{ name: 'next/npm/cypress-schematic', channel: 'next', prerelease: 'alpha' },
],
}
38 changes: 38 additions & 0 deletions npm/cypress-schematic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

✅ Scaffold base Cypress files and directories

✅ Provide the ability to add new e2e files easily using `ng-generate`

✅ Optional: prompt you to add or update the default `ng e2e` command to use Cypress.

## Usage ⏯
Expand Down Expand Up @@ -50,6 +52,12 @@ If you have chosen to add or update the `ng e2e` command, you can also run Cypre
ng e2e
```

To generate new e2e spec files:

```shell script
ng generate @cypress/schematic:e2e
```

## Builder Options 🛠

### Running the builder with a specific browser
Expand Down Expand Up @@ -138,6 +146,36 @@ Read our docs to learn more about all the [configuration options](https://on.cyp

Read our docs to learn more about speeding up test execution in CI via [Cypress parallelization](https://on.cypress.io/parallelization)

## Generator Options

### Specify Filename (bypassing CLI prompt)

In order to bypass the prompt asking for your e2e spec name, simply add a `--name=` flag like this:

```shell script
ng generate @cypress/schematic:e2e --name=login
```

This will create a new spec file named `login.spec.ts` in the default Cypress folder location.


### Specify Project

Add a `--project=` flag to specify the project:

```shell script
ng generate @cypress/schematic:e2e --name=login --project=sandbox
```
### Specify Path

Add a `--path=` flag to specify the project:

```shell script
ng generate @cypress/schematic:e2e --name=login --path=src/app/tests
```

This will create the e2e spec file in your specific location, creating folders as needed.

## Migrating from Protractor to Cypress?

Read our [migration guide](https://on.cypress.io/protractor-to-cypress) to help you make the transition from Protractor to Cypress.
Expand Down
6 changes: 2 additions & 4 deletions npm/cypress-schematic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@
"build:watch": "tsc -p tsconfig.json --watch",
"clean": "git checkout HEAD -- sandbox && git clean -f -d sandbox",
"launch": "yarn link:sandbox && cd sandbox && ng add @cypress/schematic && cd ..",
"launch:test": "yarn link:sandbox && cd sandbox && ng add @cypress/schematic && cd ..",
"launch:test": "yarn link:sandbox && cd sandbox && ng add @cypress/schematic --e2eUpdate=true && cd ..",
"link:sandbox": "yarn link && cd sandbox && yarn link @cypress/schematic",
"test:all": "yarn build:all && yarn test:schematics && yarn launch:test && yarn test:builders",
"test:builders": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/builders/cypress/index_spec.ts",
"test:schematics": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/schematics/cypress/index_spec.ts",
"test": "mocha -r @packages/ts/register --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json src/**/*.spec.ts",
"test:e2e:sandbox": "cd sandbox && ng run sandbox:cypress-run",
"unlink:sandbox": "cd sandbox && yarn unlink @cypress/schematic && cd .. && yarn unlink"
},
Expand Down
2 changes: 1 addition & 1 deletion npm/cypress-schematic/src/builders/cypress/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { dirname, join } from 'path'
import { open, run } from 'cypress'
import { from, noop, Observable, of } from 'rxjs'
import { catchError, concatMap, first, map, switchMap, tap } from 'rxjs/operators'
import { CypressBuilderOptions } from './cypress-builder-options'
import { CypressBuilderOptions } from './cypressBuilderOptions'

type CypressOptions = Partial<CypressCommandLine.CypressRunOptions> &
Partial<CypressCommandLine.CypressOpenOptions>;
Expand Down
12 changes: 10 additions & 2 deletions npm/cypress-schematic/src/schematics/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@
"schematics": {
"ng-add": {
"description": "Adds Cypress to an Angular project.",
"factory": "./cypress/index",
"schema": "./cypress/schema.json"
"factory": "./ng-add/index",
"schema": "./ng-add/schema.json"
},
"e2e": {
"description": "Create an e2e spec file",
"factory": "./ng-generate/e2e/index",
"schema": "./ng-generate/e2e/schema.json",
"aliases": [
"e2e-spec"
]
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Plugins enable you to tap into, modify, or extend the internal behavior of Cypress
// For more info, visit https://on.cypress.io/plugins-api
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('@cypress/schematic: ng-add', () => {
})

it('should create cypress files', async () => {
const files = ['cypress/integration/spec.ts', 'cypress/plugins/index.js', 'cypress/support/commands.ts', 'cypress/support/index.ts', 'cypress/tsconfig.json', 'cypress.json']
const files = ['cypress/integration/spec.ts', 'cypress/plugins/index.ts', 'cypress/support/commands.ts', 'cypress/support/index.ts', 'cypress/tsconfig.json', 'cypress.json']
const homePath = '/projects/sandbox/'

return schematicRunner.runSchematicAsync('ng-add', {}, appTree).toPromise().then((tree) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
NodePackage,
} from '../utility'
import { relative, resolve } from 'path'
import { JSONFile, JSONPath } from '../utility/json-file'
import { JSONFile, JSONPath } from '../utility/jsonFile'

export default function (_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "cypress-schematic",
"title": "Cypress ng-add schematic",
"title": "Cypress Install Schema",
"type": "object",
"properties": {
"e2eUpdate": {
"type": "boolean",
"default": true,
"description": "When true, `ng e2e` will be added or updated to use Cypress",
"x-prompt": "Would you like the default `ng e2e` command to use Cypress? [ Protractor to Cypress Migration Guide: https://on.cypress.io/protractor-to-cypress ]"
"x-prompt": "Would you like the default `ng e2e` command to use Cypress? [ Protractor to Cypress Migration Guide: https://on.cypress.io/protractor-to-cypress?cli=true ]"
}
},
"required": []
Expand Down
43 changes: 43 additions & 0 deletions npm/cypress-schematic/src/schematics/ng-generate/e2e/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'
import { join, resolve } from 'path'
import { expect } from 'chai'

describe('@cypress/schematic:e2e ng-generate', () => {
const schematicRunner = new SchematicTestRunner(
'schematics',
join(__dirname, '../../collection.json'),
)
let appTree: UnitTestTree

const workspaceOptions = {
name: 'workspace',
newProjectRoot: 'projects',
version: '12.0.0',
}

const appOptions = {
name: 'sandbox',
inlineTemplate: false,
routing: false,
skipTests: false,
skipPackageJson: false,
}

beforeEach(async () => {
appTree = await schematicRunner.runExternalSchematicAsync('@schematics/angular', 'workspace', workspaceOptions).toPromise()
appTree = await schematicRunner.runExternalSchematicAsync('@schematics/angular', 'application', appOptions, appTree).toPromise()
})

it('should create cypress files', async () => {
const files = ['cypress/integration/foo.spec.ts']
const homePath = '/projects/sandbox/'

return schematicRunner.runSchematicAsync('e2e', { name: 'foo' }, appTree).toPromise().then((tree) => {
files.forEach((f) => {
const pathToFile = resolve(homePath, f)

expect(tree.exists(pathToFile), pathToFile).equal(true)
})
})
})
})
68 changes: 68 additions & 0 deletions npm/cypress-schematic/src/schematics/ng-generate/e2e/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
Rule, Tree, SchematicsException,
apply, url, applyTemplates, move,
chain, mergeWith,
} from '@angular-devkit/schematics'

import { strings, normalize, virtualFs, workspaces } from '@angular-devkit/core'

import { Schema } from './schema'

function createSpec (tree: Tree): workspaces.WorkspaceHost {
return {
async readFile (path: string): Promise<string> {
const data = tree.read(path)

if (!data) {
throw new SchematicsException('File not found.')
}

return virtualFs.fileBufferToString(data)
},
async writeFile (path: string, data: string): Promise<void> {
return tree.overwrite(path, data)
},
async isDirectory (path: string): Promise<boolean> {
return !tree.exists(path) && tree.getDir(path).subfiles.length > 0
},
async isFile (path: string): Promise<boolean> {
return tree.exists(path)
},
}
}

export default function (options: Schema): Rule {
return async (tree: Tree) => {
const host = createSpec(tree)
const { workspace } = await workspaces.readWorkspace('/', host)

if (!options.project) {
// @ts-ignore
options.project = workspace.extensions.defaultProject
}

//@ts-ignore
const project = workspace.projects.get(options.project)

if (!project) {
throw new SchematicsException(`Invalid project name: ${options.project}`)
}

if (options.path === undefined) {
options.path = `${project.root}/cypress/integration`
}

const templateSource = apply(url('../files/__path__'), [
applyTemplates({
classify: strings.classify,
dasherize: strings.dasherize,
name: options.name,
}),
move(normalize(options.path as string)),
])

return chain([
mergeWith(templateSource),
])
}
}
33 changes: 33 additions & 0 deletions npm/cypress-schematic/src/schematics/ng-generate/e2e/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "cypress-schematics-e2e-spec",
"title": "Cypress E2E Spec Options Schema",
"type": "object",
"properties": {
"path": {
"type": "string",
"format": "path",
"description": "The path to create the component.",
"visible": false
},
"project": {
"type": "string",
"description": "The name of the project.",
"$default": {
"$source": "projectName"
}
},
"name": {
"type": "string",
"description": "The name of the e2e test.",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "What is the name of the e2e test?"
}
},
"required": [
"name"
]
}
10 changes: 10 additions & 0 deletions npm/cypress-schematic/src/schematics/ng-generate/e2e/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface Schema {
// The name of the spec.
name: string

// The path to create the spec.
path?: string

// The name of the project.
project?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
describe('<%= classify(name) %>', () => {
it('', () => {
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import { Tree } from '@angular-devkit/schematics'
import { JSONFile } from './json-file'
import { JSONFile } from './jsonFile'

const PKG_JSON_PATH = '/package.json'

Expand Down
19 changes: 3 additions & 16 deletions npm/cypress-schematic/src/schematics/utility/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,9 @@ import { get } from 'http'
import { getPackageJsonDependency } from './dependencies'

export interface NodePackage {
name: string
version: string
}

export enum Paths {
AngularJson = './angular.json',
}

export enum Configs {
JsonIndentLevel = 4,
}

export interface CypressOptions {
project?: string
__version__: number
}
name: string
version: string
}

export function getAngularVersion (tree: Tree): number {
const packageNode = getPackageJsonDependency(tree, '@angular/core')
Expand Down
2 changes: 1 addition & 1 deletion npm/cypress-schematic/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@
"include": [
"src/**/*"
],
"exclude": ["src/**/files/**/*", "src/**/*_spec.ts"]
"exclude": ["src/**/files/**/*", "src/**/*.spec.ts"]
}
2 changes: 1 addition & 1 deletion npm/cypress-schematic/tsconfig.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
]
},
"include": [
"src/**/*_spec.ts"
"src/**/*.spec.ts"
],
"exclude": [
"src/**/files/**/*"
Expand Down

0 comments on commit 96a9db4

Please sign in to comment.