feat(router): guard returning UrlTree cancels current navigation and redirects (#26521)
Fixes #24618 FW-153 #resolve PR Close #26521
This commit is contained in:

committed by
Matias Niemelä

parent
081f95c812
commit
4e9f2e5895
@ -9,7 +9,7 @@
|
||||
import {CommonModule, Location} from '@angular/common';
|
||||
import {SpyLocation} from '@angular/common/testing';
|
||||
import {ChangeDetectionStrategy, Component, Injectable, NgModule, NgModuleFactoryLoader, NgModuleRef, NgZone, OnDestroy, ɵConsole as Console, ɵNoopNgZone as NoopNgZone} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, fakeAsync, inject, tick} from '@angular/core/testing';
|
||||
import {ComponentFixture, TestBed, fakeAsync, flush, inject, tick} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
import {ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, CanActivate, CanDeactivate, ChildActivationEnd, ChildActivationStart, DetachedRouteHandle, Event, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, PRIMARY_OUTLET, ParamMap, Params, PreloadAllModules, PreloadingStrategy, Resolve, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, Router, RouterEvent, RouterModule, RouterPreloader, RouterStateSnapshot, RoutesRecognized, RunGuardsAndResolvers, UrlHandlingStrategy, UrlSegmentGroup, UrlSerializer, UrlTree} from '@angular/router';
|
||||
@ -2017,6 +2017,59 @@ describe('Integration', () => {
|
||||
})));
|
||||
});
|
||||
|
||||
describe('should redirect when guard returns UrlTree', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
providers: [{
|
||||
provide: 'returnUrlTree',
|
||||
useFactory: (router: Router) => () => { return router.parseUrl('/redirected'); },
|
||||
deps: [Router]
|
||||
}]
|
||||
}));
|
||||
|
||||
it('works', fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||
const recordedEvents: any[] = [];
|
||||
let cancelEvent: NavigationCancel = null !;
|
||||
router.events.forEach((e: any) => {
|
||||
recordedEvents.push(e);
|
||||
if (e instanceof NavigationCancel) cancelEvent = e;
|
||||
});
|
||||
router.resetConfig([
|
||||
{path: '', component: SimpleCmp},
|
||||
{path: 'one', component: RouteCmp, canActivate: ['returnUrlTree']},
|
||||
{path: 'redirected', component: SimpleCmp}
|
||||
]);
|
||||
|
||||
const fixture = TestBed.createComponent(RootCmp);
|
||||
router.navigateByUrl('/one');
|
||||
|
||||
advance(fixture);
|
||||
|
||||
expect(location.path()).toEqual('/redirected');
|
||||
expect(fixture.nativeElement).toHaveText('simple');
|
||||
expect(cancelEvent && cancelEvent.reason)
|
||||
.toBe('NavigationCancelingError: Redirecting to "/redirected"');
|
||||
expectEvents(recordedEvents, [
|
||||
[NavigationStart, '/one'],
|
||||
[RoutesRecognized, '/one'],
|
||||
[GuardsCheckStart, '/one'],
|
||||
[ChildActivationStart, undefined],
|
||||
[ActivationStart, undefined],
|
||||
[NavigationCancel, '/one'],
|
||||
[NavigationStart, '/redirected'],
|
||||
[RoutesRecognized, '/redirected'],
|
||||
[GuardsCheckStart, '/redirected'],
|
||||
[ChildActivationStart, undefined],
|
||||
[ActivationStart, undefined],
|
||||
[GuardsCheckEnd, '/redirected'],
|
||||
[ResolveStart, '/redirected'],
|
||||
[ResolveEnd, '/redirected'],
|
||||
[ActivationEnd, undefined],
|
||||
[ChildActivationEnd, undefined],
|
||||
[NavigationEnd, '/redirected'],
|
||||
]);
|
||||
})));
|
||||
});
|
||||
|
||||
describe('runGuardsAndResolvers', () => {
|
||||
let guardRunCount = 0;
|
||||
let resolverRunCount = 0;
|
||||
|
@ -672,10 +672,11 @@ function checkGuards(
|
||||
guards: getAllRouteGuards(future, curr, new ChildrenOutletContexts())
|
||||
} as Partial<NavigationTransition>)
|
||||
.pipe(checkGuardsOperator(injector))
|
||||
.subscribe(
|
||||
t => {
|
||||
if (t.guardsResult === null) throw new Error('Guard result expected');
|
||||
return check(t.guardsResult);
|
||||
},
|
||||
(e) => { throw e; });
|
||||
.subscribe({
|
||||
next(t) {
|
||||
if (t.guardsResult === null) throw new Error('Guard result expected');
|
||||
return check(t.guardsResult);
|
||||
},
|
||||
error(e) { throw e; }
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user