mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
b857aafcb9
Migrate formatting to prettier for router from clang-format PR Close #54318
216 lines
6.2 KiB
TypeScript
216 lines
6.2 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {DOCUMENT} from '@angular/common';
|
|
import {provideLocationMocks} from '@angular/common/testing';
|
|
import {Component, inject, Inject, Injectable, NgModule} from '@angular/core';
|
|
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
|
import {fakeAsync, TestBed, tick} from '@angular/core/testing';
|
|
import {
|
|
ActivatedRoute,
|
|
provideRouter,
|
|
ResolveFn,
|
|
Router,
|
|
RouterModule,
|
|
RouterStateSnapshot,
|
|
TitleStrategy,
|
|
withRouterConfig,
|
|
} from '@angular/router';
|
|
import {RouterTestingHarness} from '@angular/router/testing';
|
|
|
|
describe('title strategy', () => {
|
|
describe('DefaultTitleStrategy', () => {
|
|
let router: Router;
|
|
let document: Document;
|
|
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule({
|
|
imports: [TestModule],
|
|
providers: [
|
|
provideLocationMocks(),
|
|
provideRouter([], withRouterConfig({paramsInheritanceStrategy: 'always'})),
|
|
],
|
|
});
|
|
router = TestBed.inject(Router);
|
|
document = TestBed.inject(DOCUMENT);
|
|
});
|
|
|
|
it('sets page title from data', fakeAsync(() => {
|
|
router.resetConfig([{path: 'home', title: 'My Application', component: BlankCmp}]);
|
|
router.navigateByUrl('home');
|
|
tick();
|
|
expect(document.title).toBe('My Application');
|
|
}));
|
|
|
|
it('sets page title from resolved data', fakeAsync(() => {
|
|
router.resetConfig([{path: 'home', title: TitleResolver, component: BlankCmp}]);
|
|
router.navigateByUrl('home');
|
|
tick();
|
|
expect(document.title).toBe('resolved title');
|
|
}));
|
|
|
|
it('sets page title from resolved data function', fakeAsync(() => {
|
|
router.resetConfig([{path: 'home', title: () => 'resolved title', component: BlankCmp}]);
|
|
router.navigateByUrl('home');
|
|
tick();
|
|
expect(document.title).toBe('resolved title');
|
|
}));
|
|
|
|
it('sets title with child routes', fakeAsync(() => {
|
|
router.resetConfig([
|
|
{
|
|
path: 'home',
|
|
title: 'My Application',
|
|
children: [{path: '', title: 'child title', component: BlankCmp}],
|
|
},
|
|
]);
|
|
router.navigateByUrl('home');
|
|
tick();
|
|
expect(document.title).toBe('child title');
|
|
}));
|
|
|
|
it('sets title with child routes and named outlets', fakeAsync(() => {
|
|
router.resetConfig([
|
|
{
|
|
path: 'home',
|
|
title: 'My Application',
|
|
children: [
|
|
{path: '', title: 'child title', component: BlankCmp},
|
|
{path: '', outlet: 'childaux', title: 'child aux title', component: BlankCmp},
|
|
],
|
|
},
|
|
{path: 'compose', component: BlankCmp, outlet: 'aux', title: 'compose'},
|
|
]);
|
|
router.navigateByUrl('home(aux:compose)');
|
|
tick();
|
|
expect(document.title).toBe('child title');
|
|
}));
|
|
|
|
it('sets page title with inherited params', fakeAsync(() => {
|
|
router.resetConfig([
|
|
{
|
|
path: 'home',
|
|
title: 'My Application',
|
|
children: [
|
|
{
|
|
path: '',
|
|
title: TitleResolver,
|
|
component: BlankCmp,
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
router.navigateByUrl('home');
|
|
tick();
|
|
expect(document.title).toBe('resolved title');
|
|
}));
|
|
|
|
it('can get the title from the ActivatedRouteSnapshot', async () => {
|
|
router.resetConfig([
|
|
{
|
|
path: 'home',
|
|
title: 'My Application',
|
|
component: BlankCmp,
|
|
},
|
|
]);
|
|
await router.navigateByUrl('home');
|
|
expect(router.routerState.snapshot.root.firstChild!.title).toEqual('My Application');
|
|
});
|
|
|
|
it('pushes updates through the title observable', async () => {
|
|
@Component({template: '', standalone: true})
|
|
class HomeCmp {
|
|
private readonly title$ = inject(ActivatedRoute).title.pipe(takeUntilDestroyed());
|
|
title?: string;
|
|
|
|
constructor() {
|
|
this.title$.subscribe((v) => (this.title = v));
|
|
}
|
|
}
|
|
const titleResolver: ResolveFn<string> = (route) => route.queryParams['id'];
|
|
router.resetConfig([
|
|
{
|
|
path: 'home',
|
|
title: titleResolver,
|
|
component: HomeCmp,
|
|
runGuardsAndResolvers: 'paramsOrQueryParamsChange',
|
|
},
|
|
]);
|
|
|
|
const harness = await RouterTestingHarness.create();
|
|
const homeCmp = await harness.navigateByUrl('/home?id=1', HomeCmp);
|
|
expect(homeCmp.title).toEqual('1');
|
|
await harness.navigateByUrl('home?id=2');
|
|
expect(homeCmp.title).toEqual('2');
|
|
});
|
|
});
|
|
|
|
describe('custom strategies', () => {
|
|
it('overriding the setTitle method', fakeAsync(() => {
|
|
@Injectable({providedIn: 'root'})
|
|
class TemplatePageTitleStrategy extends TitleStrategy {
|
|
constructor(@Inject(DOCUMENT) private readonly document: Document) {
|
|
super();
|
|
}
|
|
|
|
// Example of how setTitle could implement a template for the title
|
|
override updateTitle(state: RouterStateSnapshot) {
|
|
const title = this.buildTitle(state);
|
|
this.document.title = `My Application | ${title}`;
|
|
}
|
|
}
|
|
|
|
TestBed.configureTestingModule({
|
|
imports: [TestModule],
|
|
providers: [
|
|
provideLocationMocks(),
|
|
provideRouter([]),
|
|
{provide: TitleStrategy, useClass: TemplatePageTitleStrategy},
|
|
],
|
|
});
|
|
const router = TestBed.inject(Router);
|
|
const document = TestBed.inject(DOCUMENT);
|
|
router.resetConfig([
|
|
{
|
|
path: 'home',
|
|
title: 'Home',
|
|
children: [{path: '', title: 'Child', component: BlankCmp}],
|
|
},
|
|
]);
|
|
|
|
router.navigateByUrl('home');
|
|
tick();
|
|
expect(document.title).toEqual('My Application | Child');
|
|
}));
|
|
});
|
|
});
|
|
|
|
@Component({template: ''})
|
|
export class BlankCmp {}
|
|
|
|
@Component({
|
|
template: `
|
|
<router-outlet></router-outlet>
|
|
<router-outlet name="aux"></router-outlet>
|
|
`,
|
|
})
|
|
export class RootCmp {}
|
|
|
|
@NgModule({
|
|
declarations: [BlankCmp],
|
|
imports: [RouterModule.forRoot([])],
|
|
})
|
|
export class TestModule {}
|
|
|
|
@Injectable({providedIn: 'root'})
|
|
export class TitleResolver {
|
|
resolve() {
|
|
return 'resolved title';
|
|
}
|
|
}
|