From e92799c97e9aa7fefbb40560f932994150fdb17f Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Fri, 22 Apr 2022 16:07:20 -0700 Subject: [PATCH] test(router): Add tests for initialNavigation: enabledBlocking (#45733) Adds additional tests to verify `enabledBlocking` functionality. The initial attempt to fix #44355 would have broken the scenario where a new navigation cancels the initial navigation. We also cannot rely on `NavigationError` like the example workaround in that issue report is doing because there won't be one if a guard simply rejects the initial nav (#16211). PR Close #45733 --- packages/router/test/bootstrap.spec.ts | 115 ++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/packages/router/test/bootstrap.spec.ts b/packages/router/test/bootstrap.spec.ts index 5649b11b961..2f6707d1812 100644 --- a/packages/router/test/bootstrap.spec.ts +++ b/packages/router/test/bootstrap.spec.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {APP_BASE_HREF, DOCUMENT, Location, ɵgetDOM as getDOM} from '@angular/common'; -import {ApplicationRef, Component, CUSTOM_ELEMENTS_SCHEMA, destroyPlatform, NgModule} from '@angular/core'; +import {APP_BASE_HREF, DOCUMENT, ɵgetDOM as getDOM} from '@angular/common'; +import {ApplicationRef, Component, CUSTOM_ELEMENTS_SCHEMA, destroyPlatform, Injectable, NgModule} from '@angular/core'; import {inject} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; @@ -48,6 +48,7 @@ describe('bootstrap', () => { class SecondRootCmp { } + @Injectable({providedIn: 'root'}) class TestResolver implements Resolve { resolve() { let resolve: any = null; @@ -76,6 +77,116 @@ describe('bootstrap', () => { } })); + // TODO(#44355): bootstrapping fails when the initial navigation fails + xit('should complete resolvers when initial navigation fails and initialNavigation = enabledBlocking', + async () => { + @NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot( + [{ + matcher: () => { + throw new Error('error in matcher'); + }, + children: [] + }], + {useHash: true, initialNavigation: 'enabledBlocking'}) + ], + declarations: [RootCmp], + bootstrap: [RootCmp], + providers: [...testProviders], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + class TestModule { + constructor() { + log.push('TestModule'); + } + } + + await platformBrowserDynamic([]).bootstrapModule(TestModule).then(res => { + const router = res.injector.get(Router); + expect(router.navigated).toEqual(false); + expect(router.getCurrentNavigation()).toBeNull(); + expect(log).toContain('TestModule'); + expect(log).toContain('NavigationError'); + }); + }); + + it('should wait for redirect when initialNavigation = enabledBlocking', async () => { + @Injectable({providedIn: 'root'}) + class Redirect { + constructor(private router: Router) {} + canActivate() { + this.router.navigateByUrl('redirectToMe'); + return false; + } + } + @NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot( + [ + {path: 'redirectToMe', children: [], resolve: {test: TestResolver}}, + {path: '**', canActivate: [Redirect], children: []} + ], + {useHash: true, initialNavigation: 'enabledBlocking'}) + ], + declarations: [RootCmp], + bootstrap: [RootCmp], + providers: [...testProviders], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + class TestModule { + constructor(router: Router) { + log.push('TestModule'); + } + } + + await platformBrowserDynamic([]).bootstrapModule(TestModule).then(res => { + const router = res.injector.get(Router); + expect(router.navigated).toEqual(true); + expect(router.url).toContain('redirectToMe'); + expect(log).toContain('TestModule'); + }); + }); + + it('should wait for redirect with UrlTree when initialNavigation = enabledBlocking', async () => { + @Injectable({providedIn: 'root'}) + class Redirect { + constructor(private router: Router) {} + canActivate() { + return this.router.createUrlTree(['/redirectToMe']); + } + } + @NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot( + [ + {path: 'redirectToMe', children: [], resolve: {test: TestResolver}}, + {path: '**', canActivate: [Redirect], children: []} + ], + {useHash: true, initialNavigation: 'enabledBlocking'}) + ], + declarations: [RootCmp], + bootstrap: [RootCmp], + providers: [...testProviders], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + class TestModule { + constructor(router: Router) { + log.push('TestModule'); + } + } + + await platformBrowserDynamic([]).bootstrapModule(TestModule).then(res => { + const router = res.injector.get(Router); + expect(router.navigated).toEqual(true); + expect(router.url).toContain('redirectToMe'); + expect(log).toContain('TestModule'); + }); + }); + it('should wait for resolvers to complete when initialNavigation = enabledBlocking', (done) => { @Component({selector: 'test', template: 'test'}) class TestCmpEnabled {