refactor(router): Update tests to not use deprecated string tokens (#60378)

This replaces string tokens in the router tests with functional guads.

PR Close #60378
This commit is contained in:
Andrew Scott
2025-03-13 15:18:15 -07:00
committed by Jessica Janiuk
parent c57951d58f
commit 0142ae1c8e
13 changed files with 418 additions and 561 deletions
+35 -29
View File
@@ -6,11 +6,10 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {EnvironmentInjector, inject, Injectable, NgModuleRef} from '@angular/core';
import {EnvironmentInjector, inject, Injectable} from '@angular/core';
import {fakeAsync, TestBed, tick} from '@angular/core/testing';
import {provideRouter, withRouterConfig} from '@angular/router';
import {firstValueFrom, Observable, of} from 'rxjs';
import {delay, map, tap} from 'rxjs/operators';
import {Observable, of} from 'rxjs';
import {delay, tap} from 'rxjs/operators';
import {Route, Routes} from '../src/models';
import {recognize} from '../src/recognize';
@@ -584,24 +583,28 @@ describe('redirects', () => {
let passedUrlSegments: UrlSegment[];
const guard = {
canLoad: (route: Route, urlSegments: UrlSegment[]) => {
passedUrlSegments = urlSegments;
return true;
},
};
const injector = {get: (token: any) => (token === 'guard' ? guard : {injector})};
const config = [
{
path: 'a',
component: ComponentA,
canLoad: ['guard'],
canLoad: [
(route: Route, urlSegments: UrlSegment[]) => {
passedUrlSegments = urlSegments;
return true;
},
],
loadChildren: jasmine.createSpy('children'),
},
];
recognize(<any>injector, <any>loader, null, config, tree('a/b'), serializer).subscribe(
recognize(
TestBed.inject(EnvironmentInjector),
<any>loader,
null,
config,
tree('a/b'),
serializer,
).subscribe(
({tree: r}) => {
expectTreeToBe(r, '/a/b');
expect(passedUrlSegments.length).toBe(2);
@@ -710,7 +713,7 @@ describe('redirects', () => {
});
});
it('should not load the configuration of a wildcard route if there is a match', () => {
it('should not load the configuration of a wildcard route if there is a match', async () => {
const loadedConfig = {
routes: [{path: '', component: ComponentB}],
injector: TestBed.inject(EnvironmentInjector),
@@ -727,20 +730,23 @@ describe('redirects', () => {
{path: '**', loadChildren: jasmine.createSpy('children')},
];
recognize(
TestBed.inject(EnvironmentInjector),
<any>loader,
null,
config,
tree(''),
serializer,
).forEach(({tree: r}) => {
expect(loader.loadChildren.calls.count()).toEqual(1);
expect(loader.loadChildren.calls.first().args).not.toContain(
jasmine.objectContaining({
loadChildren: jasmine.createSpy('children'),
}),
);
await new Promise<void>((resolve) => {
recognize(
TestBed.inject(EnvironmentInjector),
<any>loader,
null,
config,
tree(''),
serializer,
).forEach(({tree: r}) => {
expect(loader.loadChildren.calls.count()).toEqual(1);
expect(loader.loadChildren.calls.first().args).not.toContain(
jasmine.objectContaining({
loadChildren: jasmine.createSpy('children'),
}),
);
resolve();
});
});
});
@@ -70,7 +70,6 @@ describe('`restoredState#ɵrouterPageId`', () => {
TestBed.configureTestingModule({
imports: [TestModule],
providers: [
{provide: 'alwaysFalse', useValue: (a: any) => false},
{provide: Location, useClass: SpyLocation},
provideRouter(
[
@@ -106,7 +105,7 @@ describe('`restoredState#ɵrouterPageId`', () => {
{
path: 'loaded',
loadChildren: () => of(ModuleWithSimpleCmpAsRoute),
canLoad: ['alwaysFalse'],
canLoad: [() => false],
},
],
withRouterConfig({
-8
View File
@@ -23,14 +23,6 @@ export class Logger {
}
}
export function provideTokenLogger(token: string, returnValue = true as boolean | UrlTree) {
return {
provide: token,
useFactory: (logger: Logger) => () => (logger.add(token), returnValue),
deps: [Logger],
};
}
export declare type ARSArgs = {
url?: UrlSegment[];
params?: Params;
@@ -34,18 +34,7 @@ export function duplicateInFlightNavigationsIntegrationSuite() {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{
provide: 'in1Second',
useValue: (c: any, a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => {
let res: any = null;
const p = new Promise((_) => (res = _));
setTimeout(() => res(true), 1000);
return p;
},
},
RedirectingGuard,
],
providers: [RedirectingGuard],
});
});
@@ -54,7 +43,13 @@ export function duplicateInFlightNavigationsIntegrationSuite() {
const location = TestBed.inject(Location);
const fixture = createRoot(router, RootCmp);
router.resetConfig([{path: 'simple', component: SimpleCmp, canActivate: ['in1Second']}]);
router.resetConfig([
{
path: 'simple',
component: SimpleCmp,
canActivate: [() => new Promise((resolve) => setTimeout(resolve, 1000))],
},
]);
// Trigger two location changes to the same URL.
// Because of the guard the order will look as follows:
@@ -162,8 +157,16 @@ export function duplicateInFlightNavigationsIntegrationSuite() {
it('should accurately track currentNavigation', fakeAsync(() => {
const router = TestBed.inject(Router);
router.resetConfig([
{path: 'one', component: SimpleCmp, canActivate: ['in1Second']},
{path: 'two', component: BlankCmp, canActivate: ['in1Second']},
{
path: 'one',
component: SimpleCmp,
canActivate: [() => new Promise((resolve) => setTimeout(resolve, 1000))],
},
{
path: 'two',
component: BlankCmp,
canActivate: [() => new Promise((resolve) => setTimeout(resolve, 1000))],
},
]);
router.events.subscribe((e) => {
@@ -53,14 +53,6 @@ export function eagerUrlUpdateStrategyIntegrationSuite() {
const serializer = new DefaultUrlSerializer();
TestBed.configureTestingModule({
providers: [
{
provide: 'authGuardFail',
useValue: (a: any, b: any) => {
return new Promise((res) => {
setTimeout(() => res(serializer.parse('/login')), 1);
});
},
},
AuthGuard,
DelayedGuard,
provideRouter([], withRouterConfig({urlUpdateStrategy: 'eager'})),
@@ -102,7 +94,16 @@ export function eagerUrlUpdateStrategyIntegrationSuite() {
advance(fixture);
router.resetConfig([
{path: 'team/:id', component: SimpleCmp, canActivate: ['authGuardFail']},
{
path: 'team/:id',
component: SimpleCmp,
canActivate: [
() =>
new Promise((res) => {
setTimeout(() => res(new DefaultUrlSerializer().parse('/login')), 1);
}),
],
},
{path: 'login', component: AbsoluteSimpleLinkCmp},
]);
File diff suppressed because it is too large Load Diff
@@ -769,16 +769,7 @@ export function lazyLoadingIntegrationSuite() {
beforeEach(() => {
log.length = 0;
TestBed.configureTestingModule({
providers: [
{provide: PreloadingStrategy, useExisting: PreloadAllModules},
{
provide: 'loggingReturnsTrue',
useValue: () => {
log.push('loggingReturnsTrue');
return true;
},
},
],
providers: [{provide: PreloadingStrategy, useExisting: PreloadAllModules}],
});
const preloader = TestBed.inject(RouterPreloader);
preloader.setUpPreloading();
@@ -813,7 +804,16 @@ export function lazyLoadingIntegrationSuite() {
router.resetConfig([
{path: 'blank', component: BlankCmp},
{path: 'lazy', loadChildren: () => LoadedModule1, canLoad: ['loggingReturnsTrue']},
{
path: 'lazy',
loadChildren: () => LoadedModule1,
canLoad: [
() => {
log.push('loggingReturnsTrue');
return true;
},
],
},
]);
router.navigateByUrl('/blank');
@@ -445,31 +445,6 @@ export function navigationIntegrationTestSuite() {
beforeEach(() => {
log = [];
TestBed.configureTestingModule({
providers: [
{
provide: 'trueRightAway',
useValue: () => {
log.push('trueRightAway');
return true;
},
},
{
provide: 'trueIn2Seconds',
useValue: () => {
log.push('trueIn2Seconds-start');
let res: (value: boolean) => void;
const p = new Promise<boolean>((r) => (res = r));
setTimeout(() => {
log.push('trueIn2Seconds-end');
res(true);
}, 2000);
return p;
},
},
],
});
});
describe('route activation', () => {
@@ -680,10 +655,22 @@ export function navigationIntegrationTestSuite() {
it('should not wait for prior navigations to start a new navigation', fakeAsync(
inject([Router, Location], (router: Router) => {
const fixture = createRoot(router, RootCmp);
const trueRightAway = () => {
log.push('trueRightAway');
return true;
};
const trueIn2Seconds = () => {
log.push('trueIn2Seconds-start');
return new Promise<boolean>((res) => {
setTimeout(() => {
log.push('trueIn2Seconds-end');
res(true);
}, 2000);
});
};
router.resetConfig([
{path: 'a', component: SimpleCmp, canActivate: ['trueRightAway', 'trueIn2Seconds']},
{path: 'b', component: SimpleCmp, canActivate: ['trueRightAway', 'trueIn2Seconds']},
{path: 'a', component: SimpleCmp, canActivate: [trueRightAway, trueIn2Seconds]},
{path: 'b', component: SimpleCmp, canActivate: [trueRightAway, trueIn2Seconds]},
]);
router.navigateByUrl('/a');
@@ -352,10 +352,6 @@ export function navigationErrorsIntegrationSuite() {
});
it('should dispatch NavigationCancel after the url has been reset back', fakeAsync(() => {
TestBed.configureTestingModule({
providers: [{provide: 'returnsFalse', useValue: () => false}],
});
const router: Router = TestBed.inject(Router);
const location = TestBed.inject(Location);
@@ -366,7 +362,7 @@ export function navigationErrorsIntegrationSuite() {
{
path: 'throwing',
loadChildren: jasmine.createSpy('doesnotmatter'),
canLoad: ['returnsFalse'],
canLoad: [() => false],
},
]);
@@ -71,13 +71,6 @@ export function routeDataIntegrationSuite() {
{provide: 'resolveNullError', useValue: (a: any, b: any) => Promise.reject(null)},
{provide: 'resolveEmpty', useValue: (a: any, b: any) => EMPTY},
{provide: 'numberOfUrlSegments', useValue: (a: any, b: any) => a.url.length},
{
provide: 'overridingGuard',
useValue: (route: ActivatedRouteSnapshot) => {
route.data = {prop: 10};
return true;
},
},
],
});
});
@@ -596,7 +589,12 @@ export function routeDataIntegrationSuite() {
{
path: 'route',
component: NestedComponentWithData,
canActivate: ['overridingGuard'],
canActivate: [
(route: ActivatedRouteSnapshot) => {
route.data = {prop: 10};
return true;
},
],
},
]);
@@ -18,6 +18,7 @@ import {
Type,
ViewChild,
ViewContainerRef,
inject,
} from '@angular/core';
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {
@@ -294,20 +295,11 @@ describe('Integration', () => {
imports: [
RouterModule.forRoot([
{path: '', component: SimpleCmp},
{path: 'one', component: OneCmp, canActivate: ['returnRootUrlTree']},
{path: 'one', component: OneCmp, canActivate: [() => inject(Router).parseUrl('/')]},
]),
],
declarations: [SimpleCmp, RootCmp, OneCmp],
providers: [
provideLocationMocks(),
{
provide: 'returnRootUrlTree',
useFactory: (router: Router) => () => {
return router.parseUrl('/');
},
deps: [Router],
},
],
providers: [provideLocationMocks()],
});
const router = TestBed.inject(Router);
+72 -62
View File
@@ -7,7 +7,7 @@
*/
import {Location} from '@angular/common';
import {EnvironmentInjector} from '@angular/core';
import {EnvironmentInjector, inject as coreInject} from '@angular/core';
import {inject, TestBed} from '@angular/core/testing';
import {RouterModule} from '@angular/router';
import {of} from 'rxjs';
@@ -24,7 +24,7 @@ import {DefaultUrlSerializer, UrlTree} from '../src/url_tree';
import {getAllRouteGuards} from '../src/utils/preactivation';
import {TreeNode} from '../src/utils/tree';
import {createActivatedRouteSnapshot, Logger, provideTokenLogger} from './helpers';
import {createActivatedRouteSnapshot, Logger} from './helpers';
describe('Router', () => {
describe('resetConfig', () => {
@@ -110,54 +110,44 @@ describe('Router', () => {
const serializer = new DefaultUrlSerializer();
let empty: RouterStateSnapshot;
let logger: Logger;
function createLoggerGuard(token: string, returnValue = true as boolean | UrlTree) {
return () => {
coreInject(Logger).add(token);
return returnValue;
};
}
let events: any[];
const CA_CHILD = 'canActivate_child';
const CA_CHILD_FALSE = 'canActivate_child_false';
const CA_CHILD_REDIRECT = 'canActivate_child_redirect';
const CAC_CHILD = 'canActivateChild_child';
const CAC_CHILD_FALSE = 'canActivateChild_child_false';
const CAC_CHILD_REDIRECT = 'canActivateChild_child_redirect';
const CA_GRANDCHILD = 'canActivate_grandchild';
const CA_GRANDCHILD_FALSE = 'canActivate_grandchild_false';
const CA_GRANDCHILD_REDIRECT = 'canActivate_grandchild_redirect';
const CDA_CHILD = 'canDeactivate_child';
const CDA_CHILD_FALSE = 'canDeactivate_child_false';
const CDA_CHILD_REDIRECT = 'canDeactivate_child_redirect';
const CDA_GRANDCHILD = 'canDeactivate_grandchild';
const CDA_GRANDCHILD_FALSE = 'canDeactivate_grandchild_false';
const CDA_GRANDCHILD_REDIRECT = 'canDeactivate_grandchild_redirect';
const CA_CHILD = createLoggerGuard('canActivate_child');
const CA_CHILD_FALSE = createLoggerGuard('canActivate_child_false', false);
const CA_CHILD_REDIRECT = createLoggerGuard(
'canActivate_child_redirect',
serializer.parse('/canActivate_child_redirect'),
);
const CAC_CHILD = createLoggerGuard('canActivateChild_child');
const CAC_CHILD_FALSE = createLoggerGuard('canActivateChild_child_false', false);
const CAC_CHILD_REDIRECT = createLoggerGuard(
'canActivateChild_child_redirect',
serializer.parse('/canActivateChild_child_redirect'),
);
const CA_GRANDCHILD = createLoggerGuard('canActivate_grandchild');
const CA_GRANDCHILD_REDIRECT = createLoggerGuard(
'canActivate_grandchild_redirect',
serializer.parse('/canActivate_grandchild_redirect'),
);
const CDA_CHILD = createLoggerGuard('canDeactivate_child');
const CDA_CHILD_FALSE = createLoggerGuard('canDeactivate_child_false', false);
const CDA_CHILD_REDIRECT = createLoggerGuard(
'canDeactivate_child_redirect',
serializer.parse('/canDeactivate_child_redirect'),
);
const CDA_GRANDCHILD = createLoggerGuard('canDeactivate_grandchild');
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterModule],
providers: [
Logger,
provideTokenLogger(CA_CHILD),
provideTokenLogger(CA_CHILD_FALSE, false),
provideTokenLogger(CA_CHILD_REDIRECT, serializer.parse('/canActivate_child_redirect')),
provideTokenLogger(CAC_CHILD),
provideTokenLogger(CAC_CHILD_FALSE, false),
provideTokenLogger(
CAC_CHILD_REDIRECT,
serializer.parse('/canActivateChild_child_redirect'),
),
provideTokenLogger(CA_GRANDCHILD),
provideTokenLogger(CA_GRANDCHILD_FALSE, false),
provideTokenLogger(
CA_GRANDCHILD_REDIRECT,
serializer.parse('/canActivate_grandchild_redirect'),
),
provideTokenLogger(CDA_CHILD),
provideTokenLogger(CDA_CHILD_FALSE, false),
provideTokenLogger(CDA_CHILD_REDIRECT, serializer.parse('/canDeactivate_child_redirect')),
provideTokenLogger(CDA_GRANDCHILD),
provideTokenLogger(CDA_GRANDCHILD_FALSE, false),
provideTokenLogger(
CDA_GRANDCHILD_REDIRECT,
serializer.parse('/canDeactivate_grandchild_redirect'),
),
],
providers: [Logger],
});
});
@@ -440,7 +430,11 @@ describe('Router', () => {
checkGuards(futureState, empty, TestBed.inject(EnvironmentInjector), (result) => {
expect(result).toBe(true);
expect(logger.logs).toEqual([CA_CHILD, CAC_CHILD, CA_GRANDCHILD]);
expect(logger.logs).toEqual([
'canActivate_child',
'canActivateChild_child',
'canActivate_grandchild',
]);
});
});
@@ -471,7 +465,7 @@ describe('Router', () => {
checkGuards(futureState, empty, TestBed.inject(EnvironmentInjector), (result) => {
expect(result).toBe(false);
expect(logger.logs).toEqual([CA_CHILD_FALSE]);
expect(logger.logs).toEqual(['canActivate_child_false']);
});
});
@@ -502,7 +496,7 @@ describe('Router', () => {
checkGuards(futureState, empty, TestBed.inject(EnvironmentInjector), (result) => {
expect(result).toBe(false);
expect(logger.logs).toEqual([CA_CHILD, CAC_CHILD_FALSE]);
expect(logger.logs).toEqual(['canActivate_child', 'canActivateChild_child_false']);
});
});
@@ -543,7 +537,12 @@ describe('Router', () => {
);
checkGuards(futureState, currentState, TestBed.inject(EnvironmentInjector), (result) => {
expect(logger.logs).toEqual([CDA_CHILD, CA_CHILD, CAC_CHILD, CA_GRANDCHILD]);
expect(logger.logs).toEqual([
'canDeactivate_child',
'canActivate_child',
'canActivateChild_child',
'canActivate_grandchild',
]);
});
});
@@ -582,7 +581,7 @@ describe('Router', () => {
checkGuards(futureState, currentState, TestBed.inject(EnvironmentInjector), (result) => {
expect(result).toBe(false);
expect(logger.logs).toEqual([CDA_CHILD_FALSE]);
expect(logger.logs).toEqual(['canDeactivate_child_false']);
});
});
it('should deactivate from bottom up, then activate top down', () => {
@@ -628,11 +627,11 @@ describe('Router', () => {
checkGuards(futureState, currentState, TestBed.inject(EnvironmentInjector), (result) => {
expect(result).toBe(true);
expect(logger.logs).toEqual([
CDA_GRANDCHILD,
CDA_CHILD,
CA_CHILD,
CAC_CHILD,
CA_GRANDCHILD,
'canDeactivate_grandchild',
'canDeactivate_child',
'canActivate_child',
'canActivateChild_child',
'canActivate_grandchild',
]);
});
@@ -664,8 +663,10 @@ describe('Router', () => {
);
checkGuards(futureState, empty, TestBed.inject(EnvironmentInjector), (result) => {
expect(serializer.serialize(result as UrlTree)).toBe('/' + CA_CHILD_REDIRECT);
expect(logger.logs).toEqual([CA_CHILD_REDIRECT]);
expect(serializer.serialize(result as UrlTree)).toBe(
'/' + 'canActivate_child_redirect',
);
expect(logger.logs).toEqual(['canActivate_child_redirect']);
});
});
@@ -695,8 +696,10 @@ describe('Router', () => {
);
checkGuards(futureState, empty, TestBed.inject(EnvironmentInjector), (result) => {
expect(serializer.serialize(result as UrlTree)).toBe('/' + CAC_CHILD_REDIRECT);
expect(logger.logs).toEqual([CAC_CHILD_REDIRECT]);
expect(serializer.serialize(result as UrlTree)).toBe(
'/' + 'canActivateChild_child_redirect',
);
expect(logger.logs).toEqual(['canActivateChild_child_redirect']);
});
});
@@ -726,8 +729,13 @@ describe('Router', () => {
);
checkGuards(futureState, empty, TestBed.inject(EnvironmentInjector), (result) => {
expect(serializer.serialize(result as UrlTree)).toBe('/' + CA_GRANDCHILD_REDIRECT);
expect(logger.logs).toEqual([CAC_CHILD, CA_GRANDCHILD_REDIRECT]);
expect(serializer.serialize(result as UrlTree)).toBe(
'/' + 'canActivate_grandchild_redirect',
);
expect(logger.logs).toEqual([
'canActivateChild_child',
'canActivate_grandchild_redirect',
]);
});
});
@@ -765,8 +773,10 @@ describe('Router', () => {
);
checkGuards(futureState, currentState, TestBed.inject(EnvironmentInjector), (result) => {
expect(serializer.serialize(result as UrlTree)).toBe('/' + CDA_CHILD_REDIRECT);
expect(logger.logs).toEqual([CDA_CHILD_REDIRECT]);
expect(serializer.serialize(result as UrlTree)).toBe(
'/' + 'canDeactivate_child_redirect',
);
expect(logger.logs).toEqual(['canDeactivate_child_redirect']);
});
});
});
@@ -52,7 +52,7 @@ describe('RouterPreloader', () => {
providers: [
provideLocationMocks(),
provideRouter(
[{path: 'lazy', loadChildren: jasmine.createSpy('expected'), canLoad: ['someGuard']}],
[{path: 'lazy', loadChildren: jasmine.createSpy('expected'), canLoad: [() => true]}],
withPreloading(PreloadAllModules),
),
],
@@ -85,7 +85,7 @@ describe('RouterPreloader', () => {
providers: [
provideLocationMocks(),
provideRouter(
[{path: 'lazy', loadChildren: () => LoadedModule, canLoad: ['someGuard']}],
[{path: 'lazy', loadChildren: () => LoadedModule, canLoad: [() => true]}],
withPreloading(PreloadAllModules),
),
],