Skip to content

Commit 99562af

Browse files
feat(cypress/schematic): add support for component testing (cypress-io#23385)
Co-authored-by: Jordan <jordan@jpdesigning.com>
1 parent bd0d38f commit 99562af

33 files changed

+594
-114
lines changed

npm/cypress-schematic/README.md

+88-14
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,36 @@
1919

2020
✅ Install Cypress
2121

22-
✅ Add npm scripts for running Cypress in `run` mode and `open` mode
22+
✅ Add npm scripts for running Cypress e2e tests in `run` mode and `open` mode
2323

2424
✅ Scaffold base Cypress files and directories
2525

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

28-
✅ Optional: prompt you to add or update the default `ng e2e` command to use Cypress.
28+
✅ Optional: prompt you to add or update the default `ng e2e` command to use Cypress for e2e tests.
29+
30+
✅ Optional: prompt you to add a `ng ct` command to use Cypress component testing.
2931

3032
## Requirements
3133

32-
- Angular 12+
34+
- Angular 13+
3335

3436
## Usage ⏯
3537

36-
Install the schematic:
38+
### Adding E2E and Component Testing
39+
40+
To install the schematic via prompts:
3741

3842
```shell
3943
ng add @cypress/schematic
4044
```
4145

46+
To install the schematic via cli arguments (installs both e2e and component testing):
47+
48+
```shell
49+
ng add @cypress/schematic --e2e --component
50+
```
51+
4252
To run Cypress in `open` mode within your project:
4353

4454
```shell script
@@ -57,11 +67,49 @@ If you have chosen to add or update the `ng e2e` command, you can also run Cypre
5767
ng e2e
5868
```
5969

60-
To generate new e2e spec files:
70+
If you have chosen to add Cypress component testing, you can run component tests in `open` mode using this:
71+
72+
```shell script
73+
ng run {project-name}:ct
74+
```
75+
76+
### Generating New Cypress Spec Files
77+
78+
To generate a new e2e spec file:
79+
80+
```shell script
81+
ng generate @cypress/schematic:spec
82+
```
83+
84+
or (without cli prompt)
85+
86+
```shell script
87+
ng generate @cypress/schematic:spec {name}
88+
```
89+
90+
To generate a new component spec file:
91+
92+
```shell script
93+
ng generate @cypress/schematic:spec --component
94+
```
95+
96+
or (without cli prompt)
97+
98+
```shell script
99+
ng generate @cypress/schematic:spec {component name} --component
100+
```
101+
102+
To generate a new component spec file in a specific folder:
103+
104+
```shell script
105+
ng generate @cypress/schematic:spec {component name} --component --path {path relative to project root}
106+
```
107+
108+
To generate new component spec files alongside all component files in a project:
61109

62110
```shell script
63-
ng generate @cypress/schematic:e2e
64-
```
111+
ng generate @cypress/schematic:specs-ct
112+
```
65113

66114
## Builder Options 🛠
67115

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

110158
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).
111159

112-
### Specifying a custom `cypress.json` config file
160+
### Specifying a custom config file
113161

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

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

224272
## Generator Options
225273

274+
### Specify Testing Type
275+
276+
The default generated spec is E2E. In order to generate a component test you can run:
277+
278+
```shell script
279+
ng generate @cypress/schematic:spec --name=button -t component
280+
```
281+
282+
`-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.
283+
226284
### Specify Filename (bypassing CLI prompt)
227285

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

230288
```shell script
231-
ng generate @cypress/schematic:e2e --name=login
289+
ng generate @cypress/schematic:spec --name=login
232290
```
233291

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

240298
```shell script
241-
ng generate @cypress/schematic:e2e --name=login --project=sandbox
299+
ng generate @cypress/schematic:spec --name=login --project=sandbox
242300
```
243301
### Specify Path
244302

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

247305
```shell script
248-
ng generate @cypress/schematic:e2e --name=login --path=src/app/tests
306+
ng generate @cypress/schematic:spec --name=login --path=src/app/tests
307+
```
308+
309+
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.
310+
311+
### Generate Tests for All Components
312+
313+
You can scaffold component test specs alongside all your components in the default project by using:
314+
315+
```shell script
316+
ng generate @cypress/schematic:specs-ct -g
249317
```
250318

251-
This will create the e2e spec file in your specific location, creating folders as needed.
319+
This will identify files ending in `component.ts`. It will then create spec files alongside them - if they don't exist.
320+
321+
If you would like to specify a project, you can use the command:
322+
323+
```shell script
324+
ng generate @cypress/schematic:specs-ct -g -p {project-name}
325+
```
252326

253327
## Migrating from Protractor to Cypress?
254328

npm/cypress-schematic/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
"typescript": "^4.7.4"
2828
},
2929
"peerDependencies": {
30-
"@angular/cli": ">=14.1.0",
31-
"@angular/core": ">=14.1.0"
30+
"@angular/cli": ">=12",
31+
"@angular/core": ">=12"
3232
},
3333
"license": "MIT",
3434
"repository": {

npm/cypress-schematic/src/builders/cypress/cypressBuilderOptions.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface CypressBuilderOptions extends JsonObject {
66
browser: 'electron' | 'chrome' | 'chromium' | 'canary' | 'firefox' | 'edge' | string
77
devServerTarget: string
88
e2e: boolean
9+
component: boolean
910
env: Record<string, string>
1011
quiet: boolean
1112
exit: boolean
@@ -20,4 +21,5 @@ export interface CypressBuilderOptions extends JsonObject {
2021
spec: string
2122
tsConfig: string
2223
watch: boolean
24+
testingType: 'e2e' | 'component'
2325
}

npm/cypress-schematic/src/builders/cypress/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ function initCypress (userOptions: CypressBuilderOptions): Observable<BuilderOut
7575
spec: '',
7676
}
7777

78+
if (userOptions.component || userOptions.testingType === 'component') {
79+
userOptions.e2e = false
80+
}
81+
7882
const options: CypressOptions = {
7983
...defaultOptions,
8084
...userOptions,

npm/cypress-schematic/src/builders/cypress/schema.json

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
"description": "Run end to end tests",
4040
"default": true
4141
},
42+
"component": {
43+
"type": "boolean",
44+
"description": "Run component tests",
45+
"default": false
46+
},
4247
"env": {
4348
"type": "object",
4449
"description": "A key-value pair of environment variables to pass to Cypress runner"
@@ -87,6 +92,13 @@
8792
"type": "boolean",
8893
"description": "Recompile and run tests when files change.",
8994
"default": false
95+
},
96+
"testingType": {
97+
"enum": [
98+
"e2e",
99+
"component"
100+
],
101+
"description": "Specify the type of tests to execute; either e2e or component. Defaults to e2e."
90102
}
91103
},
92104
"additionalProperties": true

npm/cypress-schematic/src/ct.spec.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import Fixtures, { ProjectFixtureDir } from '@tooling/system-tests'
2+
import * as FixturesScaffold from '@tooling/system-tests/lib/dep-installer'
3+
import execa from 'execa'
4+
import path from 'path'
5+
import * as fs from 'fs-extra'
6+
7+
const scaffoldAngularProject = async (project: string) => {
8+
const projectPath = Fixtures.projectPath(project)
9+
10+
Fixtures.removeProject(project)
11+
await Fixtures.scaffoldProject(project)
12+
await FixturesScaffold.scaffoldProjectNodeModules(project)
13+
await fs.remove(path.join(projectPath, 'cypress.config.ts'))
14+
await fs.remove(path.join(projectPath, 'cypress'))
15+
16+
return projectPath
17+
}
18+
19+
const runCommandInProject = (command: string, projectPath: string) => {
20+
const [ex, ...args] = command.split(' ')
21+
22+
return execa(ex, args, { cwd: projectPath, stdio: 'inherit' })
23+
}
24+
25+
const cypressSchematicPackagePath = path.join(__dirname, '..')
26+
27+
const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-13', 'angular-14']
28+
29+
describe('ng add @cypress/schematic / e2e and ct', function () {
30+
this.timeout(1000 * 60 * 4)
31+
32+
for (const project of ANGULAR_PROJECTS) {
33+
it('should install ct files with option and no component specs', async () => {
34+
const projectPath = await scaffoldAngularProject(project)
35+
36+
await runCommandInProject(`yarn add @cypress/schematic@file:${cypressSchematicPackagePath}`, projectPath)
37+
await runCommandInProject('yarn ng add @cypress/schematic --e2e --component', projectPath)
38+
await runCommandInProject('yarn ng run angular:ct --watch false --spec src/app/app.component.cy.ts', projectPath)
39+
})
40+
}
41+
})

npm/cypress-schematic/src/e2e.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ const cypressSchematicPackagePath = path.join(__dirname, '..')
2626

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

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

3232
for (const project of ANGULAR_PROJECTS) {
33-
it('should', async () => {
33+
it('should install e2e files by default', async () => {
3434
const projectPath = await scaffoldAngularProject(project)
3535

3636
await runCommandInProject(`yarn add @cypress/schematic@file:${cypressSchematicPackagePath}`, projectPath)
37-
await runCommandInProject('yarn ng add @cypress/schematic --e2eUpdate', projectPath)
38-
await runCommandInProject('yarn ng e2e angular --watch false', projectPath)
37+
await runCommandInProject('yarn ng add @cypress/schematic --e2e --component false --add-ct-specs false', projectPath)
38+
await runCommandInProject('yarn ng e2e --watch false', projectPath)
3939
})
4040
}
4141
})

npm/cypress-schematic/src/schematics/collection.json

+9-7
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
"factory": "./ng-add/index",
77
"schema": "./ng-add/schema.json"
88
},
9-
"e2e": {
10-
"description": "Create an e2e spec file",
11-
"factory": "./ng-generate/e2e/index",
12-
"schema": "./ng-generate/e2e/schema.json",
13-
"aliases": [
14-
"e2e-spec"
15-
]
9+
"spec": {
10+
"description": "Create a single spec file",
11+
"factory": "./ng-generate/cypress-test/index",
12+
"schema": "./ng-generate/cypress-test/schema.json"
13+
},
14+
"specs-ct": {
15+
"description": "Create spec files for all Angular components in a project",
16+
"factory": "./ng-generate/cypress-ct-tests/index",
17+
"schema": "./ng-generate/cypress-ct-tests/schema.json"
1618
}
1719
}
1820
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { defineConfig } from 'cypress'
2+
3+
export default defineConfig({
4+
<% if (e2e) { %>
5+
e2e: {
6+
'baseUrl': '<%= baseUrl%>',
7+
supportFile: false
8+
},
9+
<% } %>
10+
<% if (component) { %>
11+
component: {
12+
devServer: {
13+
framework: 'angular',
14+
bundler: 'webpack',
15+
},
16+
specPattern: '**/*.cy.ts'
17+
}
18+
<% } %>
19+
})

npm/cypress-schematic/src/schematics/ng-add/files/cypress/support/e2e.ts npm/cypress-schematic/src/schematics/ng-add/files-core/cypress/support/e2e.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// ***********************************************************
2-
// This example support/component.ts is processed and
2+
// This example support/e2e.ts is processed and
33
// loaded automatically before your test files.
44
//
55
// This is a great place to put global configuration and

npm/cypress-schematic/src/schematics/ng-add/files/cypress/tsconfig.json npm/cypress-schematic/src/schematics/ng-add/files-core/cypress/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"extends": "<%= relativeToWorkspace %>/tsconfig.json",
2+
"extends": "../tsconfig.json",
33
"include": ["**/*.ts"],
44
"compilerOptions": {
55
"sourceMap": false,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
7+
<title>Components App</title>
8+
</head>
9+
<body>
10+
<div data-cy-root></div>
11+
</body>
12+
</html>

0 commit comments

Comments
 (0)