Skip to content

Commit b3e5b6a

Browse files
committed
WIP: support angular 21 inside cypress schematic
1 parent b6e60fd commit b3e5b6a

File tree

10 files changed

+102
-18
lines changed

10 files changed

+102
-18
lines changed

npm/cypress-schematic/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
},
1212
"dependencies": {
1313
"jsonc-parser": "^3.3.1",
14-
"rxjs": "~7.8.2"
14+
"rxjs": "~7.8.2",
15+
"semver": "^7.7.3"
1516
},
1617
"devDependencies": {
1718
"@angular-devkit/architect": "^0.2001.6",

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@ const runCommandInProject = (command: string, projectPath: string) => {
1515
// @cypress/angular won't exist in the tmp project. To fix this, we replace the
1616
// contents of the <project-path>/node_modules/cypress/angular with the latest
1717
// contents of cli/angular
18-
const copyAngularMount = async (projectPath: string) => {
19-
await fs.copy(
20-
path.join(__dirname, '..', '..', '..', 'cli', 'angular'),
21-
path.join(projectPath, 'node_modules', 'cypress', 'angular'),
22-
)
18+
const copyAngularMount = async (projectPath: string, copyZonelessMount: boolean = false) => {
19+
if (copyZonelessMount) {
20+
await fs.copy(
21+
path.join(__dirname, '..', '..', '..', 'cli', 'angular-zoneless'),
22+
path.join(projectPath, 'node_modules', 'cypress', 'angular-zoneless'),
23+
)
24+
} else {
25+
await fs.copy(
26+
path.join(__dirname, '..', '..', '..', 'cli', 'angular'),
27+
path.join(projectPath, 'node_modules', 'cypress', 'angular'),
28+
)
29+
}
2330
}
2431

2532
const cypressSchematicPackagePath = path.join(__dirname, '..')
@@ -54,8 +61,16 @@ describe('ng add @cypress/schematic / e2e and ct', function () {
5461

5562
it('should generate component alongside component spec', async () => {
5663
await runCommandInProject('yarn ng add @cypress/schematic --e2e --component', projectPath)
57-
await copyAngularMount(projectPath)
58-
await runCommandInProject('yarn ng generate c foo', projectPath)
64+
// make sure to copy the zoneless mount function for angular 21+
65+
await copyAngularMount(projectPath, true)
66+
if (project === 'angular-21') {
67+
// our angular 21 project is a pure standalone project, so we need to pass in the --standalone flag to ignore module generation.
68+
// this may be no longer true if we update the schematic dependencies
69+
await runCommandInProject('yarn ng generate c foo --standalone', projectPath)
70+
} else {
71+
await runCommandInProject('yarn ng generate c foo ', projectPath)
72+
}
73+
5974
await runCommandInProject('yarn ng run angular:ct --watch false --spec src/app/foo/foo.component.cy.ts', projectPath)
6075
}, timeout)
6176
})
Lines changed: 12 additions & 0 deletions
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>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// ***********************************************************
2+
// This example support/component.ts is processed and
3+
// loaded automatically before your test files.
4+
//
5+
// This is a great place to put global configuration and
6+
// behavior that modifies Cypress.
7+
//
8+
// You can change the location of this file or turn off
9+
// automatically serving support files with the
10+
// 'supportFile' configuration option.
11+
//
12+
// You can read more here:
13+
// https://on.cypress.io/configuration
14+
// ***********************************************************
15+
16+
// Import commands.js using ES2015 syntax:
17+
import './commands'
18+
19+
// Alternatively you can use CommonJS syntax:
20+
// require('./commands')
21+
22+
import { mount } from 'cypress/angular-zoneless'
23+
24+
// Augment the Cypress namespace to include type definitions for
25+
// your custom command.
26+
// Alternatively, can be defined in cypress/support/component.d.ts
27+
// with a <reference path="./component" /> at the top of your spec.
28+
declare global {
29+
namespace Cypress {
30+
interface Chainable {
31+
mount: typeof mount
32+
}
33+
}
34+
}
35+
36+
Cypress.Commands.add('mount', mount)
37+
38+
// Example use:
39+
// cy.mount(MyComponent)

npm/cypress-schematic/src/schematics/ng-add/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ import {
1414
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'
1515
import { of } from 'rxjs'
1616
import { concatMap, map } from 'rxjs/operators'
17+
import { gte as isSemverGte } from 'semver'
1718

1819
import { addPackageJsonDependency, NodeDependencyType } from '../utils/dependencies'
1920
import {
2021
getAngularJsonValue,
21-
getAngularVersion,
22+
getAngularSemverVersion,
2223
getLatestNodeVersion,
2324
NodePackage,
2425
getDirectoriesAndCreateSpecs,
@@ -36,7 +37,7 @@ type HandleFilesType = {
3637

3738
export default function (_options: any): Rule {
3839
return (tree: Tree, _context: SchematicContext) => {
39-
_options = { ..._options, __version__: getAngularVersion(tree) }
40+
_options = { ..._options, __version__: getAngularSemverVersion(tree) }
4041

4142
return chain([
4243
updateDependencies(),
@@ -141,10 +142,13 @@ function addCypressComponentTestingFiles (options: any): Rule {
141142
const angularJsonValue = getAngularJsonValue(tree)
142143
const { projects } = angularJsonValue
143144

145+
// if using Angular 21 or greater, we need to use the cypress/angular-zoneless mount function
146+
const applyPath = isSemverGte('21.0.0', options.__version__) ? './files-ct-zoneless' : './files-ct'
147+
144148
return handleFiles(tree, context, {
145149
projects,
146150
options,
147-
applyPath: './files-ct',
151+
applyPath,
148152
movePath: '/cypress/support',
149153
relativeToWorkspacePath: `/cypress`,
150154
})

npm/cypress-schematic/src/schematics/utils/index.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { getSystemPath, normalize, strings } from '@angular-devkit/core'
44
import { Tree, apply, url, applyTemplates, move, Rule } from '@angular-devkit/schematics'
55
import { get } from 'https'
66
import { Schema } from '../ng-generate/cypress-test/schema'
7+
import { minVersion as semverMinVersion } from 'semver'
8+
import type { SemVer } from 'semver'
79

810
import { getPackageJsonDependency } from './dependencies'
911
import { JSONFile } from './jsonFile'
@@ -13,12 +15,21 @@ export interface NodePackage {
1315
version: string
1416
}
1517

16-
export function getAngularVersion (tree: Tree): number {
18+
export function getAngularSemverVersion (tree: Tree): SemVer | null {
1719
const packageNode = getPackageJsonDependency(tree, '@angular/core')
1820

19-
const version = packageNode && packageNode.version.split('').find((char) => !!parseInt(char, 10))
21+
try {
22+
if (packageNode !== null) {
23+
const version: SemVer | null = packageNode && packageNode.version ?
24+
semverMinVersion(packageNode.version) : null
2025

21-
return version ? +version : 0
26+
return version
27+
}
28+
29+
return null
30+
} catch (e) {
31+
return null
32+
}
2233
}
2334

2435
/**

npm/webpack-dev-server/test/handlers/angularHandler.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe('angularHandler', { timeout: 60000 }, function () {
8484
browser: 'src/main.ts',
8585
tsConfig: 'tsconfig.app.json',
8686
assets: ['src/favicon.ico', 'src/assets'],
87-
styles: ['src/styles.scss'],
87+
styles: ['src/styles.css'],
8888
optimization: false,
8989
extractLicenses: false,
9090
sourceMap: true,

system-tests/projects/angular-21/angular.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
"options": {
1616
"tsConfig": "tsconfig.app.json",
1717
"browser": "src/main.ts",
18-
"tsConfig": "tsconfig.app.json",
1918
"assets": [
2019
"src/favicon.ico",
2120
"src/assets"

system-tests/projects/angular-21/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,5 @@
2828
"jsdom": "^27.1.0",
2929
"typescript": "~5.9.2",
3030
"vitest": "^4.0.8"
31-
},
32-
"projectFixtureDirectory": "angular"
31+
}
3332
}

system-tests/projects/angular-21/tsconfig.app.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,9 @@
66
},
77
"include": [
88
"src/**/*.ts"
9+
],
10+
"exclude": [
11+
"src/app/**/*.cy.ts",
12+
"src/app/components/**/*.ts"
913
]
1014
}

0 commit comments

Comments
 (0)