Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ _Released 08/12/2025 (PENDING)_
- Selectors accepted in the `selectorPriority` of the `SelectorPlayground` (renamed to `ElementSelector`) API have been expanded to accept `name` and `attributes:*`. Additionally, the default selector priority used by Cypress now includes `name`. Addresses [#31801](https://github.com/cypress-io/cypress/issues/30309) and [#6876](https://github.com/cypress-io/cypress/issues/6876). Addressed in [#31889](https://github.com/cypress-io/cypress/pull/31889).
- [`tsx`](https://tsx.is/) is now used in all cases to run the Cypress config, replacing [ts-node](https://github.com/TypeStrong/ts-node) for TypeScript and Node.js for CommonJS/ESM. This should allow for more interoperability for users who are using any variant of ES Modules. Addresses [#8090](https://github.com/cypress-io/cypress/issues/8090), [#15724](https://github.com/cypress-io/cypress/issues/15724), [#21805](https://github.com/cypress-io/cypress/issues/21805), [#22273](https://github.com/cypress-io/cypress/issues/22273), [#22747](https://github.com/cypress-io/cypress/issues/22747), [#23141](https://github.com/cypress-io/cypress/issues/23141), [#25958](https://github.com/cypress-io/cypress/issues/25958), [#25959](https://github.com/cypress-io/cypress/issues/25959), [#26606](https://github.com/cypress-io/cypress/issues/26606), [#27359](https://github.com/cypress-io/cypress/issues/27359), [#27450](https://github.com/cypress-io/cypress/issues/27450), [#28442](https://github.com/cypress-io/cypress/issues/28442), [#30318](https://github.com/cypress-io/cypress/issues/30318), [#30718](https://github.com/cypress-io/cypress/issues/30718), [#30907](https://github.com/cypress-io/cypress/issues/30907), [#30915](https://github.com/cypress-io/cypress/issues/30915), [#30925](https://github.com/cypress-io/cypress/issues/30925), [#30954](https://github.com/cypress-io/cypress/issues/30954) and [#31185](https://github.com/cypress-io/cypress/issues/31185).
- `@cypress/vite-dev-server` now supports [vite](https://vite.dev/) version 7. Addresses[#31882](https://github.com/cypress-io/cypress/issues/31882).
- `Angular` version 20 is now supported within component testing. As of now, `cypress/angular` still requires `zone.js` and `@angular-devkit/build-angular`. Addresses [#31304](https://github.com/cypress-io/cypress/issues/31304).


**Bugfixes:**

Expand Down
18 changes: 9 additions & 9 deletions npm/cypress-schematic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@
},
"dependencies": {
"jsonc-parser": "^3.3.1",
"rxjs": "~7.8.1"
"rxjs": "~7.8.2"
},
"devDependencies": {
"@angular-devkit/architect": "^0.1802.11",
"@angular-devkit/core": "^18.2.11",
"@angular-devkit/schematics": "^18.2.11",
"@angular-devkit/schematics-cli": "^18.2.11",
"@angular/cli": "^18.2.11",
"@schematics/angular": "^18.2.11",
"@angular-devkit/architect": "^0.2001.6",
"@angular-devkit/core": "^20.1.6",
"@angular-devkit/schematics": "^20.1.6",
"@angular-devkit/schematics-cli": "^20.1.6",
"@angular/cli": "^20.1.6",
"@schematics/angular": "^20.1.6",
"@types/chai-enzyme": "0.6.13",
"@types/mocha": "8.0.3",
"@types/node": "^20.16.0",
"@types/node": "^22.17.1",
"typescript": "~5.4.5",
"vitest": "2.1.4"
"vitest": "3.2.4"
},
"peerDependencies": {
"@angular/cli": ">=18.0.0",
Expand Down
2 changes: 1 addition & 1 deletion npm/cypress-schematic/src/ct.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const copyAngularMount = async (projectPath: string) => {

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

const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-18', 'angular-19']
const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-19', 'angular-20']

const timeout = 1000 * 60 * 5

Expand Down
2 changes: 1 addition & 1 deletion npm/cypress-schematic/src/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const runCommandInProject = (command: string, projectPath: string) => {

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

const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-18', 'angular-19']
const ANGULAR_PROJECTS: ProjectFixtureDir[] = ['angular-19', 'angular-20']

describe('ng add @cypress/schematic / only e2e', { timeout: 1000 * 60 * 5 }, function () {
for (const project of ANGULAR_PROJECTS) {
Expand Down
1 change: 1 addition & 0 deletions npm/webpack-dev-server/cypress/e2e/angular.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { ProjectFixtureDir } from '@tooling/system-tests/lib/fixtureDirs'
const WEBPACK_ANGULAR: ProjectFixtureDir[] = [
'angular-18',
'angular-19',
'angular-20',
]

// Add to this list to focus on a particular permutation
Expand Down
25 changes: 2 additions & 23 deletions npm/webpack-dev-server/src/helpers/angularHandler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as fs from 'fs-extra'
import { tmpdir } from 'os'
import * as path from 'path'
import { gte } from 'semver'
import type { Configuration, RuleSetRule } from 'webpack'
import type { PresetHandlerResult, WebpackDevServerConfig } from '../devServer'
import { dynamicAbsoluteImport, dynamicImport } from '../dynamic-import'
Expand Down Expand Up @@ -170,22 +169,11 @@ export async function getTempDir (projectName: string): Promise<string> {
}

export async function getAngularCliModules (projectRoot: string) {
let angularVersion: string

try {
angularVersion = await getInstalledPackageVersion('@angular-devkit/core', projectRoot)
} catch {
throw new Error(`Could not resolve "@angular-devkit/core". Do you have it installed?`)
}

const angularCLiModules = [
'@angular-devkit/build-angular/src/utils/webpack-browser-config.js',
// in Angular 16.1 the locations of these files below were changed
...(
gte(angularVersion, '16.1.0')
? ['@angular-devkit/build-angular/src/tools/webpack/configs/common.js', '@angular-devkit/build-angular/src/tools/webpack/configs/styles.js']
: ['@angular-devkit/build-angular/src/webpack/configs/common.js', '@angular-devkit/build-angular/src/webpack/configs/styles.js']
),
'@angular-devkit/build-angular/src/tools/webpack/configs/common.js',
'@angular-devkit/build-angular/src/tools/webpack/configs/styles.js',
'@angular-devkit/core/src/index.js',
] as const

Expand All @@ -212,15 +200,6 @@ export async function getAngularCliModules (projectRoot: string) {
}
}

async function getInstalledPackageVersion (pkgName: string, projectRoot: string): Promise<string> {
const packageJsonPath = require.resolve(`${pkgName}/package.json`, { paths: [projectRoot] })
const { version } = JSON.parse(
await fs.readFile(packageJsonPath, { encoding: 'utf-8' }),
)

return version
}

export async function getAngularJson (projectRoot: string): Promise<AngularJson> {
const { findUp } = await dynamicImport<typeof import('find-up')>('find-up')

Expand Down
93 changes: 53 additions & 40 deletions npm/webpack-dev-server/test/handlers/angularHandler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ chai.use(chaiPromise)
describe('angularHandler', function () {
this.timeout(1000 * 60)

it('sources the config from angular-18', async () => {
const projectRoot = await scaffoldMigrationProject('angular-18')
it('sources the config from angular-19', async () => {
const projectRoot = await scaffoldMigrationProject('angular-19')

process.chdir(projectRoot)
const devServerConfig = {
Expand All @@ -38,16 +38,38 @@ describe('angularHandler', function () {
expect(webpackConfig).to.exist
expect((webpackConfig?.entry as any).main).to.be.undefined
expect(sourceWebpackModulesResult.framework?.importPath).to.include(path.join('@angular-devkit', 'build-angular'))
const { buildOptions } = await expectNormalizeProjectConfig(projectRoot)
const projectConfig = await getProjectConfig(projectRoot)

expect(projectConfig).to.deep.eq({
root: '',
sourceRoot: 'src',
buildOptions: {
outputPath: 'dist/angular',
index: 'src/index.html',
main: 'src/main.ts',
polyfills: 'src/polyfills.ts',
tsConfig: 'tsconfig.app.json',
inlineStyleLanguage: 'scss',
assets: ['src/favicon.ico', 'src/assets'],
styles: ['src/styles.scss'],
scripts: [],
buildOptimizer: false,
optimization: false,
vendorChunk: true,
extractLicenses: false,
sourceMap: true,
namedChunks: true,
},
})

await expectLoadsAngularJson(projectRoot)
await expectLoadsAngularCLiModules(projectRoot)
await expectGeneratesTsConfig(devServerConfig, buildOptions)
expectLoadsAngularBuildOptions(buildOptions)
await expectGeneratesTsConfig(devServerConfig, projectConfig.buildOptions, true)
expectLoadsAngularBuildOptions(projectConfig.buildOptions)
})

it('sources the config from angular-19', async () => {
const projectRoot = await scaffoldMigrationProject('angular-19')
it('sources the config from angular-20', async () => {
const projectRoot = await scaffoldMigrationProject('angular-20')

process.chdir(projectRoot)
const devServerConfig = {
Expand All @@ -62,12 +84,30 @@ describe('angularHandler', function () {
expect(webpackConfig).to.exist
expect((webpackConfig?.entry as any).main).to.be.undefined
expect(sourceWebpackModulesResult.framework?.importPath).to.include(path.join('@angular-devkit', 'build-angular'))
const { buildOptions } = await expectNormalizeProjectConfig(projectRoot)
const projectConfig = await getProjectConfig(projectRoot)

expect(projectConfig).to.deep.eq({
root: '',
sourceRoot: 'src',
buildOptions: {
browser: 'src/main.ts',
// because of the way the main fixtures are configured in the system-test projects, we need to run as a zone.js application
polyfills: [
'zone.js',
],
tsConfig: 'tsconfig.app.json',
assets: ['src/favicon.ico', 'src/assets'],
styles: ['src/styles.scss'],
optimization: false,
extractLicenses: false,
sourceMap: true,
},
})

await expectLoadsAngularJson(projectRoot)
await expectLoadsAngularCLiModules(projectRoot)
await expectGeneratesTsConfig(devServerConfig, buildOptions)
expectLoadsAngularBuildOptions(buildOptions)
await expectGeneratesTsConfig(devServerConfig, projectConfig.buildOptions, false)
expectLoadsAngularBuildOptions(projectConfig.buildOptions)
})

it('allows custom project config', async () => {
Expand Down Expand Up @@ -112,38 +152,11 @@ describe('angularHandler', function () {
expect(sourceWebpackModulesResult.framework?.importPath).to.include(path.join('@angular-devkit', 'build-angular'))
await expectLoadsAngularJson(projectRoot)
await expectLoadsAngularCLiModules(projectRoot)
await expectGeneratesTsConfig(devServerConfig, customProjectConfig.buildOptions)
await expectGeneratesTsConfig(devServerConfig, customProjectConfig.buildOptions, true)
expectLoadsAngularBuildOptions(customProjectConfig.buildOptions)
})
})

const expectNormalizeProjectConfig = async (projectRoot: string) => {
const projectConfig = await getProjectConfig(projectRoot)

expect(projectConfig).to.deep.eq({
root: '',
sourceRoot: 'src',
buildOptions: {
outputPath: 'dist/angular',
index: 'src/index.html',
main: 'src/main.ts',
polyfills: 'src/polyfills.ts',
tsConfig: 'tsconfig.app.json',
inlineStyleLanguage: 'scss',
assets: ['src/favicon.ico', 'src/assets'],
styles: ['src/styles.scss'],
scripts: [],
buildOptimizer: false,
optimization: false,
vendorChunk: true,
extractLicenses: false,
sourceMap: true,
namedChunks: true,
},
})

return projectConfig
}
const expectLoadsAngularJson = async (projectRoot: string) => {
const angularJson = await getAngularJson(projectRoot)

Expand All @@ -168,7 +181,7 @@ const expectLoadsAngularBuildOptions = (buildOptions: BuildOptions) => {
expect(finalBuildOptions.outputHashing).to.equal('none')
expect(finalBuildOptions.budgets).to.be.undefined
}
const expectGeneratesTsConfig = async (devServerConfig: AngularWebpackDevServerConfig, buildOptions: any) => {
const expectGeneratesTsConfig = async (devServerConfig: AngularWebpackDevServerConfig, buildOptions: any, hasPolyfillsConfigured: boolean = false) => {
const { projectRoot } = devServerConfig.cypressConfig
let tsConfigPath = await generateTsConfig(devServerConfig, buildOptions)
const tempDir = await getTempDir(path.basename(projectRoot))
Expand All @@ -193,7 +206,7 @@ const expectGeneratesTsConfig = async (devServerConfig: AngularWebpackDevServerC
},
include: [
toPosix(path.join(projectRoot, 'src/**/*.cy.ts')),
toPosix(path.join(projectRoot, 'src/polyfills.ts')),
...(hasPolyfillsConfigured ? [toPosix(path.join(projectRoot, 'src/polyfills.ts'))] : []),
],
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { fixtureDirs } from '@tooling/system-tests'
type ProjectDirs = typeof fixtureDirs

const PROJECTS: {projectName: ProjectDirs[number], test: string}[] = [
{ projectName: 'angular-19', test: 'app.component' },
{ projectName: 'angular-20', test: 'app.component' },
{ projectName: 'react-vite-ts-configured', test: 'App.cy' },
{ projectName: 'react18', test: 'App.cy' },
{ projectName: 'next-14', test: 'index.cy' },
Expand Down
10 changes: 5 additions & 5 deletions packages/scaffold-config/src/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const WIZARD_DEPENDENCY_ANGULAR_CLI = {
package: '@angular/cli',
installer: '@angular/cli',
description: 'CLI tool that you use to initialize, develop, scaffold, and maintain Angular applications.',
minVersion: '^18.0.0 || ^19.0.0',
minVersion: '^18.0.0 || ^19.0.0 || ^20.0.0',
} as const

export const WIZARD_DEPENDENCY_ANGULAR_DEVKIT_BUILD_ANGULAR = {
Expand All @@ -79,7 +79,7 @@ export const WIZARD_DEPENDENCY_ANGULAR_DEVKIT_BUILD_ANGULAR = {
package: '@angular-devkit/build-angular',
installer: '@angular-devkit/build-angular',
description: 'Angular Webpack build facade',
minVersion: '^18.0.0 || ^19.0.0',
minVersion: '^18.0.0 || ^19.0.0 || ^20.0.0',
} as const

export const WIZARD_DEPENDENCY_ANGULAR_CORE = {
Expand All @@ -88,7 +88,7 @@ export const WIZARD_DEPENDENCY_ANGULAR_CORE = {
package: '@angular/core',
installer: '@angular/core',
description: 'The core of the Angular framework',
minVersion: '^18.0.0 || ^19.0.0',
minVersion: '^18.0.0 || ^19.0.0 || ^20.0.0',
} as const

export const WIZARD_DEPENDENCY_ANGULAR_COMMON = {
Expand All @@ -97,7 +97,7 @@ export const WIZARD_DEPENDENCY_ANGULAR_COMMON = {
package: '@angular/common',
installer: '@angular/common',
description: 'Commonly needed Angular directives and services',
minVersion: '^18.0.0 || ^19.0.0',
minVersion: '^18.0.0 || ^19.0.0 || ^20.0.0',
} as const

export const WIZARD_DEPENDENCY_ANGULAR_PLATFORM_BROWSER_DYNAMIC = {
Expand All @@ -106,7 +106,7 @@ export const WIZARD_DEPENDENCY_ANGULAR_PLATFORM_BROWSER_DYNAMIC = {
package: '@angular/platform-browser-dynamic',
installer: '@angular/platform-browser-dynamic',
description: 'Library for using Angular in a web browser with JIT compilation',
minVersion: '^18.0.0 || ^19.0.0',
minVersion: '^18.0.0 || ^19.0.0 || ^20.0.0',
} as const

export const WIZARD_DEPENDENCY_SVELTE: Cypress.CypressComponentDependency = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import { CounterService } from './counter.service'
</button>`,
})
export class CounterComponent {
count$ = this.counterService.count$
count$

constructor (private counterService: CounterService) {}
constructor (private counterService: CounterService) {
this.count$ = this.counterService.count$
}

increment () {
this.counterService.increment()
Expand Down
Loading
Loading