From 5d692ecddfd0fe6b7a2ae45dc830dbe420953d40 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Fri, 23 Oct 2026 15:30:59 -0400 Subject: [PATCH] chore(angular): use Ionic lint and Prettier configs and add Playwright e2e tests --- angular-standalone/base/.gitignore | 6 ++ angular-standalone/base/.prettierignore | 5 ++ .../base/.vscode/extensions.json | 9 ++- angular-standalone/base/angular.json | 17 ++--- angular-standalone/base/eslint.config.js | 52 +++++++++----- angular-standalone/base/package.json | 19 ++++- angular-standalone/base/playwright.config.ts | 27 ++++++++ .../base/src/app/app.component.spec.ts | 5 +- .../base/src/environments/environment.prod.ts | 2 +- .../base/src/environments/environment.ts | 2 +- angular-standalone/base/src/index.html | 39 ++++++----- angular-standalone/base/src/main.ts | 10 ++- angular-standalone/base/tsconfig.e2e.json | 12 ++++ angular-standalone/base/vitest.config.mts | 10 +++ .../official/blank/e2e/app.spec.ts | 6 ++ .../official/blank/ionic.starter.json | 2 +- .../official/blank/src/app/app.routes.ts | 2 +- .../blank/src/app/home/home.page.html | 9 +-- .../blank/src/app/home/home.page.spec.ts | 3 +- .../official/list/e2e/app.spec.ts | 6 ++ .../official/list/ionic.starter.json | 2 +- .../list/src/app/app.component.spec.ts | 4 +- .../official/list/src/app/app.routes.ts | 6 +- .../official/list/src/app/home/home.page.html | 10 +-- .../list/src/app/home/home.page.spec.ts | 3 +- .../official/list/src/app/home/home.page.ts | 15 +++- .../src/app/message/message.component.html | 23 ++----- .../src/app/message/message.component.spec.ts | 6 +- .../list/src/app/message/message.component.ts | 3 +- .../list/src/app/services/data.service.ts | 22 +++--- .../app/view-message/view-message.page.html | 58 +++++++--------- .../view-message/view-message.page.spec.ts | 3 +- .../src/app/view-message/view-message.page.ts | 14 +++- .../official/sidemenu/e2e/app.spec.ts | 6 ++ .../official/sidemenu/ionic.starter.json | 2 +- .../sidemenu/src/app/app.component.html | 15 +++- .../sidemenu/src/app/app.component.spec.ts | 6 +- .../sidemenu/src/app/app.component.ts | 69 +++++++++++++++++-- .../official/sidemenu/src/app/app.routes.ts | 5 +- .../sidemenu/src/app/folder/folder.page.html | 5 +- .../src/app/folder/folder.page.spec.ts | 5 +- .../official/tabs/e2e/app.spec.ts | 6 ++ .../official/tabs/ionic.starter.json | 2 +- .../official/tabs/src/app/app.routes.ts | 2 +- .../explore-container.component.html | 7 +- .../explore-container.component.spec.ts | 3 +- .../official/tabs/src/app/tab1/tab1.page.html | 4 +- .../tabs/src/app/tab1/tab1.page.spec.ts | 3 +- .../official/tabs/src/app/tab1/tab1.page.ts | 1 + .../official/tabs/src/app/tab2/tab2.page.html | 4 +- .../tabs/src/app/tab2/tab2.page.spec.ts | 3 +- .../official/tabs/src/app/tab2/tab2.page.ts | 5 +- .../official/tabs/src/app/tab3/tab3.page.html | 4 +- .../tabs/src/app/tab3/tab3.page.spec.ts | 3 +- .../official/tabs/src/app/tab3/tab3.page.ts | 1 + .../tabs/src/app/tabs/tabs.page.spec.ts | 5 +- .../official/tabs/src/app/tabs/tabs.routes.ts | 12 ++-- 57 files changed, 389 insertions(+), 201 deletions(-) create mode 100644 angular-standalone/base/.prettierignore create mode 100644 angular-standalone/base/playwright.config.ts create mode 100644 angular-standalone/base/tsconfig.e2e.json create mode 100644 angular-standalone/base/vitest.config.mts create mode 100644 angular-standalone/official/blank/e2e/app.spec.ts create mode 100644 angular-standalone/official/list/e2e/app.spec.ts create mode 100644 angular-standalone/official/sidemenu/e2e/app.spec.ts create mode 100644 angular-standalone/official/tabs/e2e/app.spec.ts diff --git a/angular-standalone/base/.gitignore b/angular-standalone/base/.gitignore index 5b669df77..126473917 100644 --- a/angular-standalone/base/.gitignore +++ b/angular-standalone/base/.gitignore @@ -68,3 +68,9 @@ testem.log # System files .DS_Store Thumbs.db + +# Playwright +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/angular-standalone/base/.prettierignore b/angular-standalone/base/.prettierignore new file mode 100644 index 000000000..08d41d635 --- /dev/null +++ b/angular-standalone/base/.prettierignore @@ -0,0 +1,5 @@ +# Prettier only reads the root .gitignore, not the ones inside the native +# projects, so ignore them here to skip Capacitor's copied web build and +# Gradle's build output. +android/ +ios/ diff --git a/angular-standalone/base/.vscode/extensions.json b/angular-standalone/base/.vscode/extensions.json index 1e9202d91..2fbec7bf5 100644 --- a/angular-standalone/base/.vscode/extensions.json +++ b/angular-standalone/base/.vscode/extensions.json @@ -1,5 +1,8 @@ { - "recommendations": [ - "Webnative.webnative" - ] + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "Angular.ng-template", + "Webnative.webnative" + ] } diff --git a/angular-standalone/base/angular.json b/angular-standalone/base/angular.json index 087955fb6..c0c01d68d 100644 --- a/angular-standalone/base/angular.json +++ b/angular-standalone/base/angular.json @@ -95,20 +95,21 @@ "test": { "builder": "@angular/build:unit-test", "options": { - "tsConfig": "tsconfig.spec.json", "buildTarget": "::development", - "setupFiles": ["src/test-setup.ts"] - }, - "configurations": { - "ci": { - "watch": false - } + "runnerConfig": "vitest.config.mts", + "setupFiles": ["src/test-setup.ts"], + "tsConfig": "tsconfig.spec.json" } }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { - "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"] + "lintFilePatterns": [ + "src/**/*.ts", + "src/**/*.html", + "e2e/**/*.ts", + "playwright.config.ts" + ] } } } diff --git a/angular-standalone/base/eslint.config.js b/angular-standalone/base/eslint.config.js index 2b4e5da28..a8a8929a7 100644 --- a/angular-standalone/base/eslint.config.js +++ b/angular-standalone/base/eslint.config.js @@ -1,31 +1,45 @@ // @ts-check -const tseslint = require("typescript-eslint"); -const angular = require("angular-eslint"); +const ionic = require('@ionic/eslint-config/recommended'); +const angular = require('angular-eslint'); +const { defineConfig } = require('eslint/config'); -module.exports = tseslint.config( +module.exports = defineConfig([ { - files: ["**/*.ts"], - ignores: ["projects/**/*"], - extends: [...angular.configs.tsRecommended], + ignores: ['www/**', 'dist/**', 'coverage/**', '.angular/**', 'android/**', 'ios/**'], + }, + ionic, + { + files: ['**/*.ts'], + extends: [angular.configs.tsRecommended], processor: angular.processInlineTemplates, rules: { - "@angular-eslint/component-class-suffix": [ - "error", - { suffixes: ["Page", "Component"] }, + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'app', + style: 'camelCase', + }, ], - "@angular-eslint/component-selector": [ - "error", - { type: "element", prefix: "app", style: "kebab-case" }, + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'app', + style: 'kebab-case', + }, ], - "@angular-eslint/directive-selector": [ - "error", - { type: "attribute", prefix: "app", style: "camelCase" }, + '@angular-eslint/component-class-suffix': [ + 'error', + { + suffixes: ['Page', 'Component'], + }, ], }, }, { - files: ["**/*.html"], - extends: [...angular.configs.templateRecommended], + files: ['**/*.html'], + extends: [angular.configs.templateRecommended, angular.configs.templateAccessibility], rules: {}, - } -); + }, +]); diff --git a/angular-standalone/base/package.json b/angular-standalone/base/package.json index 5aedbe201..e328bd2e7 100644 --- a/angular-standalone/base/package.json +++ b/angular-standalone/base/package.json @@ -8,8 +8,15 @@ "start": "ng serve", "build": "ng build", "watch": "ng build --watch --configuration development", - "test": "ng test", - "lint": "ng lint" + "lint": "npm run eslint && npm run typecheck:e2e && npm run prettier -- --check", + "lint:fix": "npm run eslint -- --fix && npm run prettier -- --write", + "eslint": "ng lint --max-warnings 0", + "prettier": "prettier \"**/*.{ts,html}\"", + "typecheck:e2e": "tsc -p tsconfig.e2e.json", + "test": "npm run test:unit && npm run test:e2e", + "test:unit": "ng test --no-watch", + "test:unit:watch": "ng test --watch", + "test:e2e": "playwright test" }, "private": true, "dependencies": { @@ -30,11 +37,17 @@ "@angular/compiler-cli": "22.2.3", "@angular/language-service": "22.2.3", "@ionic/angular-toolkit": "^13.0.0", + "@ionic/eslint-config": "^0.5.0", + "@ionic/prettier-config": "^4.0.0", + "@playwright/test": "^1.64.1", + "@types/node": "^24.0.0", "angular-eslint": "22.6.0", "eslint": "^10.10.0", "jsdom": "^30.1.1", + "prettier": "^3.9.10", "typescript": "~6.0.0", "typescript-eslint": "^8.61.0", "vitest": "~5.0.5" - } + }, + "prettier": "@ionic/prettier-config" } diff --git a/angular-standalone/base/playwright.config.ts b/angular-standalone/base/playwright.config.ts new file mode 100644 index 000000000..c55d6a1af --- /dev/null +++ b/angular-standalone/base/playwright.config.ts @@ -0,0 +1,27 @@ +import { defineConfig, devices } from '@playwright/test'; + +const baseURL = 'http://localhost:4200'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + reporter: process.env.CI ? [['github'], ['html', { open: 'never' }]] : 'list', + use: { + baseURL, + trace: 'on-first-retry', + }, + projects: [ + { + name: 'Mobile Chrome', + use: { ...devices['Pixel 7'] }, + }, + ], + webServer: { + command: 'npm start -- --port 4200', + url: baseURL, + reuseExistingServer: !process.env.CI, + timeout: 120_000, + }, +}); diff --git a/angular-standalone/base/src/app/app.component.spec.ts b/angular-standalone/base/src/app/app.component.spec.ts index 118209f91..07e9f4460 100644 --- a/angular-standalone/base/src/app/app.component.spec.ts +++ b/angular-standalone/base/src/app/app.component.spec.ts @@ -1,14 +1,15 @@ import { TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; + import { AppComponent } from './app.component'; describe('AppComponent', () => { it('should create the app', async () => { await TestBed.configureTestingModule({ imports: [AppComponent], - providers: [provideRouter([])] + providers: [provideRouter([])], }).compileComponents(); - + const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app).toBeTruthy(); diff --git a/angular-standalone/base/src/environments/environment.prod.ts b/angular-standalone/base/src/environments/environment.prod.ts index 3612073bc..c9669790b 100644 --- a/angular-standalone/base/src/environments/environment.prod.ts +++ b/angular-standalone/base/src/environments/environment.prod.ts @@ -1,3 +1,3 @@ export const environment = { - production: true + production: true, }; diff --git a/angular-standalone/base/src/environments/environment.ts b/angular-standalone/base/src/environments/environment.ts index f56ff4702..66998ae9a 100644 --- a/angular-standalone/base/src/environments/environment.ts +++ b/angular-standalone/base/src/environments/environment.ts @@ -3,7 +3,7 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, }; /* diff --git a/angular-standalone/base/src/index.html b/angular-standalone/base/src/index.html index 29902c2ce..6e08086fc 100644 --- a/angular-standalone/base/src/index.html +++ b/angular-standalone/base/src/index.html @@ -1,26 +1,27 @@ - + + + + Ionic App - - - Ionic App + - + + + + - - - - + - - - - - - - - - - + + + + + + + diff --git a/angular-standalone/base/src/main.ts b/angular-standalone/base/src/main.ts index b5f19e1f3..5332fa06f 100644 --- a/angular-standalone/base/src/main.ts +++ b/angular-standalone/base/src/main.ts @@ -1,9 +1,15 @@ import { bootstrapApplication } from '@angular/platform-browser'; -import { RouteReuseStrategy, provideRouter, withComponentInputBinding, withPreloading, PreloadAllModules } from '@angular/router'; +import { + RouteReuseStrategy, + provideRouter, + withComponentInputBinding, + withPreloading, + PreloadAllModules, +} from '@angular/router'; import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular'; -import { routes } from './app/app.routes'; import { AppComponent } from './app/app.component'; +import { routes } from './app/app.routes'; bootstrapApplication(AppComponent, { providers: [ diff --git a/angular-standalone/base/tsconfig.e2e.json b/angular-standalone/base/tsconfig.e2e.json new file mode 100644 index 000000000..cb9db5a11 --- /dev/null +++ b/angular-standalone/base/tsconfig.e2e.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["e2e/**/*.ts", "playwright.config.ts"] +} diff --git a/angular-standalone/base/vitest.config.mts b/angular-standalone/base/vitest.config.mts new file mode 100644 index 000000000..a0f615ccf --- /dev/null +++ b/angular-standalone/base/vitest.config.mts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + // Angular's unit-test builder bundles each spec with the code it imports, and + // Vitest's file-system module cache can then serve a stale bundle after a + // non-spec file changes. Turn the cache off so reruns always test current code. + fsModuleCache: false, + }, +}); diff --git a/angular-standalone/official/blank/e2e/app.spec.ts b/angular-standalone/official/blank/e2e/app.spec.ts new file mode 100644 index 000000000..9a3645c1f --- /dev/null +++ b/angular-standalone/official/blank/e2e/app.spec.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@playwright/test'; + +test('visits the app root url', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('#container')).toContainText('Ready to create an app?'); +}); diff --git a/angular-standalone/official/blank/ionic.starter.json b/angular-standalone/official/blank/ionic.starter.json index 87b690f45..680603d01 100644 --- a/angular-standalone/official/blank/ionic.starter.json +++ b/angular-standalone/official/blank/ionic.starter.json @@ -7,6 +7,6 @@ "www" ], "scripts": { - "test": "npm run lint && npm run build && npm run test -- --configuration=ci" + "test": "npm run lint && npm run build && npm run test:unit && npx playwright install --with-deps chromium && npm run test:e2e" } } diff --git a/angular-standalone/official/blank/src/app/app.routes.ts b/angular-standalone/official/blank/src/app/app.routes.ts index 90671c494..09b04d5ac 100644 --- a/angular-standalone/official/blank/src/app/app.routes.ts +++ b/angular-standalone/official/blank/src/app/app.routes.ts @@ -1,4 +1,4 @@ -import { Routes } from '@angular/router'; +import type { Routes } from '@angular/router'; export const routes: Routes = [ { diff --git a/angular-standalone/official/blank/src/app/home/home.page.html b/angular-standalone/official/blank/src/app/home/home.page.html index 911cab762..dc4275c31 100644 --- a/angular-standalone/official/blank/src/app/home/home.page.html +++ b/angular-standalone/official/blank/src/app/home/home.page.html @@ -1,8 +1,6 @@ - - Blank - + Blank @@ -15,6 +13,9 @@
Ready to create an app? -

Start with Ionic UI Components

+

+ Start with Ionic + UI Components +

diff --git a/angular-standalone/official/blank/src/app/home/home.page.spec.ts b/angular-standalone/official/blank/src/app/home/home.page.spec.ts index fe8f195bc..1e9aaf9c7 100644 --- a/angular-standalone/official/blank/src/app/home/home.page.spec.ts +++ b/angular-standalone/official/blank/src/app/home/home.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { HomePage } from './home.page'; diff --git a/angular-standalone/official/list/e2e/app.spec.ts b/angular-standalone/official/list/e2e/app.spec.ts new file mode 100644 index 000000000..c53b3b061 --- /dev/null +++ b/angular-standalone/official/list/e2e/app.spec.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@playwright/test'; + +test('visits the app root url', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('ion-header').first()).toContainText('Inbox'); +}); diff --git a/angular-standalone/official/list/ionic.starter.json b/angular-standalone/official/list/ionic.starter.json index 9d399db0b..1d6c95d38 100644 --- a/angular-standalone/official/list/ionic.starter.json +++ b/angular-standalone/official/list/ionic.starter.json @@ -7,6 +7,6 @@ "www" ], "scripts": { - "test": "npm run lint && npm run build && npm run test -- --configuration=ci" + "test": "npm run lint && npm run build && npm run test:unit && npx playwright install --with-deps chromium && npm run test:e2e" } } diff --git a/angular-standalone/official/list/src/app/app.component.spec.ts b/angular-standalone/official/list/src/app/app.component.spec.ts index 9f9e2a737..17505bd46 100644 --- a/angular-standalone/official/list/src/app/app.component.spec.ts +++ b/angular-standalone/official/list/src/app/app.component.spec.ts @@ -4,11 +4,10 @@ import { provideRouter } from '@angular/router'; import { AppComponent } from './app.component'; describe('AppComponent', () => { - beforeEach(async () => { await TestBed.configureTestingModule({ imports: [AppComponent], - providers: [provideRouter([])] + providers: [provideRouter([])], }).compileComponents(); }); @@ -17,5 +16,4 @@ describe('AppComponent', () => { const app = fixture.componentInstance; expect(app).toBeTruthy(); }); - }); diff --git a/angular-standalone/official/list/src/app/app.routes.ts b/angular-standalone/official/list/src/app/app.routes.ts index 8460211db..78e26f51c 100644 --- a/angular-standalone/official/list/src/app/app.routes.ts +++ b/angular-standalone/official/list/src/app/app.routes.ts @@ -1,4 +1,4 @@ -import { Routes } from '@angular/router'; +import type { Routes } from '@angular/router'; export const routes: Routes = [ { @@ -7,8 +7,7 @@ export const routes: Routes = [ }, { path: 'message/:id', - loadComponent: () => - import('./view-message/view-message.page').then((m) => m.ViewMessagePage), + loadComponent: () => import('./view-message/view-message.page').then((m) => m.ViewMessagePage), }, { path: '', @@ -16,4 +15,3 @@ export const routes: Routes = [ pathMatch: 'full', }, ]; - diff --git a/angular-standalone/official/list/src/app/home/home.page.html b/angular-standalone/official/list/src/app/home/home.page.html index 0e49dd03e..b6f32ba9f 100644 --- a/angular-standalone/official/list/src/app/home/home.page.html +++ b/angular-standalone/official/list/src/app/home/home.page.html @@ -1,8 +1,6 @@ - - Inbox - + Inbox @@ -13,15 +11,13 @@ - - Inbox - + Inbox @for (message of messages; track message.id) { - + } diff --git a/angular-standalone/official/list/src/app/home/home.page.spec.ts b/angular-standalone/official/list/src/app/home/home.page.spec.ts index f1add0bd5..935818cff 100644 --- a/angular-standalone/official/list/src/app/home/home.page.spec.ts +++ b/angular-standalone/official/list/src/app/home/home.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { HomePage } from './home.page'; diff --git a/angular-standalone/official/list/src/app/home/home.page.ts b/angular-standalone/official/list/src/app/home/home.page.ts index ad4b65b6d..2b4a0bd78 100644 --- a/angular-standalone/official/list/src/app/home/home.page.ts +++ b/angular-standalone/official/list/src/app/home/home.page.ts @@ -1,7 +1,16 @@ import { Component, inject } from '@angular/core'; -import { RefresherCustomEvent, IonHeader, IonToolbar, IonTitle, IonContent, IonRefresher, IonRefresherContent, IonList } from '@ionic/angular'; -import { MessageComponent } from '../message/message.component'; +import type { RefresherCustomEvent } from '@ionic/angular'; +import { + IonHeader, + IonToolbar, + IonTitle, + IonContent, + IonRefresher, + IonRefresherContent, + IonList, +} from '@ionic/angular'; +import { MessageComponent } from '../message/message.component'; import { DataService } from '../services/data.service'; @Component({ @@ -14,7 +23,7 @@ export class HomePage { private data = inject(DataService); protected readonly messages = this.data.getMessages(); - refresh(ev: any) { + refresh(ev: any): void { setTimeout(() => { (ev as RefresherCustomEvent).detail.complete(); }, 3000); diff --git a/angular-standalone/official/list/src/app/message/message.component.html b/angular-standalone/official/list/src/app/message/message.component.html index b530dc791..65115a3cb 100644 --- a/angular-standalone/official/list/src/app/message/message.component.html +++ b/angular-standalone/official/list/src/app/message/message.component.html @@ -1,8 +1,5 @@ @if (message(); as message) { - +

@@ -10,23 +7,17 @@

{{ message.date }} @if (isIos) { - + }

{{ message.subject }}

- Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod - tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim - veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea - commodo consequat. Duis aute irure dolor in reprehenderit in voluptate - velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat - cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum.

diff --git a/angular-standalone/official/list/src/app/message/message.component.spec.ts b/angular-standalone/official/list/src/app/message/message.component.spec.ts index c613897f9..1310e4a2f 100644 --- a/angular-standalone/official/list/src/app/message/message.component.spec.ts +++ b/angular-standalone/official/list/src/app/message/message.component.spec.ts @@ -1,5 +1,7 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; + import { ViewMessagePage } from '../view-message/view-message.page'; import { MessageComponent } from './message.component'; @@ -11,7 +13,7 @@ describe('MessageComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [MessageComponent, ViewMessagePage], - providers: [provideRouter([])] + providers: [provideRouter([])], }).compileComponents(); fixture = TestBed.createComponent(MessageComponent); diff --git a/angular-standalone/official/list/src/app/message/message.component.ts b/angular-standalone/official/list/src/app/message/message.component.ts index 2981243b1..39bc76b5a 100644 --- a/angular-standalone/official/list/src/app/message/message.component.ts +++ b/angular-standalone/official/list/src/app/message/message.component.ts @@ -3,7 +3,8 @@ import { RouterLink } from '@angular/router'; import { Platform, IonItem, IonLabel, IonNote, IonIcon } from '@ionic/angular'; import { addIcons } from 'ionicons'; import { chevronForward } from 'ionicons/icons'; -import { Message } from '../services/data.service'; + +import type { Message } from '../services/data.service'; @Component({ selector: 'app-message', diff --git a/angular-standalone/official/list/src/app/services/data.service.ts b/angular-standalone/official/list/src/app/services/data.service.ts index 2fb24a271..8b12665d7 100644 --- a/angular-standalone/official/list/src/app/services/data.service.ts +++ b/angular-standalone/official/list/src/app/services/data.service.ts @@ -9,7 +9,7 @@ export interface Message { } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DataService { public messages: Message[] = [ @@ -18,60 +18,60 @@ export class DataService { subject: 'New event: Trip to Vegas', date: '9:32 AM', id: 0, - read: false + read: false, }, { fromName: 'Lauren Ruthford', subject: 'Long time no chat', date: '6:12 AM', id: 1, - read: false + read: false, }, { fromName: 'Jordan Firth', subject: 'Report Results', date: '4:55 AM', id: 2, - read: false + read: false, }, { fromName: 'Bill Thomas', subject: 'The situation', date: 'Yesterday', id: 3, - read: false + read: false, }, { fromName: 'Joanne Pollan', subject: 'Updated invitation: Swim lessons', date: 'Yesterday', id: 4, - read: false + read: false, }, { fromName: 'Andrea Cornerston', subject: 'Last minute ask', date: 'Yesterday', id: 5, - read: false + read: false, }, { fromName: 'Moe Chamont', subject: 'Family Calendar - Version 1', date: 'Last Week', id: 6, - read: false + read: false, }, { fromName: 'Kelly Richardson', subject: 'Placeholder Headhots', date: 'Last Week', id: 7, - read: false - } + read: false, + }, ]; - constructor() { } + constructor() {} public getMessages(): Message[] { return this.messages; diff --git a/angular-standalone/official/list/src/app/view-message/view-message.page.html b/angular-standalone/official/list/src/app/view-message/view-message.page.html index 67535357f..362c74111 100644 --- a/angular-standalone/official/list/src/app/view-message/view-message.page.html +++ b/angular-standalone/official/list/src/app/view-message/view-message.page.html @@ -1,43 +1,33 @@ - + @if (message(); as message) { - - - - -

- {{ message.fromName }} - - {{ message.date }} - -

-

To: Me

-
-
-
-

{{ message.subject }}

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod - tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim - veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea - commodo consequat. Duis aute irure dolor in reprehenderit in voluptate - velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat - cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id - est laborum. -

-
-
+ + + + +

+ {{ message.fromName }} + + {{ message.date }} + +

+

To: Me

+
+
+
+

{{ message.subject }}

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+
+
} diff --git a/angular-standalone/official/list/src/app/view-message/view-message.page.spec.ts b/angular-standalone/official/list/src/app/view-message/view-message.page.spec.ts index f433d15ba..83e2c8bf6 100644 --- a/angular-standalone/official/list/src/app/view-message/view-message.page.spec.ts +++ b/angular-standalone/official/list/src/app/view-message/view-message.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { ViewMessagePage } from './view-message.page'; diff --git a/angular-standalone/official/list/src/app/view-message/view-message.page.ts b/angular-standalone/official/list/src/app/view-message/view-message.page.ts index 5a887837a..5b64162e1 100644 --- a/angular-standalone/official/list/src/app/view-message/view-message.page.ts +++ b/angular-standalone/official/list/src/app/view-message/view-message.page.ts @@ -1,7 +1,19 @@ import { Component, computed, inject, input } from '@angular/core'; -import { Platform, IonHeader, IonToolbar, IonButtons, IonBackButton, IonContent, IonItem, IonIcon, IonLabel, IonNote } from '@ionic/angular'; +import { + Platform, + IonHeader, + IonToolbar, + IonButtons, + IonBackButton, + IonContent, + IonItem, + IonIcon, + IonLabel, + IonNote, +} from '@ionic/angular'; import { addIcons } from 'ionicons'; import { personCircle } from 'ionicons/icons'; + import { DataService } from '../services/data.service'; @Component({ diff --git a/angular-standalone/official/sidemenu/e2e/app.spec.ts b/angular-standalone/official/sidemenu/e2e/app.spec.ts new file mode 100644 index 000000000..11cd138af --- /dev/null +++ b/angular-standalone/official/sidemenu/e2e/app.spec.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@playwright/test'; + +test('visits the app root url', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('#container')).toContainText('Inbox'); +}); diff --git a/angular-standalone/official/sidemenu/ionic.starter.json b/angular-standalone/official/sidemenu/ionic.starter.json index a78ac8bb8..824dc06e5 100644 --- a/angular-standalone/official/sidemenu/ionic.starter.json +++ b/angular-standalone/official/sidemenu/ionic.starter.json @@ -7,6 +7,6 @@ "www" ], "scripts": { - "test": "npm run lint && npm run build && npm run test -- --configuration=ci" + "test": "npm run lint && npm run build && npm run test:unit && npx playwright install --with-deps chromium && npm run test:e2e" } } diff --git a/angular-standalone/official/sidemenu/src/app/app.component.html b/angular-standalone/official/sidemenu/src/app/app.component.html index eaa3ed35a..c72c7ca29 100644 --- a/angular-standalone/official/sidemenu/src/app/app.component.html +++ b/angular-standalone/official/sidemenu/src/app/app.component.html @@ -8,8 +8,19 @@ @for (p of appPages; track p; let i = $index) { - - + + {{ p.title }} diff --git a/angular-standalone/official/sidemenu/src/app/app.component.spec.ts b/angular-standalone/official/sidemenu/src/app/app.component.spec.ts index ece1ffb50..d36b25311 100644 --- a/angular-standalone/official/sidemenu/src/app/app.component.spec.ts +++ b/angular-standalone/official/sidemenu/src/app/app.component.spec.ts @@ -8,7 +8,7 @@ describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [AppComponent], - providers: [provideRouter([])] + providers: [provideRouter([])], }).compileComponents(); }); @@ -40,9 +40,7 @@ describe('AppComponent', () => { // reading the DOM attribute is flaky (FW-6264). Assert the routerLink // binding directly, which resolves synchronously. const router = TestBed.inject(Router); - const links = fixture.debugElement - .queryAll(By.directive(RouterLink)) - .map((el) => el.injector.get(RouterLink)); + const links = fixture.debugElement.queryAll(By.directive(RouterLink)).map((el) => el.injector.get(RouterLink)); expect(links.length).toEqual(6); expect(router.serializeUrl(links[0].urlTree!)).toEqual('/folder/Inbox'); expect(router.serializeUrl(links[1].urlTree!)).toEqual('/folder/Outbox'); diff --git a/angular-standalone/official/sidemenu/src/app/app.component.ts b/angular-standalone/official/sidemenu/src/app/app.component.ts index 2239afe79..9d63fb948 100644 --- a/angular-standalone/official/sidemenu/src/app/app.component.ts +++ b/angular-standalone/official/sidemenu/src/app/app.component.ts @@ -1,15 +1,59 @@ - import { Component } from '@angular/core'; import { RouterLink, RouterLinkActive } from '@angular/router'; -import { IonApp, IonSplitPane, IonMenu, IonContent, IonList, IonListHeader, IonNote, IonMenuToggle, IonItem, IonIcon, IonLabel, IonRouterOutlet, IonRouterLink } from '@ionic/angular'; +import { + IonApp, + IonSplitPane, + IonMenu, + IonContent, + IonList, + IonListHeader, + IonNote, + IonMenuToggle, + IonItem, + IonIcon, + IonLabel, + IonRouterOutlet, + IonRouterLink, +} from '@ionic/angular'; import { addIcons } from 'ionicons'; -import { mailOutline, mailSharp, paperPlaneOutline, paperPlaneSharp, heartOutline, heartSharp, archiveOutline, archiveSharp, trashOutline, trashSharp, warningOutline, warningSharp, bookmarkOutline, bookmarkSharp } from 'ionicons/icons'; +import { + mailOutline, + mailSharp, + paperPlaneOutline, + paperPlaneSharp, + heartOutline, + heartSharp, + archiveOutline, + archiveSharp, + trashOutline, + trashSharp, + warningOutline, + warningSharp, + bookmarkOutline, + bookmarkSharp, +} from 'ionicons/icons'; @Component({ selector: 'app-root', templateUrl: 'app.component.html', styleUrls: ['app.component.scss'], - imports: [RouterLink, RouterLinkActive, IonApp, IonSplitPane, IonMenu, IonContent, IonList, IonListHeader, IonNote, IonMenuToggle, IonItem, IonIcon, IonLabel, IonRouterLink, IonRouterOutlet], + imports: [ + RouterLink, + RouterLinkActive, + IonApp, + IonSplitPane, + IonMenu, + IonContent, + IonList, + IonListHeader, + IonNote, + IonMenuToggle, + IonItem, + IonIcon, + IonLabel, + IonRouterLink, + IonRouterOutlet, + ], }) export class AppComponent { protected readonly appPages = [ @@ -22,6 +66,21 @@ export class AppComponent { ]; protected readonly labels = ['Family', 'Friends', 'Notes', 'Work', 'Travel', 'Reminders']; constructor() { - addIcons({ mailOutline, mailSharp, paperPlaneOutline, paperPlaneSharp, heartOutline, heartSharp, archiveOutline, archiveSharp, trashOutline, trashSharp, warningOutline, warningSharp, bookmarkOutline, bookmarkSharp }); + addIcons({ + mailOutline, + mailSharp, + paperPlaneOutline, + paperPlaneSharp, + heartOutline, + heartSharp, + archiveOutline, + archiveSharp, + trashOutline, + trashSharp, + warningOutline, + warningSharp, + bookmarkOutline, + bookmarkSharp, + }); } } diff --git a/angular-standalone/official/sidemenu/src/app/app.routes.ts b/angular-standalone/official/sidemenu/src/app/app.routes.ts index 0679d47bb..e8165c027 100644 --- a/angular-standalone/official/sidemenu/src/app/app.routes.ts +++ b/angular-standalone/official/sidemenu/src/app/app.routes.ts @@ -1,4 +1,4 @@ -import { Routes } from '@angular/router'; +import type { Routes } from '@angular/router'; export const routes: Routes = [ { @@ -8,7 +8,6 @@ export const routes: Routes = [ }, { path: 'folder/:folder', - loadComponent: () => - import('./folder/folder.page').then((m) => m.FolderPage), + loadComponent: () => import('./folder/folder.page').then((m) => m.FolderPage), }, ]; diff --git a/angular-standalone/official/sidemenu/src/app/folder/folder.page.html b/angular-standalone/official/sidemenu/src/app/folder/folder.page.html index 9a96665b6..f0a0d83f1 100644 --- a/angular-standalone/official/sidemenu/src/app/folder/folder.page.html +++ b/angular-standalone/official/sidemenu/src/app/folder/folder.page.html @@ -16,6 +16,9 @@
{{ folder() }} -

Explore UI Components

+

+ Explore + UI Components +

diff --git a/angular-standalone/official/sidemenu/src/app/folder/folder.page.spec.ts b/angular-standalone/official/sidemenu/src/app/folder/folder.page.spec.ts index 184d3c02d..f7805d8be 100644 --- a/angular-standalone/official/sidemenu/src/app/folder/folder.page.spec.ts +++ b/angular-standalone/official/sidemenu/src/app/folder/folder.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { FolderPage } from './folder.page'; @@ -10,7 +11,7 @@ describe('FolderPage', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [FolderPage], - providers: [provideRouter([])] + providers: [provideRouter([])], }).compileComponents(); fixture = TestBed.createComponent(FolderPage); diff --git a/angular-standalone/official/tabs/e2e/app.spec.ts b/angular-standalone/official/tabs/e2e/app.spec.ts new file mode 100644 index 000000000..338de5e3e --- /dev/null +++ b/angular-standalone/official/tabs/e2e/app.spec.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@playwright/test'; + +test('visits the app root url', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('ion-content')).toContainText('Tab 1 page'); +}); diff --git a/angular-standalone/official/tabs/ionic.starter.json b/angular-standalone/official/tabs/ionic.starter.json index 8c29cbd27..8088c9a9a 100644 --- a/angular-standalone/official/tabs/ionic.starter.json +++ b/angular-standalone/official/tabs/ionic.starter.json @@ -7,6 +7,6 @@ "www" ], "scripts": { - "test": "npm run lint && npm run build && npm run test -- --configuration=ci" + "test": "npm run lint && npm run build && npm run test:unit && npx playwright install --with-deps chromium && npm run test:e2e" } } diff --git a/angular-standalone/official/tabs/src/app/app.routes.ts b/angular-standalone/official/tabs/src/app/app.routes.ts index 8e70dff06..dd6f5c143 100644 --- a/angular-standalone/official/tabs/src/app/app.routes.ts +++ b/angular-standalone/official/tabs/src/app/app.routes.ts @@ -1,4 +1,4 @@ -import { Routes } from '@angular/router'; +import type { Routes } from '@angular/router'; export const routes: Routes = [ { diff --git a/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.html b/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.html index c5e53d0f9..05b41318a 100644 --- a/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.html +++ b/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.html @@ -2,11 +2,6 @@ {{ name() }}

Explore - UI Components + UI Components

diff --git a/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.spec.ts b/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.spec.ts index aa956d9b9..c20dca47f 100644 --- a/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.spec.ts +++ b/angular-standalone/official/tabs/src/app/explore-container/explore-container.component.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { ExploreContainerComponent } from './explore-container.component'; diff --git a/angular-standalone/official/tabs/src/app/tab1/tab1.page.html b/angular-standalone/official/tabs/src/app/tab1/tab1.page.html index 22e11e475..8044cba68 100644 --- a/angular-standalone/official/tabs/src/app/tab1/tab1.page.html +++ b/angular-standalone/official/tabs/src/app/tab1/tab1.page.html @@ -1,8 +1,6 @@ - - Tab 1 - + Tab 1 diff --git a/angular-standalone/official/tabs/src/app/tab1/tab1.page.spec.ts b/angular-standalone/official/tabs/src/app/tab1/tab1.page.spec.ts index fcc00f940..fbaa3c046 100644 --- a/angular-standalone/official/tabs/src/app/tab1/tab1.page.spec.ts +++ b/angular-standalone/official/tabs/src/app/tab1/tab1.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { Tab1Page } from './tab1.page'; diff --git a/angular-standalone/official/tabs/src/app/tab1/tab1.page.ts b/angular-standalone/official/tabs/src/app/tab1/tab1.page.ts index 677ad98da..cf4e64a17 100644 --- a/angular-standalone/official/tabs/src/app/tab1/tab1.page.ts +++ b/angular-standalone/official/tabs/src/app/tab1/tab1.page.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular'; + import { ExploreContainerComponent } from '../explore-container/explore-container.component'; @Component({ diff --git a/angular-standalone/official/tabs/src/app/tab2/tab2.page.html b/angular-standalone/official/tabs/src/app/tab2/tab2.page.html index 38b153ec4..287415bd0 100644 --- a/angular-standalone/official/tabs/src/app/tab2/tab2.page.html +++ b/angular-standalone/official/tabs/src/app/tab2/tab2.page.html @@ -1,8 +1,6 @@ - - Tab 2 - + Tab 2 diff --git a/angular-standalone/official/tabs/src/app/tab2/tab2.page.spec.ts b/angular-standalone/official/tabs/src/app/tab2/tab2.page.spec.ts index 92c0cac4a..06fda82c1 100644 --- a/angular-standalone/official/tabs/src/app/tab2/tab2.page.spec.ts +++ b/angular-standalone/official/tabs/src/app/tab2/tab2.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { Tab2Page } from './tab2.page'; diff --git a/angular-standalone/official/tabs/src/app/tab2/tab2.page.ts b/angular-standalone/official/tabs/src/app/tab2/tab2.page.ts index 2110b9efd..ebd25b359 100644 --- a/angular-standalone/official/tabs/src/app/tab2/tab2.page.ts +++ b/angular-standalone/official/tabs/src/app/tab2/tab2.page.ts @@ -1,15 +1,14 @@ import { Component } from '@angular/core'; import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular'; + import { ExploreContainerComponent } from '../explore-container/explore-container.component'; @Component({ selector: 'app-tab2', templateUrl: 'tab2.page.html', styleUrls: ['tab2.page.scss'], - imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent] + imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent], }) export class Tab2Page { - constructor() {} - } diff --git a/angular-standalone/official/tabs/src/app/tab3/tab3.page.html b/angular-standalone/official/tabs/src/app/tab3/tab3.page.html index 222333d58..89458ab9e 100644 --- a/angular-standalone/official/tabs/src/app/tab3/tab3.page.html +++ b/angular-standalone/official/tabs/src/app/tab3/tab3.page.html @@ -1,8 +1,6 @@ - - Tab 3 - + Tab 3 diff --git a/angular-standalone/official/tabs/src/app/tab3/tab3.page.spec.ts b/angular-standalone/official/tabs/src/app/tab3/tab3.page.spec.ts index a03da9934..8e306c2f3 100644 --- a/angular-standalone/official/tabs/src/app/tab3/tab3.page.spec.ts +++ b/angular-standalone/official/tabs/src/app/tab3/tab3.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { Tab3Page } from './tab3.page'; diff --git a/angular-standalone/official/tabs/src/app/tab3/tab3.page.ts b/angular-standalone/official/tabs/src/app/tab3/tab3.page.ts index e6d434b54..cf49acd23 100644 --- a/angular-standalone/official/tabs/src/app/tab3/tab3.page.ts +++ b/angular-standalone/official/tabs/src/app/tab3/tab3.page.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular'; + import { ExploreContainerComponent } from '../explore-container/explore-container.component'; @Component({ diff --git a/angular-standalone/official/tabs/src/app/tabs/tabs.page.spec.ts b/angular-standalone/official/tabs/src/app/tabs/tabs.page.spec.ts index 2ebc97e2d..f1df7b928 100644 --- a/angular-standalone/official/tabs/src/app/tabs/tabs.page.spec.ts +++ b/angular-standalone/official/tabs/src/app/tabs/tabs.page.spec.ts @@ -1,4 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import type { ComponentFixture } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { provideRouter } from '@angular/router'; import { TabsPage } from './tabs.page'; @@ -10,7 +11,7 @@ describe('TabsPage', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [TabsPage], - providers: [provideRouter([])] + providers: [provideRouter([])], }).compileComponents(); }); diff --git a/angular-standalone/official/tabs/src/app/tabs/tabs.routes.ts b/angular-standalone/official/tabs/src/app/tabs/tabs.routes.ts index 15ba9e57a..adceab94b 100644 --- a/angular-standalone/official/tabs/src/app/tabs/tabs.routes.ts +++ b/angular-standalone/official/tabs/src/app/tabs/tabs.routes.ts @@ -1,4 +1,5 @@ -import { Routes } from '@angular/router'; +import type { Routes } from '@angular/router'; + import { TabsPage } from './tabs.page'; export const routes: Routes = [ @@ -8,18 +9,15 @@ export const routes: Routes = [ children: [ { path: 'tab1', - loadComponent: () => - import('../tab1/tab1.page').then((m) => m.Tab1Page), + loadComponent: () => import('../tab1/tab1.page').then((m) => m.Tab1Page), }, { path: 'tab2', - loadComponent: () => - import('../tab2/tab2.page').then((m) => m.Tab2Page), + loadComponent: () => import('../tab2/tab2.page').then((m) => m.Tab2Page), }, { path: 'tab3', - loadComponent: () => - import('../tab3/tab3.page').then((m) => m.Tab3Page), + loadComponent: () => import('../tab3/tab3.page').then((m) => m.Tab3Page), }, { path: '',