angular/packages/router/test/operators/resolve_data.spec.ts
Leonel Franchelli 29e0834c4d fix(router): Resolvers in different parts of the route tree should be able to execute together (#52934)
The following commit accidentally broken execution of resolvers when
two resolvers appear in different parts of the tree and do not share a
3278966068

This happens when there are secondary routes. This test ensures that all
routes with resolves are run.

fixes #52892

PR Close #52934
2023-11-20 12:07:10 -08:00

176 lines
6.1 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 {Component} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {provideRouter, Router} from '@angular/router';
import {RouterTestingHarness} from '@angular/router/testing';
import {EMPTY, interval, NEVER, of} from 'rxjs';
describe('resolveData operator', () => {
it('should take only the first emitted value of every resolver', async () => {
TestBed.configureTestingModule({
providers: [provideRouter([{path: '**', children: [], resolve: {e1: () => interval()}}])]
});
await RouterTestingHarness.create('/');
expect(TestBed.inject(Router).routerState.root.firstChild?.snapshot.data).toEqual({e1: 0});
});
it('should cancel navigation if a resolver does not complete', async () => {
TestBed.configureTestingModule(
{providers: [provideRouter([{path: '**', children: [], resolve: {e1: () => EMPTY}}])]});
await RouterTestingHarness.create('/a');
expect(TestBed.inject(Router).url).toEqual('/');
});
it('should cancel navigation if 1 of 2 resolvers does not emit', async () => {
TestBed.configureTestingModule({
providers:
[provideRouter([{path: '**', children: [], resolve: {e0: () => of(0), e1: () => EMPTY}}])]
});
await RouterTestingHarness.create('/a');
expect(TestBed.inject(Router).url).toEqual('/');
});
it('should complete instantly if at least one resolver doesn\'t emit', async () => {
TestBed.configureTestingModule({
providers:
[provideRouter([{path: '**', children: [], resolve: {e0: () => EMPTY, e1: () => NEVER}}])]
});
await RouterTestingHarness.create('/a');
expect(TestBed.inject(Router).url).toEqual('/');
});
it('should run resolvers in different parts of the tree', async () => {
let value = 0;
let bValue = 0;
TestBed.configureTestingModule({
providers: [provideRouter([
{
path: 'a',
runGuardsAndResolvers: () => false,
children: [{
path: '',
resolve: {d0: () => ++value},
runGuardsAndResolvers: 'always',
children: [],
}],
},
{
path: 'b',
outlet: 'aux',
runGuardsAndResolvers: () => false,
children: [{
path: '',
resolve: {d1: () => ++bValue},
runGuardsAndResolvers: 'always',
children: [],
}]
},
])]
});
const router = TestBed.inject(Router);
const harness = await RouterTestingHarness.create('/a(aux:b)');
expect(router.routerState.root.children[0]?.firstChild?.snapshot.data).toEqual({d0: 1});
expect(router.routerState.root.children[1]?.firstChild?.snapshot.data).toEqual({d1: 1});
await harness.navigateByUrl('/a(aux:b)#new');
expect(router.routerState.root.children[0]?.firstChild?.snapshot.data).toEqual({d0: 2});
expect(router.routerState.root.children[1]?.firstChild?.snapshot.data).toEqual({d1: 2});
});
it('should update children inherited data when resolvers run', async () => {
let value = 0;
TestBed.configureTestingModule({
providers: [provideRouter([{
path: 'a',
children: [{path: 'b', children: []}],
resolve: {d0: () => ++value},
runGuardsAndResolvers: 'always',
}])]
});
const harness = await RouterTestingHarness.create('/a/b');
expect(TestBed.inject(Router).routerState.root.firstChild?.snapshot.data).toEqual({d0: 1});
expect(TestBed.inject(Router).routerState.root.firstChild?.firstChild?.snapshot.data).toEqual({
d0: 1
});
await harness.navigateByUrl('/a/b#new');
expect(TestBed.inject(Router).routerState.root.firstChild?.snapshot.data).toEqual({d0: 2});
expect(TestBed.inject(Router).routerState.root.firstChild?.firstChild?.snapshot.data).toEqual({
d0: 2
});
});
it('should have correct data when parent resolver runs but data is not inherited', async () => {
@Component({template: ''})
class Empty {
}
TestBed.configureTestingModule({
providers: [provideRouter([{
path: 'a',
component: Empty,
data: {parent: 'parent'},
resolve: {other: () => 'other'},
children: [{
path: 'b',
data: {child: 'child'},
component: Empty,
}]
}])]
});
await RouterTestingHarness.create('/a/b');
const rootSnapshot = TestBed.inject(Router).routerState.root.firstChild!.snapshot;
expect(rootSnapshot.data).toEqual({parent: 'parent', other: 'other'});
expect(rootSnapshot.firstChild!.data).toEqual({child: 'child'});
});
it('should have static title when there is a resolver', async () => {
@Component({template: ''})
class Empty {
}
TestBed.configureTestingModule({
providers: [provideRouter([{
path: 'a',
title: 'a title',
component: Empty,
resolve: {other: () => 'other'},
children: [{
path: 'b',
title: 'b title',
component: Empty,
resolve: {otherb: () => 'other b'},
}]
}])]
});
await RouterTestingHarness.create('/a/b');
const rootSnapshot = TestBed.inject(Router).routerState.root.firstChild!.snapshot;
expect(rootSnapshot.title).toBe('a title');
expect(rootSnapshot.firstChild!.title).toBe('b title');
});
it('should inherit resolved data from parent of parent route', async () => {
@Component({template: ''})
class Empty {
}
TestBed.configureTestingModule({
providers: [provideRouter([{
path: 'a',
resolve: {aResolve: () => 'a'},
children:
[{path: 'b', resolve: {bResolve: () => 'b'}, children: [{path: 'c', component: Empty}]}]
}])]
});
await RouterTestingHarness.create('/a/b/c');
const rootSnapshot = TestBed.inject(Router).routerState.root.firstChild!.snapshot;
expect(rootSnapshot.firstChild!.firstChild!.data).toEqual({bResolve: 'b', aResolve: 'a'});
});
});