diff --git a/package.json b/package.json index 56390d1d..e2e14e91 100644 --- a/package.json +++ b/package.json @@ -79,12 +79,6 @@ "vitest": "^4.0.8", "zone.js": "~0.16.0" }, - "checkPeerDependencies": { - "ignore": [ - "ajv", - "terser" - ] - }, "docgen": { "publishDir": "_ng2_docs", "navigation": { diff --git a/test-angular-versions/scaffold.sh b/test-angular-versions/scaffold.sh index f304e68b..0a88fa1e 100755 --- a/test-angular-versions/scaffold.sh +++ b/test-angular-versions/scaffold.sh @@ -12,13 +12,16 @@ DIR=v$VERSION npx -y -p @angular/cli@$VERSION ng new --package-manager=yarn --style=css --routing=false --skip-git --skip-install --skip-tests $DIR rm -rf $DIR/src/app -cp -Rp scaffold/* $DIR +cp -Rp scaffold/src $DIR/ +cp -Rp scaffold/e2e $DIR/ +cp scaffold/playwright.config.ts $DIR/ $JSON write $DIR/package.json name "$VERSION" $JSON write $DIR/package.json dependencies.@uirouter/angular "*" -$JSON write $DIR/package.json dependencies.@uirouter/cypress-runner "*" +$JSON write $DIR/package.json devDependencies.@playwright/test "^1.49.0" +$JSON write $DIR/package.json devDependencies.serve "^14.2.4" $JSON write $DIR/package.json scripts.test "npm run test:dev && npm run test:prod" -$JSON write $DIR/package.json scripts.test:dev "ng build --configuration development && cypress-runner run --path dist/$DIR" -$JSON write $DIR/package.json scripts.test:prod "ng build --configuration production && cypress-runner run --path dist/$DIR" +$JSON write $DIR/package.json scripts.test:dev "ng build --configuration development && DIST_PATH=dist/$DIR/browser npx playwright test" +$JSON write $DIR/package.json scripts.test:prod "ng build --configuration production && DIST_PATH=dist/$DIR/browser npx playwright test" $JSON write ../downstream_projects.json "projects.angular$VERSION" "./test-angular-versions/$DIR" diff --git a/test-angular-versions/scaffold/cypress.config.ts b/test-angular-versions/scaffold/cypress.config.ts deleted file mode 100644 index d764a065..00000000 --- a/test-angular-versions/scaffold/cypress.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - video: false, - e2e: { - setupNodeEvents(on, config) {}, - baseUrl: 'http://localhost:4000', - supportFile: false - }, -}) diff --git a/test-angular-versions/scaffold/cypress/e2e/sample_app.cy.js b/test-angular-versions/scaffold/cypress/e2e/sample_app.cy.js deleted file mode 100644 index f01159c7..00000000 --- a/test-angular-versions/scaffold/cypress/e2e/sample_app.cy.js +++ /dev/null @@ -1,69 +0,0 @@ -describe('Angular app', () => { - beforeEach(() => { - window.sessionStorage.clear(); - }); - - it('loads', () => { - cy.visit(''); - }); - - it('loads home state by default', () => { - cy.visit(''); - cy.url().should('include', '/home'); - }); - - it('renders uisref as links', () => { - cy.visit(''); - cy.get('a').contains('home'); - cy.get('a').contains('about'); - cy.get('a').contains('lazy'); - cy.get('a').contains('lazy.child'); - cy.get('a').contains('lazy.child.viewtarget'); - }); - - it('renders home', () => { - cy.visit('/home'); - cy.get('a').contains('home').should('have.class', 'active'); - cy.get('a').contains('about').should('not.have.class', 'active'); - cy.get('#default').contains('home works'); - }); - - it('renders about', () => { - cy.visit('/home'); - cy.visit('/about'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('about').should('have.class', 'active'); - cy.get('#default').contains('about works'); - }); - - it('loads lazy routes', () => { - cy.visit('/home'); - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy routes', () => { - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy child routes', () => { - cy.visit('/lazy/child'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - }); - - it('targets named views', () => { - cy.visit('/lazy/child/viewtarget'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - cy.get('#header').contains('lazy.child.viewtarget works'); - cy.get('#footer').contains('lazy.child.viewtarget works'); - }); -}); diff --git a/test-angular-versions/scaffold/e2e/sample_app.spec.ts b/test-angular-versions/scaffold/e2e/sample_app.spec.ts new file mode 100644 index 00000000..5a357b8a --- /dev/null +++ b/test-angular-versions/scaffold/e2e/sample_app.spec.ts @@ -0,0 +1,67 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Angular app', () => { + test('loads', async ({ page }) => { + await page.goto('/'); + }); + + test('loads home state by default', async ({ page }) => { + await page.goto('/'); + await expect(page).toHaveURL(/\/home/); + }); + + test('renders uisref as links', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('a', { hasText: 'home' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'about' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child.viewtarget' })).toBeVisible(); + }); + + test('renders home', async ({ page }) => { + await page.goto('/home'); + await expect(page.locator('a', { hasText: 'home' })).toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).not.toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('home works'); + }); + + test('renders about', async ({ page }) => { + await page.goto('/home'); + await page.goto('/about'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('about works'); + }); + + test('loads lazy routes', async ({ page }) => { + await page.goto('/home'); + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy routes', async ({ page }) => { + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy child routes', async ({ page }) => { + await page.goto('/lazy/child'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + }); + + test('targets named views', async ({ page }) => { + await page.goto('/lazy/child/viewtarget'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + await expect(page.locator('#header')).toContainText('lazy.child.viewtarget works'); + await expect(page.locator('#footer')).toContainText('lazy.child.viewtarget works'); + }); +}); diff --git a/test-angular-versions/scaffold/playwright.config.ts b/test-angular-versions/scaffold/playwright.config.ts new file mode 100644 index 00000000..7865f415 --- /dev/null +++ b/test-angular-versions/scaffold/playwright.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from '@playwright/test'; + +const distPath = process.env.DIST_PATH || 'dist'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + reporter: 'list', + use: { + baseURL: 'http://localhost:4000', + trace: 'on-first-retry', + }, + webServer: { + command: `npx serve ${distPath} -l 4000 -s`, + url: 'http://localhost:4000', + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/test-angular-versions/v21-standalone/cypress.config.js b/test-angular-versions/v21-standalone/cypress.config.js deleted file mode 100644 index d764a065..00000000 --- a/test-angular-versions/v21-standalone/cypress.config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - video: false, - e2e: { - setupNodeEvents(on, config) {}, - baseUrl: 'http://localhost:4000', - supportFile: false - }, -}) diff --git a/test-angular-versions/v21-standalone/cypress/e2e/sample_app.cy.js b/test-angular-versions/v21-standalone/cypress/e2e/sample_app.cy.js deleted file mode 100644 index 584659b5..00000000 --- a/test-angular-versions/v21-standalone/cypress/e2e/sample_app.cy.js +++ /dev/null @@ -1,70 +0,0 @@ -describe('Angular app', () => { - beforeEach(() => { - window.sessionStorage.clear(); - }); - - it('loads', () => { - cy.visit(''); - }); - - it('loads home state by default', () => { - cy.visit(''); - cy.url().should('include', '/home'); - }); - - it('renders uisref as links', () => { - cy.visit(''); - cy.get('a').contains('home'); - cy.get('a').contains('about'); - cy.get('a').contains('lazy'); - cy.get('a').contains('lazy.child'); - cy.get('a').contains('lazy.child.viewtarget'); - }); - - it('renders home', () => { - cy.visit('/home'); - cy.get('a').contains('home').should('have.class', 'active'); - cy.get('a').contains('about').should('not.have.class', 'active'); - cy.get('#default').contains('home works'); - }); - - it('renders about', () => { - cy.visit('/home'); - cy.visit('/about'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('about').should('have.class', 'active'); - cy.get('#default').contains('about works'); - }); - - it('loads lazy routes', () => { - cy.visit('/home'); - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy routes', () => { - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy child routes', () => { - cy.visit('/lazy/child'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - cy.get('#lazy-child-provided').contains('provided value'); - }); - - it('targets named views', () => { - cy.visit('/lazy/child/viewtarget'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - cy.get('#header').contains('lazy.child.viewtarget works'); - cy.get('#footer').contains('lazy.child.viewtarget works'); - }); -}); diff --git a/test-angular-versions/v21-standalone/e2e/sample_app.spec.ts b/test-angular-versions/v21-standalone/e2e/sample_app.spec.ts new file mode 100644 index 00000000..71d99156 --- /dev/null +++ b/test-angular-versions/v21-standalone/e2e/sample_app.spec.ts @@ -0,0 +1,68 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Angular app', () => { + test('loads', async ({ page }) => { + await page.goto('/'); + }); + + test('loads home state by default', async ({ page }) => { + await page.goto('/'); + await expect(page).toHaveURL(/\/home/); + }); + + test('renders uisref as links', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('a', { hasText: 'home' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'about' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child.viewtarget' })).toBeVisible(); + }); + + test('renders home', async ({ page }) => { + await page.goto('/home'); + await expect(page.locator('a', { hasText: 'home' })).toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).not.toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('home works'); + }); + + test('renders about', async ({ page }) => { + await page.goto('/home'); + await page.goto('/about'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('about works'); + }); + + test('loads lazy routes', async ({ page }) => { + await page.goto('/home'); + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy routes', async ({ page }) => { + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy child routes', async ({ page }) => { + await page.goto('/lazy/child'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + await expect(page.locator('#lazy-child-provided')).toContainText('provided value'); + }); + + test('targets named views', async ({ page }) => { + await page.goto('/lazy/child/viewtarget'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + await expect(page.locator('#header')).toContainText('lazy.child.viewtarget works'); + await expect(page.locator('#footer')).toContainText('lazy.child.viewtarget works'); + }); +}); diff --git a/test-angular-versions/v21-standalone/package.json b/test-angular-versions/v21-standalone/package.json index 0c59d42a..8d8303f5 100644 --- a/test-angular-versions/v21-standalone/package.json +++ b/test-angular-versions/v21-standalone/package.json @@ -7,8 +7,8 @@ "build": "ng build", "watch": "ng build --watch --configuration development", "test": "npm run test:dev && npm run test:prod", - "test:dev": "ng build --configuration development && cypress-runner run --path dist/v21-standalone/browser", - "test:prod": "ng build --configuration production && cypress-runner run --path dist/v21-standalone/browser" + "test:dev": "ng build --configuration development && DIST_PATH=dist/v21-standalone/browser npx playwright test", + "test:prod": "ng build --configuration production && DIST_PATH=dist/v21-standalone/browser npx playwright test" }, "private": true, "dependencies": { @@ -18,7 +18,6 @@ "@angular/platform-browser": "^21.0.3", "@angular/platform-browser-dynamic": "^21.0.3", "@uirouter/angular": "*", - "@uirouter/cypress-runner": "*", "@uirouter/core": "*", "@uirouter/rx": "*", "rxjs": "~7.8.0", @@ -29,19 +28,8 @@ "@angular/build": "^21.0.2", "@angular/cli": "^21.0.2", "@angular/compiler-cli": "^21.0.3", - "@types/jasmine": "~5.1.0", - "jasmine-core": "~5.1.0", - "karma": "~6.4.0", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "~2.1.0", + "@playwright/test": "^1.49.0", + "serve": "^14.2.4", "typescript": "~5.9.3" - }, - "checkPeerDependencies": { - "ignore": [ - "ajv", - "terser" - ] } } diff --git a/test-angular-versions/v21-standalone/playwright.config.ts b/test-angular-versions/v21-standalone/playwright.config.ts new file mode 100644 index 00000000..7865f415 --- /dev/null +++ b/test-angular-versions/v21-standalone/playwright.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from '@playwright/test'; + +const distPath = process.env.DIST_PATH || 'dist'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + reporter: 'list', + use: { + baseURL: 'http://localhost:4000', + trace: 'on-first-retry', + }, + webServer: { + command: `npx serve ${distPath} -l 4000 -s`, + url: 'http://localhost:4000', + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/test-angular-versions/v21-zoneless/cypress.config.js b/test-angular-versions/v21-zoneless/cypress.config.js deleted file mode 100644 index d764a065..00000000 --- a/test-angular-versions/v21-zoneless/cypress.config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - video: false, - e2e: { - setupNodeEvents(on, config) {}, - baseUrl: 'http://localhost:4000', - supportFile: false - }, -}) diff --git a/test-angular-versions/v21-zoneless/cypress/e2e/sample_app.cy.js b/test-angular-versions/v21-zoneless/cypress/e2e/sample_app.cy.js deleted file mode 100644 index 584659b5..00000000 --- a/test-angular-versions/v21-zoneless/cypress/e2e/sample_app.cy.js +++ /dev/null @@ -1,70 +0,0 @@ -describe('Angular app', () => { - beforeEach(() => { - window.sessionStorage.clear(); - }); - - it('loads', () => { - cy.visit(''); - }); - - it('loads home state by default', () => { - cy.visit(''); - cy.url().should('include', '/home'); - }); - - it('renders uisref as links', () => { - cy.visit(''); - cy.get('a').contains('home'); - cy.get('a').contains('about'); - cy.get('a').contains('lazy'); - cy.get('a').contains('lazy.child'); - cy.get('a').contains('lazy.child.viewtarget'); - }); - - it('renders home', () => { - cy.visit('/home'); - cy.get('a').contains('home').should('have.class', 'active'); - cy.get('a').contains('about').should('not.have.class', 'active'); - cy.get('#default').contains('home works'); - }); - - it('renders about', () => { - cy.visit('/home'); - cy.visit('/about'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('about').should('have.class', 'active'); - cy.get('#default').contains('about works'); - }); - - it('loads lazy routes', () => { - cy.visit('/home'); - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy routes', () => { - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy child routes', () => { - cy.visit('/lazy/child'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - cy.get('#lazy-child-provided').contains('provided value'); - }); - - it('targets named views', () => { - cy.visit('/lazy/child/viewtarget'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - cy.get('#header').contains('lazy.child.viewtarget works'); - cy.get('#footer').contains('lazy.child.viewtarget works'); - }); -}); diff --git a/test-angular-versions/v21-zoneless/e2e/sample_app.spec.ts b/test-angular-versions/v21-zoneless/e2e/sample_app.spec.ts new file mode 100644 index 00000000..71d99156 --- /dev/null +++ b/test-angular-versions/v21-zoneless/e2e/sample_app.spec.ts @@ -0,0 +1,68 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Angular app', () => { + test('loads', async ({ page }) => { + await page.goto('/'); + }); + + test('loads home state by default', async ({ page }) => { + await page.goto('/'); + await expect(page).toHaveURL(/\/home/); + }); + + test('renders uisref as links', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('a', { hasText: 'home' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'about' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child.viewtarget' })).toBeVisible(); + }); + + test('renders home', async ({ page }) => { + await page.goto('/home'); + await expect(page.locator('a', { hasText: 'home' })).toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).not.toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('home works'); + }); + + test('renders about', async ({ page }) => { + await page.goto('/home'); + await page.goto('/about'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('about works'); + }); + + test('loads lazy routes', async ({ page }) => { + await page.goto('/home'); + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy routes', async ({ page }) => { + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy child routes', async ({ page }) => { + await page.goto('/lazy/child'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + await expect(page.locator('#lazy-child-provided')).toContainText('provided value'); + }); + + test('targets named views', async ({ page }) => { + await page.goto('/lazy/child/viewtarget'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + await expect(page.locator('#header')).toContainText('lazy.child.viewtarget works'); + await expect(page.locator('#footer')).toContainText('lazy.child.viewtarget works'); + }); +}); diff --git a/test-angular-versions/v21-zoneless/package.json b/test-angular-versions/v21-zoneless/package.json index 4d398beb..fffc6318 100644 --- a/test-angular-versions/v21-zoneless/package.json +++ b/test-angular-versions/v21-zoneless/package.json @@ -7,8 +7,8 @@ "build": "ng build", "watch": "ng build --watch --configuration development", "test": "npm run test:dev && npm run test:prod", - "test:dev": "ng build --configuration development && cypress-runner run --path dist/v21-zoneless/browser", - "test:prod": "ng build --configuration production && cypress-runner run --path dist/v21-zoneless/browser" + "test:dev": "ng build --configuration development && DIST_PATH=dist/v21-zoneless/browser npx playwright test", + "test:prod": "ng build --configuration production && DIST_PATH=dist/v21-zoneless/browser npx playwright test" }, "private": true, "dependencies": { @@ -18,7 +18,6 @@ "@angular/platform-browser": "^21.0.3", "@angular/platform-browser-dynamic": "^21.0.3", "@uirouter/angular": "*", - "@uirouter/cypress-runner": "*", "@uirouter/core": "*", "@uirouter/rx": "*", "rxjs": "~7.8.0", @@ -28,12 +27,8 @@ "@angular/build": "^21.0.2", "@angular/cli": "^21.0.2", "@angular/compiler-cli": "^21.0.3", + "@playwright/test": "^1.49.0", + "serve": "^14.2.4", "typescript": "~5.9.3" - }, - "checkPeerDependencies": { - "ignore": [ - "ajv", - "terser" - ] } } diff --git a/test-angular-versions/v21-zoneless/playwright.config.ts b/test-angular-versions/v21-zoneless/playwright.config.ts new file mode 100644 index 00000000..7865f415 --- /dev/null +++ b/test-angular-versions/v21-zoneless/playwright.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from '@playwright/test'; + +const distPath = process.env.DIST_PATH || 'dist'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + reporter: 'list', + use: { + baseURL: 'http://localhost:4000', + trace: 'on-first-retry', + }, + webServer: { + command: `npx serve ${distPath} -l 4000 -s`, + url: 'http://localhost:4000', + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/test-angular-versions/v21/cypress.config.js b/test-angular-versions/v21/cypress.config.js deleted file mode 100644 index 18216453..00000000 --- a/test-angular-versions/v21/cypress.config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'cypress'; - -export default defineConfig({ - video: false, - e2e: { - setupNodeEvents(on, config) { }, - baseUrl: 'http://localhost:4000', - supportFile: false - }, -}) diff --git a/test-angular-versions/v21/cypress/e2e/sample_app.cy.js b/test-angular-versions/v21/cypress/e2e/sample_app.cy.js deleted file mode 100644 index f01159c7..00000000 --- a/test-angular-versions/v21/cypress/e2e/sample_app.cy.js +++ /dev/null @@ -1,69 +0,0 @@ -describe('Angular app', () => { - beforeEach(() => { - window.sessionStorage.clear(); - }); - - it('loads', () => { - cy.visit(''); - }); - - it('loads home state by default', () => { - cy.visit(''); - cy.url().should('include', '/home'); - }); - - it('renders uisref as links', () => { - cy.visit(''); - cy.get('a').contains('home'); - cy.get('a').contains('about'); - cy.get('a').contains('lazy'); - cy.get('a').contains('lazy.child'); - cy.get('a').contains('lazy.child.viewtarget'); - }); - - it('renders home', () => { - cy.visit('/home'); - cy.get('a').contains('home').should('have.class', 'active'); - cy.get('a').contains('about').should('not.have.class', 'active'); - cy.get('#default').contains('home works'); - }); - - it('renders about', () => { - cy.visit('/home'); - cy.visit('/about'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('about').should('have.class', 'active'); - cy.get('#default').contains('about works'); - }); - - it('loads lazy routes', () => { - cy.visit('/home'); - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy routes', () => { - cy.visit('/lazy'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy').should('have.class', 'active'); - cy.get('#default').contains('lazy works'); - }); - - it('routes to lazy child routes', () => { - cy.visit('/lazy/child'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - }); - - it('targets named views', () => { - cy.visit('/lazy/child/viewtarget'); - cy.get('a').contains('home').should('not.have.class', 'active'); - cy.get('a').contains('lazy.child').should('have.class', 'active'); - cy.get('#default').contains('lazy.child works'); - cy.get('#header').contains('lazy.child.viewtarget works'); - cy.get('#footer').contains('lazy.child.viewtarget works'); - }); -}); diff --git a/test-angular-versions/v21/e2e/sample_app.spec.ts b/test-angular-versions/v21/e2e/sample_app.spec.ts new file mode 100644 index 00000000..5a357b8a --- /dev/null +++ b/test-angular-versions/v21/e2e/sample_app.spec.ts @@ -0,0 +1,67 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Angular app', () => { + test('loads', async ({ page }) => { + await page.goto('/'); + }); + + test('loads home state by default', async ({ page }) => { + await page.goto('/'); + await expect(page).toHaveURL(/\/home/); + }); + + test('renders uisref as links', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('a', { hasText: 'home' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'about' })).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toBeVisible(); + await expect(page.locator('a', { hasText: 'lazy.child.viewtarget' })).toBeVisible(); + }); + + test('renders home', async ({ page }) => { + await page.goto('/home'); + await expect(page.locator('a', { hasText: 'home' })).toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).not.toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('home works'); + }); + + test('renders about', async ({ page }) => { + await page.goto('/home'); + await page.goto('/about'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'about' })).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('about works'); + }); + + test('loads lazy routes', async ({ page }) => { + await page.goto('/home'); + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy routes', async ({ page }) => { + await page.goto('/lazy'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy works'); + }); + + test('routes to lazy child routes', async ({ page }) => { + await page.goto('/lazy/child'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + }); + + test('targets named views', async ({ page }) => { + await page.goto('/lazy/child/viewtarget'); + await expect(page.locator('a', { hasText: 'home' })).not.toHaveClass(/active/); + await expect(page.locator('a', { hasText: 'lazy.child' }).first()).toHaveClass(/active/); + await expect(page.locator('#default')).toContainText('lazy.child works'); + await expect(page.locator('#header')).toContainText('lazy.child.viewtarget works'); + await expect(page.locator('#footer')).toContainText('lazy.child.viewtarget works'); + }); +}); diff --git a/test-angular-versions/v21/package.json b/test-angular-versions/v21/package.json index fef0e6db..0958e57d 100644 --- a/test-angular-versions/v21/package.json +++ b/test-angular-versions/v21/package.json @@ -7,8 +7,8 @@ "build": "ng build", "watch": "ng build --watch --configuration development", "test": "npm run test:dev && npm run test:prod", - "test:dev": "ng build --configuration development && cypress-runner run --path dist/v21/browser", - "test:prod": "ng build --configuration production && cypress-runner run --path dist/v21/browser" + "test:dev": "ng build --configuration development && DIST_PATH=dist/v21/browser npx playwright test", + "test:prod": "ng build --configuration production && DIST_PATH=dist/v21/browser npx playwright test" }, "private": true, "dependencies": { @@ -18,7 +18,6 @@ "@angular/platform-browser": "^21.0.3", "@angular/platform-browser-dynamic": "^21.0.3", "@uirouter/angular": "*", - "@uirouter/cypress-runner": "*", "@uirouter/core": "*", "@uirouter/rx": "*", "rxjs": "~7.8.0", @@ -29,19 +28,8 @@ "@angular/build": "^21.0.2", "@angular/cli": "^21.0.2", "@angular/compiler-cli": "^21.0.3", - "@types/jasmine": "~5.1.0", - "jasmine-core": "~5.1.0", - "karma": "~6.4.0", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "~2.1.0", + "@playwright/test": "^1.49.0", + "serve": "^14.2.4", "typescript": "~5.9.3" - }, - "checkPeerDependencies": { - "ignore": [ - "ajv", - "terser" - ] } } diff --git a/test-angular-versions/v21/playwright.config.ts b/test-angular-versions/v21/playwright.config.ts new file mode 100644 index 00000000..7865f415 --- /dev/null +++ b/test-angular-versions/v21/playwright.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from '@playwright/test'; + +const distPath = process.env.DIST_PATH || 'dist'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + reporter: 'list', + use: { + baseURL: 'http://localhost:4000', + trace: 'on-first-retry', + }, + webServer: { + command: `npx serve ${distPath} -l 4000 -s`, + url: 'http://localhost:4000', + reuseExistingServer: !process.env.CI, + }, +});