test(angular): add a landing page to go between lazy and standalone apps (#30286)

## What is the new behavior?
Adds a landing page to the Angular test app to make it easier to get to
and debug standalone.

## Does this introduce a breaking change?
- [ ] Yes
- [x] No

Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:
Brandy Smith
2025-03-26 16:55:04 -04:00
committed by GitHub
parent ac6e6a0317
commit 0893703769
15 changed files with 487 additions and 171 deletions

View File

@ -1,28 +0,0 @@
import { APP_ID, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
export function ionicConfigFactory(): any {
const isLazy = isBrowser && window.location.href.includes('lazy');
return isLazy ? { keyboardHeight: 12345 } : {};
}
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
IonicModule.forRoot(ionicConfigFactory()),
],
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
{ provide: APP_ID, useValue: 'serverApp' },
],
bootstrap: [AppComponent],
})
export class AppModule {}

View File

@ -327,7 +327,7 @@ describe('Tabs', () => {
cy.get('ion-title').should('contain.text', 'Test App');
cy.get('ion-item').contains('Tabs test').click();
cy.get('ion-item').contains('Tabs Test').click();
cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1');

View File

@ -0,0 +1,16 @@
<ion-header>
<ion-toolbar>
<ion-title>Test App - Angular {{ angularVersion.major }} </ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item routerLink="/lazy">
<ion-label>Go to Lazy App</ion-label>
</ion-item>
<ion-item routerLink="/standalone">
<ion-label>Go to Standalone App</ion-label>
</ion-item>
</ion-list>
</ion-content>

View File

@ -0,0 +1,13 @@
import { Component, VERSION } from '@angular/core';
@Component({
selector: 'app-landing',
templateUrl: './app-landing.component.html',
standalone: false
})
export class AppLandingComponent {
angularVersion = VERSION;
constructor() {}
}

View File

@ -1,30 +1,29 @@
import { APP_ID, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouteReuseStrategy } from '@angular/router';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { AppLandingComponent } from './app-landing/app-landing.component';
const isLazy = window.location.href.includes('lazy');
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
const imports = [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule,
];
if (isLazy) {
imports.push(IonicModule.forRoot({ keyboardHeight: 12345 }));
export function ionicConfigFactory(): any {
const isLazy = isBrowser && window.location.href.includes('lazy');
return isLazy ? { keyboardHeight: 12345 } : {};
}
@NgModule({
declarations: [
AppComponent,
declarations: [AppComponent, AppLandingComponent],
imports: [
BrowserModule,
AppRoutingModule,
IonicModule.forRoot(ionicConfigFactory()),
],
imports,
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
{ provide: APP_ID, useValue: 'serverApp' },
],
bootstrap: [AppComponent]
bootstrap: [AppComponent],
})
export class AppModule {}

View File

@ -1,16 +1,18 @@
import { Routes } from '@angular/router';
import { AppLandingComponent } from './app-landing/app-landing.component';
export const routes: Routes = [
{
path: '',
pathMatch: 'full',
/**
* Omit the slash at the beginning
* so query params are preserved.
* https://github.com/angular/angular/issues/13315#issuecomment-427254639
*/
redirectTo: 'lazy'
component: AppLandingComponent
},
{ path: 'lazy', loadChildren: () => import('./lazy/app-lazy/app.module').then(m => m.AppModule) },
{ path: 'standalone', loadChildren: () => import('./standalone/app-standalone/app.routes').then(m => m.routes) }
{
path: 'lazy',
loadChildren: () => import('./lazy/app-lazy/app.module').then(m => m.AppModule)
},
{
path: 'standalone',
loadChildren: () => import('./standalone/app-standalone/app.routes').then(m => m.routes)
}
];

View File

@ -1,7 +1,10 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
<ion-title>
Test App - Angular {{ angularVersion.major }}
Test App - Angular {{ angularVersion.major }} - Lazy
</ion-title>
</ion-toolbar>
</ion-header>
@ -9,37 +12,37 @@
<ion-list>
<ion-item routerLink="/lazy/alerts" [routerAnimation]="routerAnimation">
<ion-label>
Alerts test
Alerts Test
</ion-label>
</ion-item>
<ion-item routerLink="/lazy/inputs">
<ion-label>
Inputs test
Inputs Test
</ion-label>
</ion-item>
<ion-item routerLink="/lazy/form">
<ion-label>
Form test
Form Test
</ion-label>
</ion-item>
<ion-item routerLink="/lazy/modals">
<ion-label>
Modals test
Modals Test
</ion-label>
</ion-item>
<ion-item routerLink="/lazy/router-link">
<ion-label>
Router link test
Router link Test
</ion-label>
</ion-item>
<ion-item routerLink="/lazy/tabs">
<ion-label>
Tabs test
Tabs Test
</ion-label>
</ion-item>
<ion-item routerLink="/lazy/tabs-basic">
<ion-label>
Basic Tabs test
Basic Tabs Test
</ion-label>
</ion-item>
<ion-item routerLink="/lazy/nested-outlet/page">

View File

@ -6,6 +6,7 @@ export const routes: Routes = [
path: '',
component: AppComponent,
children: [
{ path: '', loadComponent: () => import('../home-page/home-page.component').then(c => c.HomePageComponent) },
{ path: 'menu-controller', loadComponent: () => import('../menu-controller/menu-controller.component').then(c => c.MenuControllerComponent) },
{ path: 'action-sheet-controller', loadComponent: () => import('../action-sheet-controller/action-sheet-controller.component').then(c => c.ActionSheetControllerComponent) },
{ path: 'popover', loadComponent: () => import('../popover/popover.component').then(c => c.PopoverComponent) },
@ -18,6 +19,14 @@ export const routes: Routes = [
{ path: 'overlay-controllers', loadComponent: () => import('../overlay-controllers/overlay-controllers.component').then(c => c.OverlayControllersComponent) },
{ path: 'button', loadComponent: () => import('../button/button.component').then(c => c.ButtonComponent) },
{ path: 'icon', loadComponent: () => import('../icon/icon.component').then(c => c.IconComponent) },
{ path: 'split-pane', redirectTo: '/standalone/split-pane/inbox', pathMatch: 'full' },
{
path: 'split-pane',
loadComponent: () => import('../split-pane/split-pane.component').then(c => c.SplitPaneComponent),
children: [
{ path: ':id', loadComponent: () => import('../split-pane/split-pane-page.component').then(c => c.SplitPanePageComponent) },
]
},
{ path: 'tabs', redirectTo: '/standalone/tabs/tab-one', pathMatch: 'full' },
{
path: 'tabs',

View File

@ -0,0 +1,166 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
<ion-title>
Test App - Angular {{ angularVersion.major }} - Standalone
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-list-header>
<ion-label>Components</ion-label>
</ion-list-header>
<ion-item routerLink="/standalone/back-button">
<ion-label>
Back Button Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/button">
<ion-label>
Button Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/icon">
<ion-label>
Icon Test
</ion-label>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>Navigation</ion-label>
</ion-list-header>
<ion-item routerLink="/standalone/nav">
<ion-label>
Nav Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/router-link">
<ion-label>
Router Link Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/router-outlet">
<ion-label>
Router Outlet Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/split-pane">
<ion-label>
Split Pane Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/tabs">
<ion-label>
Tabs Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/tabs-basic">
<ion-label>
Tabs Basic Test
</ion-label>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>Overlays</ion-label>
</ion-list-header>
<ion-item routerLink="/standalone/action-sheet-controller">
<ion-label>
Action Sheet Controller Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/menu-controller">
<ion-label>
Menu Controller Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/modal">
<ion-label>
Modal Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/overlay-controllers">
<ion-label>
Overlay Controllers Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/popover">
<ion-label>
Popover Test
</ion-label>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>Value Accessors</ion-label>
</ion-list-header>
<ion-item routerLink="/standalone/value-accessors/checkbox">
<ion-label>
Checkbox Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/datetime">
<ion-label>
Datetime Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/input">
<ion-label>
Input Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/radio-group">
<ion-label>
Radio Group Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/range">
<ion-label>
Range Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/searchbar">
<ion-label>
Searchbar Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/segment">
<ion-label>
Segment Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/select">
<ion-label>
Select Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/textarea">
<ion-label>
Textarea Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/value-accessors/toggle">
<ion-label>
Toggle Test
</ion-label>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>
<ion-label>Miscellaneous</ion-label>
</ion-list-header>
<ion-item routerLink="/standalone/providers">
<ion-label>
Providers Test
</ion-label>
</ion-item>
</ion-list>
</ion-content>

View File

@ -0,0 +1,15 @@
import { Component, VERSION } from '@angular/core';
import { RouterModule } from '@angular/router';
import { IonBackButton, IonButtons, IonContent, IonLabel, IonList, IonListHeader, IonHeader, IonItem, IonRouterLink, IonTitle, IonToolbar } from '@ionic/angular/standalone';
@Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
standalone: true,
imports: [ IonBackButton, IonButtons, IonContent, IonLabel, IonList, IonHeader, IonListHeader, IonItem, IonRouterLink, IonTitle, IonToolbar, RouterModule ]
})
export class HomePageComponent {
angularVersion = VERSION;
constructor() {}
}

View File

@ -0,0 +1,23 @@
<ion-header [translucent]="true">
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>{{ folder }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">{{ folder }}</ion-title>
</ion-toolbar>
</ion-header>
<div id="container">
<ion-button (click)="onClick('one')">Button One</ion-button>
<ion-button (click)="onClick('two')">Button Two</ion-button>
<ion-button (click)="onClick('three')">Button Three</ion-button>
<ion-button (click)="onClick('four')">Button Four</ion-button>
</div>
</ion-content>

View File

@ -0,0 +1,24 @@
import { Component, inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonTitle, IonToolbar } from '@ionic/angular/standalone';
@Component({
selector: 'app-split-pane-page',
templateUrl: './split-pane-page.component.html',
imports: [ IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonTitle, IonToolbar ],
standalone: true,
})
export class SplitPanePageComponent implements OnInit {
public folder!: string;
private activatedRoute = inject(ActivatedRoute);
constructor() {}
ngOnInit() {
this.folder = this.activatedRoute.snapshot.paramMap.get('id') as string;
}
onClick(val: string) {
console.log(val);
}
}

View File

@ -0,0 +1,3 @@
ion-item.selected {
--background: rgb(var(--ion-color-primary-rgb, 0, 84, 233), 0.14);
}

View File

@ -0,0 +1,22 @@
<ion-split-pane contentId="main-content" when="xs">
<ion-menu contentId="main-content" type="overlay">
<ion-content>
<ion-list id="inbox-list">
<ion-list-header>Inbox</ion-list-header>
<ion-menu-toggle auto-hide="false" *ngFor="let p of appPages; let i = index">
<ion-item
routerDirection="root"
[routerLink]="[p.url]"
lines="none"
detail="false"
routerLinkActive="selected"
>
<ion-label>{{ p.title }}</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outlet id="main-content"></ion-router-outlet>
</ion-split-pane>

View File

@ -0,0 +1,49 @@
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive } from '@angular/router';
import {
IonContent,
IonItem,
IonLabel,
IonList,
IonListHeader,
IonMenu,
IonMenuToggle,
IonRouterLink,
IonRouterOutlet,
IonSplitPane
} from '@ionic/angular/standalone';
@Component({
selector: 'app-split-pane',
templateUrl: 'split-pane.component.html',
styleUrls: ['split-pane.component.css'],
standalone: true,
imports: [
CommonModule,
IonContent,
IonItem,
IonLabel,
IonList,
IonListHeader,
IonMenu,
IonMenuToggle,
IonRouterLink,
IonRouterOutlet,
IonSplitPane,
RouterLink,
RouterLinkActive,
],
})
export class SplitPaneComponent {
public appPages = [
{ title: 'Inbox', url: '/standalone/split-pane/inbox' },
{ title: 'Outbox', url: '/standalone/split-pane/outbox' },
{ title: 'Favorites', url: '/standalone/split-pane/favorites' },
{ title: 'Archived', url: '/standalone/split-pane/archived' },
{ title: 'Trash', url: '/standalone/split-pane/trash' },
{ title: 'Spam', url: '/standalone/split-pane/spam'}
];
constructor() { }
}