Skip to content

Commit

Permalink
feat(cypress/schematic): add support for component testing (#23385)
Browse files Browse the repository at this point in the history
Co-authored-by: Jordan <jordan@jpdesigning.com>
  • Loading branch information
admah and jordanpowell88 committed Aug 25, 2022
1 parent bd0d38f commit 99562af
Show file tree
Hide file tree
Showing 33 changed files with 594 additions and 114 deletions.
102 changes: 88 additions & 14 deletions npm/cypress-schematic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,36 @@

✅ Install Cypress

✅ Add npm scripts for running Cypress in `run` mode and `open` mode
✅ Add npm scripts for running Cypress e2e tests in `run` mode and `open` mode

✅ Scaffold base Cypress files and directories

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

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

✅ Optional: prompt you to add a `ng ct` command to use Cypress component testing.

## Requirements

- Angular 12+
- Angular 13+

## Usage ⏯

Install the schematic:
### Adding E2E and Component Testing

To install the schematic via prompts:

```shell
ng add @cypress/schematic
```

To install the schematic via cli arguments (installs both e2e and component testing):

```shell
ng add @cypress/schematic --e2e --component
```

To run Cypress in `open` mode within your project:

```shell script
Expand All @@ -57,11 +67,49 @@ 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:
If you have chosen to add Cypress component testing, you can run component tests in `open` mode using this:

```shell script
ng run {project-name}:ct
```

### Generating New Cypress Spec Files

To generate a new e2e spec file:

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

or (without cli prompt)

```shell script
ng generate @cypress/schematic:spec {name}
```

To generate a new component spec file:

```shell script
ng generate @cypress/schematic:spec --component
```

or (without cli prompt)

```shell script
ng generate @cypress/schematic:spec {component name} --component
```

To generate a new component spec file in a specific folder:

```shell script
ng generate @cypress/schematic:spec {component name} --component --path {path relative to project root}
```

To generate new component spec files alongside all component files in a project:

```shell script
ng generate @cypress/schematic:e2e
```
ng generate @cypress/schematic:specs-ct
```

## Builder Options 🛠

Expand Down Expand Up @@ -109,7 +157,7 @@ We recommend setting your [Cypress Dashboard](https://on.cypress.io/features-das

Read our docs to learn more about [recording test results](https://on.cypress.io/recording-project-runs) to the [Cypress Dashboard](https://on.cypress.io/features-dashboard).

### Specifying a custom `cypress.json` config file
### Specifying a custom config file

It may be useful to have different Cypress configuration files per environment (ie. development, staging, production).

Expand Down Expand Up @@ -223,12 +271,22 @@ In order to prevent the application from building, add the following to the end

## Generator Options

### Specify Testing Type

The default generated spec is E2E. In order to generate a component test you can run:

```shell script
ng generate @cypress/schematic:spec --name=button -t component
```

`-t` is an alias for `testing-type`. It accepts `e2e` or `component` as arguments. If you are using the CLI tool, a prompt will appear asking which spec type you want to generate.

### Specify Filename (bypassing CLI prompt)

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

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

This will create a new spec file named `login.cy.ts` in the default Cypress folder location.
Expand All @@ -238,17 +296,33 @@ This will create a new spec file named `login.cy.ts` in the default Cypress fold
Add a `--project=` flag to specify the project:

```shell script
ng generate @cypress/schematic:e2e --name=login --project=sandbox
ng generate @cypress/schematic:spec --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
ng generate @cypress/schematic:spec --name=login --path=src/app/tests
```

This will create a spec file in your specific location, creating folders as needed. By default, new specs are created in either `cypress/e2e` for E2E specs or `cypress/ct` for component specs.

### Generate Tests for All Components

You can scaffold component test specs alongside all your components in the default project by using:

```shell script
ng generate @cypress/schematic:specs-ct -g
```

This will create the e2e spec file in your specific location, creating folders as needed.
This will identify files ending in `component.ts`. It will then create spec files alongside them - if they don't exist.

If you would like to specify a project, you can use the command:

```shell script
ng generate @cypress/schematic:specs-ct -g -p {project-name}
```

## Migrating from Protractor to Cypress?

Expand Down
4 changes: 2 additions & 2 deletions npm/cypress-schematic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
"typescript": "^4.7.4"
},
"peerDependencies": {
"@angular/cli": ">=14.1.0",
"@angular/core": ">=14.1.0"
"@angular/cli": ">=12",
"@angular/core": ">=12"
},
"license": "MIT",
"repository": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface CypressBuilderOptions extends JsonObject {
browser: 'electron' | 'chrome' | 'chromium' | 'canary' | 'firefox' | 'edge' | string
devServerTarget: string
e2e: boolean
component: boolean
env: Record<string, string>
quiet: boolean
exit: boolean
Expand All @@ -20,4 +21,5 @@ export interface CypressBuilderOptions extends JsonObject {
spec: string
tsConfig: string
watch: boolean
testingType: 'e2e' | 'component'
}
4 changes: 4 additions & 0 deletions npm/cypress-schematic/src/builders/cypress/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ function initCypress (userOptions: CypressBuilderOptions): Observable<BuilderOut
spec: '',
}

if (userOptions.component || userOptions.testingType === 'component') {
userOptions.e2e = false
}

const options: CypressOptions = {
...defaultOptions,
...userOptions,
Expand Down
12 changes: 12 additions & 0 deletions npm/cypress-schematic/src/builders/cypress/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
"description": "Run end to end tests",
"default": true
},
"component": {
"type": "boolean",
"description": "Run component tests",
"default": false
},
"env": {
"type": "object",
"description": "A key-value pair of environment variables to pass to Cypress runner"
Expand Down Expand Up @@ -87,6 +92,13 @@
"type": "boolean",
"description": "Recompile and run tests when files change.",
"default": false
},
"testingType": {
"enum": [
"e2e",
"component"
],
"description": "Specify the type of tests to execute; either e2e or component. Defaults to e2e."
}
},
"additionalProperties": true
Expand Down
41 changes: 41 additions & 0 deletions npm/cypress-schematic/src/ct.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Fixtures, { ProjectFixtureDir } from '@tooling/system-tests'
import * as FixturesScaffold from '@tooling/system-tests/lib/dep-installer'
import execa from 'execa'
import path from 'path'
import * as fs from 'fs-extra'

const scaffoldAngularProject = async (project: string) => {
const projectPath = Fixtures.projectPath(project)

Fixtures.removeProject(project)
await Fixtures.scaffoldProject(project)
await FixturesScaffold.scaffoldProjectNodeModules(project)
await fs.remove(path.join(projectPath, 'cypress.config.ts'))
await fs.remove(path.join(projectPath, 'cypress'))

return projectPath
}

const runCommandInProject = (command: string, projectPath: string) => {
const [ex, ...args] = command.split(' ')

return execa(ex, args, { cwd: projectPath, stdio: 'inherit' })
}

const cypressSchematicPackagePath = path.join(__dirname, '..')

const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-13', 'angular-14']

describe('ng add @cypress/schematic / e2e and ct', function () {
this.timeout(1000 * 60 * 4)

for (const project of ANGULAR_PROJECTS) {
it('should install ct files with option and no component specs', async () => {
const projectPath = await scaffoldAngularProject(project)

await runCommandInProject(`yarn add @cypress/schematic@file:${cypressSchematicPackagePath}`, projectPath)
await runCommandInProject('yarn ng add @cypress/schematic --e2e --component', projectPath)
await runCommandInProject('yarn ng run angular:ct --watch false --spec src/app/app.component.cy.ts', projectPath)
})
}
})
8 changes: 4 additions & 4 deletions npm/cypress-schematic/src/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ const cypressSchematicPackagePath = path.join(__dirname, '..')

const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-13', 'angular-14']

describe('cypress-schematic-e2e', function () {
describe('ng add @cypress/schematic / only e2e', function () {
this.timeout(1000 * 60 * 4)

for (const project of ANGULAR_PROJECTS) {
it('should', async () => {
it('should install e2e files by default', async () => {
const projectPath = await scaffoldAngularProject(project)

await runCommandInProject(`yarn add @cypress/schematic@file:${cypressSchematicPackagePath}`, projectPath)
await runCommandInProject('yarn ng add @cypress/schematic --e2eUpdate', projectPath)
await runCommandInProject('yarn ng e2e angular --watch false', projectPath)
await runCommandInProject('yarn ng add @cypress/schematic --e2e --component false --add-ct-specs false', projectPath)
await runCommandInProject('yarn ng e2e --watch false', projectPath)
})
}
})
16 changes: 9 additions & 7 deletions npm/cypress-schematic/src/schematics/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
"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"
]
"spec": {
"description": "Create a single spec file",
"factory": "./ng-generate/cypress-test/index",
"schema": "./ng-generate/cypress-test/schema.json"
},
"specs-ct": {
"description": "Create spec files for all Angular components in a project",
"factory": "./ng-generate/cypress-ct-tests/index",
"schema": "./ng-generate/cypress-ct-tests/schema.json"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defineConfig } from 'cypress'

export default defineConfig({
<% if (e2e) { %>
e2e: {
'baseUrl': '<%= baseUrl%>',
supportFile: false
},
<% } %>
<% if (component) { %>
component: {
devServer: {
framework: 'angular',
bundler: 'webpack',
},
specPattern: '**/*.cy.ts'
}
<% } %>
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ***********************************************************
// This example support/component.ts is processed and
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": "<%= relativeToWorkspace %>/tsconfig.json",
"extends": "../tsconfig.json",
"include": ["**/*.ts"],
"compilerOptions": {
"sourceMap": false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Components App</title>
</head>
<body>
<div data-cy-root></div>
</body>
</html>

0 comments on commit 99562af

Please sign in to comment.