test(ivy): run browser-specific @angular/core tests on CI (#27545)
PR Close #27545
This commit is contained in:
parent
aa48810d80
commit
5657126d86
@ -66,9 +66,6 @@ jasmine_node_test(
|
|||||||
|
|
||||||
ts_web_test_suite(
|
ts_web_test_suite(
|
||||||
name = "test_web",
|
name = "test_web",
|
||||||
tags = [
|
|
||||||
"fixme-ivy-aot",
|
|
||||||
],
|
|
||||||
deps = [
|
deps = [
|
||||||
":test_lib",
|
":test_lib",
|
||||||
],
|
],
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@ import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/brow
|
|||||||
import {Component, HostBinding} from '@angular/core';
|
import {Component, HostBinding} from '@angular/core';
|
||||||
import {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
|
import {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
|
||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {fixmeIvy} from '@angular/private/testing';
|
||||||
import {ActivatedRoute, Router, RouterOutlet} from '@angular/router';
|
import {ActivatedRoute, Router, RouterOutlet} from '@angular/router';
|
||||||
import {RouterTestingModule} from '@angular/router/testing';
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
|
|
||||||
@ -33,349 +34,354 @@ import {RouterTestingModule} from '@angular/router/testing';
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should query the old and new routes via :leave and :enter', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
@Component({
|
'should query the old and new routes via :leave and :enter', fakeAsync(() => {
|
||||||
animations: [
|
@Component({
|
||||||
trigger(
|
animations: [
|
||||||
'routerAnimations',
|
trigger(
|
||||||
[
|
'routerAnimations',
|
||||||
transition(
|
[
|
||||||
'page1 => page2',
|
transition(
|
||||||
[
|
'page1 => page2',
|
||||||
query(':leave', animateChild()),
|
[
|
||||||
query(':enter', animateChild()),
|
query(':leave', animateChild()),
|
||||||
]),
|
query(':enter', animateChild()),
|
||||||
]),
|
]),
|
||||||
],
|
]),
|
||||||
template: `
|
],
|
||||||
|
template: `
|
||||||
<div [@routerAnimations]="prepareRouteAnimation(r)">
|
<div [@routerAnimations]="prepareRouteAnimation(r)">
|
||||||
<router-outlet #r="outlet"></router-outlet>
|
<router-outlet #r="outlet"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class ContainerCmp {
|
class ContainerCmp {
|
||||||
constructor(public router: Router) {}
|
constructor(public router: Router) {}
|
||||||
|
|
||||||
prepareRouteAnimation(r: RouterOutlet) {
|
prepareRouteAnimation(r: RouterOutlet) {
|
||||||
const animation = r.activatedRouteData['animation'];
|
const animation = r.activatedRouteData['animation'];
|
||||||
const value = animation ? animation['value'] : null;
|
const value = animation ? animation['value'] : null;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page1',
|
selector: 'page1',
|
||||||
template: `page1`,
|
template: `page1`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'page1Animation',
|
'page1Animation',
|
||||||
[
|
[
|
||||||
transition(
|
transition(
|
||||||
':leave',
|
':leave',
|
||||||
[
|
[
|
||||||
style({width: '200px'}),
|
style({width: '200px'}),
|
||||||
animate(1000, style({width: '0px'})),
|
animate(1000, style({width: '0px'})),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Page1Cmp {
|
class Page1Cmp {
|
||||||
@HostBinding('@page1Animation') public doAnimate = true;
|
@HostBinding('@page1Animation') public doAnimate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page2',
|
selector: 'page2',
|
||||||
template: `page2`,
|
template: `page2`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'page2Animation',
|
'page2Animation',
|
||||||
[
|
[
|
||||||
transition(
|
transition(
|
||||||
':enter',
|
':enter',
|
||||||
[
|
[
|
||||||
style({opacity: 0}),
|
style({opacity: 0}),
|
||||||
animate(1000, style({opacity: 1})),
|
animate(1000, style({opacity: 1})),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Page2Cmp {
|
class Page2Cmp {
|
||||||
@HostBinding('@page2Animation') public doAnimate = true;
|
@HostBinding('@page2Animation') public doAnimate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
||||||
imports: [RouterTestingModule.withRoutes([
|
imports: [RouterTestingModule.withRoutes([
|
||||||
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
||||||
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
||||||
])]
|
])]
|
||||||
});
|
});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(ContainerCmp);
|
const fixture = TestBed.createComponent(ContainerCmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
cmp.router.initialNavigation();
|
cmp.router.initialNavigation();
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page1');
|
cmp.router.navigateByUrl('/page1');
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page2');
|
cmp.router.navigateByUrl('/page2');
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
const player = engine.players[0] !;
|
const player = engine.players[0] !;
|
||||||
const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
||||||
const players = groupPlayer.players as MockAnimationPlayer[];
|
const players = groupPlayer.players as MockAnimationPlayer[];
|
||||||
|
|
||||||
expect(players.length).toEqual(2);
|
expect(players.length).toEqual(2);
|
||||||
const [p1, p2] = players;
|
const [p1, p2] = players;
|
||||||
|
|
||||||
expect(p1.duration).toEqual(1000);
|
expect(p1.duration).toEqual(1000);
|
||||||
expect(p1.keyframes).toEqual([
|
expect(p1.keyframes).toEqual([
|
||||||
{offset: 0, width: '200px'},
|
{offset: 0, width: '200px'},
|
||||||
{offset: 1, width: '0px'},
|
{offset: 1, width: '0px'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(p2.duration).toEqual(2000);
|
expect(p2.duration).toEqual(2000);
|
||||||
expect(p2.keyframes).toEqual([
|
expect(p2.keyframes).toEqual([
|
||||||
{offset: 0, opacity: '0'},
|
{offset: 0, opacity: '0'},
|
||||||
{offset: .5, opacity: '0'},
|
{offset: .5, opacity: '0'},
|
||||||
{offset: 1, opacity: '1'},
|
{offset: 1, opacity: '1'},
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
@Component({
|
'should allow inner enter animations to be emulated within a routed item', fakeAsync(() => {
|
||||||
animations: [
|
@Component({
|
||||||
trigger(
|
animations: [
|
||||||
'routerAnimations',
|
trigger(
|
||||||
[
|
'routerAnimations',
|
||||||
transition(
|
[
|
||||||
'page1 => page2',
|
transition(
|
||||||
[
|
'page1 => page2',
|
||||||
query(':enter', animateChild()),
|
[
|
||||||
]),
|
query(':enter', animateChild()),
|
||||||
]),
|
]),
|
||||||
],
|
]),
|
||||||
template: `
|
],
|
||||||
|
template: `
|
||||||
<div [@routerAnimations]="prepareRouteAnimation(r)">
|
<div [@routerAnimations]="prepareRouteAnimation(r)">
|
||||||
<router-outlet #r="outlet"></router-outlet>
|
<router-outlet #r="outlet"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class ContainerCmp {
|
class ContainerCmp {
|
||||||
constructor(public router: Router) {}
|
constructor(public router: Router) {}
|
||||||
|
|
||||||
prepareRouteAnimation(r: RouterOutlet) {
|
prepareRouteAnimation(r: RouterOutlet) {
|
||||||
const animation = r.activatedRouteData['animation'];
|
const animation = r.activatedRouteData['animation'];
|
||||||
const value = animation ? animation['value'] : null;
|
const value = animation ? animation['value'] : null;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'page1', template: `page1`, animations: []})
|
@Component({selector: 'page1', template: `page1`, animations: []})
|
||||||
class Page1Cmp {
|
class Page1Cmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page2',
|
selector: 'page2',
|
||||||
template: `
|
template: `
|
||||||
<h1>Page 2</h1>
|
<h1>Page 2</h1>
|
||||||
<div *ngIf="exp" class="if-one" @ifAnimation></div>
|
<div *ngIf="exp" class="if-one" @ifAnimation></div>
|
||||||
<div *ngIf="exp" class="if-two" @ifAnimation></div>
|
<div *ngIf="exp" class="if-two" @ifAnimation></div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'page2Animation',
|
'page2Animation',
|
||||||
[
|
[
|
||||||
transition(
|
transition(
|
||||||
':enter',
|
':enter',
|
||||||
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
|
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
|
||||||
]),
|
]),
|
||||||
trigger(
|
trigger(
|
||||||
'ifAnimation',
|
'ifAnimation',
|
||||||
[transition(
|
[transition(
|
||||||
':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])
|
':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Page2Cmp {
|
class Page2Cmp {
|
||||||
@HostBinding('@page2Animation') public doAnimate = true;
|
@HostBinding('@page2Animation') public doAnimate = true;
|
||||||
|
|
||||||
public exp = true;
|
public exp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
||||||
imports: [RouterTestingModule.withRoutes([
|
imports: [RouterTestingModule.withRoutes([
|
||||||
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
||||||
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
||||||
])]
|
])]
|
||||||
});
|
});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(ContainerCmp);
|
const fixture = TestBed.createComponent(ContainerCmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
cmp.router.initialNavigation();
|
cmp.router.initialNavigation();
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page1');
|
cmp.router.navigateByUrl('/page1');
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page2');
|
cmp.router.navigateByUrl('/page2');
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
const player = engine.players[0] !;
|
const player = engine.players[0] !;
|
||||||
const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
||||||
const players = groupPlayer.players as MockAnimationPlayer[];
|
const players = groupPlayer.players as MockAnimationPlayer[];
|
||||||
|
|
||||||
expect(players.length).toEqual(2);
|
expect(players.length).toEqual(2);
|
||||||
const [p1, p2] = players;
|
const [p1, p2] = players;
|
||||||
|
|
||||||
expect(p1.keyframes).toEqual([
|
expect(p1.keyframes).toEqual([
|
||||||
{offset: 0, opacity: '0'},
|
{offset: 0, opacity: '0'},
|
||||||
{offset: 1, opacity: '1'},
|
{offset: 1, opacity: '1'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(p2.keyframes).toEqual([
|
expect(p2.keyframes).toEqual([
|
||||||
{offset: 0, opacity: '0'},
|
{offset: 0, opacity: '0'},
|
||||||
{offset: .5, opacity: '0'},
|
{offset: .5, opacity: '0'},
|
||||||
{offset: 1, opacity: '1'},
|
{offset: 1, opacity: '1'},
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
@Component({
|
'should allow inner leave animations to be emulated within a routed item', fakeAsync(() => {
|
||||||
animations: [
|
@Component({
|
||||||
trigger(
|
animations: [
|
||||||
'routerAnimations',
|
trigger(
|
||||||
[
|
'routerAnimations',
|
||||||
transition(
|
[
|
||||||
'page1 => page2',
|
transition(
|
||||||
[
|
'page1 => page2',
|
||||||
query(':leave', animateChild()),
|
[
|
||||||
]),
|
query(':leave', animateChild()),
|
||||||
]),
|
]),
|
||||||
],
|
]),
|
||||||
template: `
|
],
|
||||||
|
template: `
|
||||||
<div [@routerAnimations]="prepareRouteAnimation(r)">
|
<div [@routerAnimations]="prepareRouteAnimation(r)">
|
||||||
<router-outlet #r="outlet"></router-outlet>
|
<router-outlet #r="outlet"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class ContainerCmp {
|
class ContainerCmp {
|
||||||
constructor(public router: Router) {}
|
constructor(public router: Router) {}
|
||||||
|
|
||||||
prepareRouteAnimation(r: RouterOutlet) {
|
prepareRouteAnimation(r: RouterOutlet) {
|
||||||
const animation = r.activatedRouteData['animation'];
|
const animation = r.activatedRouteData['animation'];
|
||||||
const value = animation ? animation['value'] : null;
|
const value = animation ? animation['value'] : null;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page1',
|
selector: 'page1',
|
||||||
template: `
|
template: `
|
||||||
<h1>Page 1</h1>
|
<h1>Page 1</h1>
|
||||||
<div *ngIf="exp" class="if-one" @ifAnimation></div>
|
<div *ngIf="exp" class="if-one" @ifAnimation></div>
|
||||||
<div *ngIf="exp" class="if-two" @ifAnimation></div>
|
<div *ngIf="exp" class="if-two" @ifAnimation></div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'page1Animation',
|
'page1Animation',
|
||||||
[
|
[
|
||||||
transition(
|
transition(
|
||||||
':leave',
|
':leave',
|
||||||
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
|
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
|
||||||
]),
|
]),
|
||||||
trigger(
|
trigger(
|
||||||
'ifAnimation',
|
'ifAnimation',
|
||||||
[transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]),
|
[transition(
|
||||||
]
|
':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]),
|
||||||
})
|
]
|
||||||
class Page1Cmp {
|
})
|
||||||
@HostBinding('@page1Animation') public doAnimate = true;
|
class Page1Cmp {
|
||||||
|
@HostBinding('@page1Animation') public doAnimate = true;
|
||||||
|
|
||||||
public exp = true;
|
public exp = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'page2', template: `page2`, animations: []})
|
@Component({selector: 'page2', template: `page2`, animations: []})
|
||||||
class Page2Cmp {
|
class Page2Cmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
||||||
imports: [RouterTestingModule.withRoutes([
|
imports: [RouterTestingModule.withRoutes([
|
||||||
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
||||||
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
||||||
])]
|
])]
|
||||||
});
|
});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(ContainerCmp);
|
const fixture = TestBed.createComponent(ContainerCmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
cmp.router.initialNavigation();
|
cmp.router.initialNavigation();
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page1');
|
cmp.router.navigateByUrl('/page1');
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page2');
|
cmp.router.navigateByUrl('/page2');
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
const player = engine.players[0] !;
|
const player = engine.players[0] !;
|
||||||
const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
||||||
const players = groupPlayer.players as MockAnimationPlayer[];
|
const players = groupPlayer.players as MockAnimationPlayer[];
|
||||||
|
|
||||||
expect(players.length).toEqual(2);
|
expect(players.length).toEqual(2);
|
||||||
const [p1, p2] = players;
|
const [p1, p2] = players;
|
||||||
|
|
||||||
expect(p1.keyframes).toEqual([
|
expect(p1.keyframes).toEqual([
|
||||||
{offset: 0, opacity: '1'},
|
{offset: 0, opacity: '1'},
|
||||||
{offset: 1, opacity: '0'},
|
{offset: 1, opacity: '0'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(p2.keyframes).toEqual([
|
expect(p2.keyframes).toEqual([
|
||||||
{offset: 0, opacity: '1'},
|
{offset: 0, opacity: '1'},
|
||||||
{offset: .5, opacity: '1'},
|
{offset: .5, opacity: '1'},
|
||||||
{offset: 1, opacity: '0'},
|
{offset: 1, opacity: '0'},
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries',
|
fixmeIvy('unknown').it(
|
||||||
fakeAsync(() => {
|
'should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries',
|
||||||
@Component({
|
fakeAsync(() => {
|
||||||
selector: 'ani-cmp',
|
@Component({
|
||||||
animations: [
|
selector: 'ani-cmp',
|
||||||
trigger(
|
animations: [
|
||||||
'pageAnimation',
|
trigger(
|
||||||
[
|
'pageAnimation',
|
||||||
transition(
|
[
|
||||||
'page1 => page2',
|
transition(
|
||||||
[
|
'page1 => page2',
|
||||||
query('.router-container :leave', animate('1s', style({opacity: 0}))),
|
[
|
||||||
query('.router-container :enter', animate('1s', style({opacity: 1}))),
|
query('.router-container :leave', animate('1s', style({opacity: 0}))),
|
||||||
]),
|
query('.router-container :enter', animate('1s', style({opacity: 1}))),
|
||||||
]),
|
]),
|
||||||
],
|
]),
|
||||||
template: `
|
],
|
||||||
|
template: `
|
||||||
<div [@pageAnimation]="prepRoute(outlet)">
|
<div [@pageAnimation]="prepRoute(outlet)">
|
||||||
<header>
|
<header>
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
@ -388,136 +394,139 @@ import {RouterTestingModule} from '@angular/router/testing';
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class ContainerCmp {
|
class ContainerCmp {
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|
||||||
constructor(public router: Router) {}
|
constructor(public router: Router) {}
|
||||||
|
|
||||||
prepRoute(outlet: any) { return outlet.activatedRouteData['animation']; }
|
prepRoute(outlet: any) { return outlet.activatedRouteData['animation']; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'page1', template: `page1`})
|
@Component({selector: 'page1', template: `page1`})
|
||||||
class Page1Cmp {
|
class Page1Cmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'page2', template: `page2`})
|
@Component({selector: 'page2', template: `page2`})
|
||||||
class Page2Cmp {
|
class Page2Cmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
|
||||||
imports: [RouterTestingModule.withRoutes([
|
imports: [RouterTestingModule.withRoutes([
|
||||||
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
|
||||||
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
|
||||||
])]
|
])]
|
||||||
});
|
});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(ContainerCmp);
|
const fixture = TestBed.createComponent(ContainerCmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
cmp.router.initialNavigation();
|
cmp.router.initialNavigation();
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page1');
|
cmp.router.navigateByUrl('/page1');
|
||||||
tick();
|
tick();
|
||||||
cmp.loading = true;
|
cmp.loading = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
cmp.router.navigateByUrl('/page2');
|
cmp.router.navigateByUrl('/page2');
|
||||||
tick();
|
tick();
|
||||||
cmp.loading = false;
|
cmp.loading = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
const players = engine.players;
|
const players = engine.players;
|
||||||
expect(players.length).toEqual(1);
|
expect(players.length).toEqual(1);
|
||||||
const [p1] = players;
|
const [p1] = players;
|
||||||
|
|
||||||
const innerPlayers = p1.getRealPlayer().players;
|
const innerPlayers = p1.getRealPlayer().players;
|
||||||
expect(innerPlayers.length).toEqual(2);
|
expect(innerPlayers.length).toEqual(2);
|
||||||
|
|
||||||
const [ip1, ip2] = innerPlayers;
|
const [ip1, ip2] = innerPlayers;
|
||||||
expect(ip1.element.innerText).toEqual('page1');
|
expect(ip1.element.innerText).toEqual('page1');
|
||||||
expect(ip2.element.innerText).toEqual('page2');
|
expect(ip2.element.innerText).toEqual('page2');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow a recursive set of :leave animations to occur for nested routes',
|
fixmeIvy('unknown').it(
|
||||||
fakeAsync(() => {
|
'should allow a recursive set of :leave animations to occur for nested routes',
|
||||||
@Component({selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'})
|
fakeAsync(() => {
|
||||||
class ContainerCmp {
|
@Component(
|
||||||
constructor(private _router: Router) {}
|
{selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'})
|
||||||
log: string[] = [];
|
class ContainerCmp {
|
||||||
|
constructor(private _router: Router) {}
|
||||||
|
log: string[] = [];
|
||||||
|
|
||||||
enter() { this._router.navigateByUrl('/(recur:recur/nested)'); }
|
enter() { this._router.navigateByUrl('/(recur:recur/nested)'); }
|
||||||
|
|
||||||
leave() { this._router.navigateByUrl('/'); }
|
leave() { this._router.navigateByUrl('/'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'recur-page',
|
selector: 'recur-page',
|
||||||
template: 'Depth: {{ depth }} \n <router-outlet></router-outlet>',
|
template: 'Depth: {{ depth }} \n <router-outlet></router-outlet>',
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'pageAnimations',
|
'pageAnimations',
|
||||||
[
|
[
|
||||||
transition(':leave', [group([
|
transition(
|
||||||
sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]),
|
':leave', [group([
|
||||||
query('@*', animateChild(), {optional: true})
|
sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]),
|
||||||
])]),
|
query('@*', animateChild(), {optional: true})
|
||||||
]),
|
])]),
|
||||||
]
|
]),
|
||||||
})
|
]
|
||||||
class RecurPageCmp {
|
})
|
||||||
@HostBinding('@pageAnimations') public animatePage = true;
|
class RecurPageCmp {
|
||||||
|
@HostBinding('@pageAnimations') public animatePage = true;
|
||||||
|
|
||||||
@HostBinding('attr.data-depth') public depth = 0;
|
@HostBinding('attr.data-depth') public depth = 0;
|
||||||
|
|
||||||
constructor(private container: ContainerCmp, private route: ActivatedRoute) {
|
constructor(private container: ContainerCmp, private route: ActivatedRoute) {
|
||||||
this.route.data.subscribe(data => {
|
this.route.data.subscribe(data => {
|
||||||
this.container.log.push(`DEPTH ${data.depth}`);
|
this.container.log.push(`DEPTH ${data.depth}`);
|
||||||
this.depth = data.depth;
|
this.depth = data.depth;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ContainerCmp, RecurPageCmp],
|
declarations: [ContainerCmp, RecurPageCmp],
|
||||||
imports: [RouterTestingModule.withRoutes([{
|
imports: [RouterTestingModule.withRoutes([{
|
||||||
path: 'recur',
|
path: 'recur',
|
||||||
component: RecurPageCmp,
|
component: RecurPageCmp,
|
||||||
outlet: 'recur',
|
outlet: 'recur',
|
||||||
data: {depth: 0},
|
data: {depth: 0},
|
||||||
children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}]
|
children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}]
|
||||||
}])]
|
}])]
|
||||||
});
|
});
|
||||||
|
|
||||||
const fixture = TestBed.createComponent(ContainerCmp);
|
const fixture = TestBed.createComponent(ContainerCmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
cmp.enter();
|
cmp.enter();
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
|
|
||||||
expect(cmp.log).toEqual([
|
expect(cmp.log).toEqual([
|
||||||
'DEPTH 0',
|
'DEPTH 0',
|
||||||
'DEPTH 1',
|
'DEPTH 1',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
cmp.leave();
|
cmp.leave();
|
||||||
tick();
|
tick();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const players = getLog();
|
const players = getLog();
|
||||||
expect(players.length).toEqual(2);
|
expect(players.length).toEqual(2);
|
||||||
|
|
||||||
const [p1, p2] = players;
|
const [p1, p2] = players;
|
||||||
expect(p1.element.getAttribute('data-depth')).toEqual('0');
|
expect(p1.element.getAttribute('data-depth')).toEqual('0');
|
||||||
expect(p2.element.getAttribute('data-depth')).toEqual('1');
|
expect(p2.element.getAttribute('data-depth')).toEqual('1');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5,15 +5,15 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {animate, group, query, state, style, transition, trigger} from '@angular/animations';
|
import {animate, query, state, style, transition, trigger} from '@angular/animations';
|
||||||
import {AnimationDriver, ɵAnimationEngine, ɵWebAnimationsDriver, ɵWebAnimationsPlayer, ɵsupportsWebAnimations} from '@angular/animations/browser';
|
import {AnimationDriver, ɵAnimationEngine, ɵWebAnimationsDriver, ɵWebAnimationsPlayer, ɵsupportsWebAnimations} from '@angular/animations/browser';
|
||||||
import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine';
|
import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine';
|
||||||
import {AnimationGroupPlayer} from '@angular/animations/src/players/animation_group_player';
|
import {AnimationGroupPlayer} from '@angular/animations/src/players/animation_group_player';
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
||||||
|
import {fixmeIvy} from '@angular/private/testing';
|
||||||
import {TestBed} from '../../testing';
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
// these tests are only mean't to be run within the DOM (for now)
|
// these tests are only mean't to be run within the DOM (for now)
|
||||||
@ -242,9 +242,10 @@ import {TestBed} from '../../testing';
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should treat * styles as ! for queried items that are collected in a container that is being removed',
|
fixmeIvy('unknown').it(
|
||||||
() => {
|
'should treat * styles as ! for queried items that are collected in a container that is being removed',
|
||||||
@Component({
|
() => {
|
||||||
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
styles: [`
|
styles: [`
|
||||||
.list .outer {
|
.list .outer {
|
||||||
@ -285,58 +286,58 @@ import {TestBed} from '../../testing';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
items: any[] = [];
|
items: any[] = [];
|
||||||
|
|
||||||
get exp() { return this.items.length ? 'full' : 'empty'; }
|
get exp() { return this.items.length ? 'full' : 'empty'; }
|
||||||
|
|
||||||
empty() { this.items = []; }
|
empty() { this.items = []; }
|
||||||
|
|
||||||
full() { this.items = [0, 1, 2, 3, 4]; }
|
full() { this.items = [0, 1, 2, 3, 4]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
|
|
||||||
cmp.empty();
|
cmp.empty();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let player = engine.players[0] !as TransitionAnimationPlayer;
|
let player = engine.players[0] !as TransitionAnimationPlayer;
|
||||||
player.finish();
|
player.finish();
|
||||||
|
|
||||||
cmp.full();
|
cmp.full();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
player = engine.players[0] !as TransitionAnimationPlayer;
|
player = engine.players[0] !as TransitionAnimationPlayer;
|
||||||
let queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players;
|
let queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players;
|
||||||
expect(queriedPlayers.length).toEqual(5);
|
expect(queriedPlayers.length).toEqual(5);
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (i = 0; i < queriedPlayers.length; i++) {
|
for (i = 0; i < queriedPlayers.length; i++) {
|
||||||
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
|
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
|
||||||
expect(player.keyframes).toEqual([
|
expect(player.keyframes).toEqual([
|
||||||
{height: '0px', offset: 0},
|
{height: '0px', offset: 0},
|
||||||
{height: '50px', offset: 1},
|
{height: '50px', offset: 1},
|
||||||
]);
|
]);
|
||||||
player.finish();
|
player.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
cmp.empty();
|
cmp.empty();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
player = engine.players[0] !as TransitionAnimationPlayer;
|
player = engine.players[0] !as TransitionAnimationPlayer;
|
||||||
queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players;
|
queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players;
|
||||||
expect(queriedPlayers.length).toEqual(5);
|
expect(queriedPlayers.length).toEqual(5);
|
||||||
|
|
||||||
for (i = 0; i < queriedPlayers.length; i++) {
|
for (i = 0; i < queriedPlayers.length; i++) {
|
||||||
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
|
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
|
||||||
expect(player.keyframes).toEqual([
|
expect(player.keyframes).toEqual([
|
||||||
{height: '50px', offset: 0},
|
{height: '50px', offset: 0},
|
||||||
{height: '0px', offset: 1},
|
{height: '0px', offset: 1},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should compute intermediate styles properly when an animation is cancelled', () => {
|
it('should compute intermediate styles properly when an animation is cancelled', () => {
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -13,6 +13,7 @@ import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
|
|||||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
|
import {fixmeIvy} from '@angular/private/testing';
|
||||||
|
|
||||||
export function createUrlResolverWithoutPackagePrefix(): UrlResolver {
|
export function createUrlResolverWithoutPackagePrefix(): UrlResolver {
|
||||||
return new UrlResolver();
|
return new UrlResolver();
|
||||||
@ -445,13 +446,14 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should ignore empty bindings', fakeAsync(() => {
|
fixmeIvy('FW-814: Bindings with an empty value should be ignored in the compiler')
|
||||||
const ctx = _bindSimpleProp('[someProp]', TestData);
|
.it('should ignore empty bindings', fakeAsync(() => {
|
||||||
ctx.componentInstance.a = 'value';
|
const ctx = _bindSimpleProp('[someProp]', TestData);
|
||||||
ctx.detectChanges(false);
|
ctx.componentInstance.a = 'value';
|
||||||
|
ctx.detectChanges(false);
|
||||||
|
|
||||||
expect(renderLog.log).toEqual([]);
|
expect(renderLog.log).toEqual([]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should support interpolation', fakeAsync(() => {
|
it('should support interpolation', fakeAsync(() => {
|
||||||
const ctx = _bindSimpleProp('someProp="B{{a}}A"', TestData);
|
const ctx = _bindSimpleProp('someProp="B{{a}}A"', TestData);
|
||||||
@ -537,27 +539,28 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
expect(renderLog.log).toEqual(['someProp=Megatron']);
|
expect(renderLog.log).toEqual(['someProp=Megatron']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should record unwrapped values via ngOnChanges', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
const ctx = createCompFixture(
|
'should record unwrapped values via ngOnChanges', fakeAsync(() => {
|
||||||
'<div [testDirective]="\'aName\' | wrappedPipe" [a]="1" [b]="2 | wrappedPipe"></div>');
|
const ctx = createCompFixture(
|
||||||
const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0];
|
'<div [testDirective]="\'aName\' | wrappedPipe" [a]="1" [b]="2 | wrappedPipe"></div>');
|
||||||
ctx.detectChanges(false);
|
const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0];
|
||||||
dir.changes = {};
|
ctx.detectChanges(false);
|
||||||
ctx.detectChanges(false);
|
dir.changes = {};
|
||||||
|
ctx.detectChanges(false);
|
||||||
|
|
||||||
// Note: the binding for `b` did not change and has no ValueWrapper,
|
// Note: the binding for `b` did not change and has no ValueWrapper,
|
||||||
// and should therefore stay unchanged.
|
// and should therefore stay unchanged.
|
||||||
expect(dir.changes).toEqual({
|
expect(dir.changes).toEqual({
|
||||||
'name': new SimpleChange('aName', 'aName', false),
|
'name': new SimpleChange('aName', 'aName', false),
|
||||||
'b': new SimpleChange(2, 2, false)
|
'b': new SimpleChange(2, 2, false)
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
expect(dir.changes).toEqual({
|
expect(dir.changes).toEqual({
|
||||||
'name': new SimpleChange('aName', 'aName', false),
|
'name': new SimpleChange('aName', 'aName', false),
|
||||||
'b': new SimpleChange(2, 2, false)
|
'b': new SimpleChange(2, 2, false)
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call pure pipes only if the arguments change', fakeAsync(() => {
|
it('should call pure pipes only if the arguments change', fakeAsync(() => {
|
||||||
const ctx = _bindSimpleValue('name | countingPipe', Person);
|
const ctx = _bindSimpleValue('name | countingPipe', Person);
|
||||||
@ -588,29 +591,30 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call pure pipes that are used multiple times only when the arguments change',
|
fixmeIvy('unknown').it(
|
||||||
fakeAsync(() => {
|
'should call pure pipes that are used multiple times only when the arguments change',
|
||||||
const ctx = createCompFixture(
|
fakeAsync(() => {
|
||||||
`<div [someProp]="name | countingPipe"></div><div [someProp]="age | countingPipe"></div>` +
|
const ctx = createCompFixture(
|
||||||
'<div *ngFor="let x of [1,2]" [someProp]="address.city | countingPipe"></div>',
|
`<div [someProp]="name | countingPipe"></div><div [someProp]="age | countingPipe"></div>` +
|
||||||
Person);
|
'<div *ngFor="let x of [1,2]" [someProp]="address.city | countingPipe"></div>',
|
||||||
ctx.componentInstance.name = 'a';
|
Person);
|
||||||
ctx.componentInstance.age = 10;
|
ctx.componentInstance.name = 'a';
|
||||||
ctx.componentInstance.address = new Address('mtv');
|
ctx.componentInstance.age = 10;
|
||||||
ctx.detectChanges(false);
|
ctx.componentInstance.address = new Address('mtv');
|
||||||
expect(renderLog.loggedValues).toEqual([
|
ctx.detectChanges(false);
|
||||||
'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3'
|
expect(renderLog.loggedValues).toEqual([
|
||||||
]);
|
'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3'
|
||||||
ctx.detectChanges(false);
|
]);
|
||||||
expect(renderLog.loggedValues).toEqual([
|
ctx.detectChanges(false);
|
||||||
'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3'
|
expect(renderLog.loggedValues).toEqual([
|
||||||
]);
|
'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3'
|
||||||
ctx.componentInstance.age = 11;
|
]);
|
||||||
ctx.detectChanges(false);
|
ctx.componentInstance.age = 11;
|
||||||
expect(renderLog.loggedValues).toEqual([
|
ctx.detectChanges(false);
|
||||||
'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3', '11 state:4'
|
expect(renderLog.loggedValues).toEqual([
|
||||||
]);
|
'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3', '11 state:4'
|
||||||
}));
|
]);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should call impure pipes on each change detection run', fakeAsync(() => {
|
it('should call impure pipes on each change detection run', fakeAsync(() => {
|
||||||
const ctx = _bindSimpleValue('name | countingImpurePipe', Person);
|
const ctx = _bindSimpleValue('name | countingImpurePipe', Person);
|
||||||
@ -994,31 +998,32 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]);
|
expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not call ngAfterViewInit again if it throws', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
const ctx =
|
'should not call ngAfterViewInit again if it throws', fakeAsync(() => {
|
||||||
createCompFixture('<div testDirective="dir" throwOn="ngAfterViewInit"></div>');
|
const ctx =
|
||||||
|
createCompFixture('<div testDirective="dir" throwOn="ngAfterViewInit"></div>');
|
||||||
|
|
||||||
let errored = false;
|
let errored = false;
|
||||||
// First pass fails, but ngAfterViewInit should be called.
|
// First pass fails, but ngAfterViewInit should be called.
|
||||||
try {
|
try {
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errored = true;
|
errored = true;
|
||||||
}
|
}
|
||||||
expect(errored).toBe(true);
|
expect(errored).toBe(true);
|
||||||
|
|
||||||
expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']);
|
expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']);
|
||||||
directiveLog.clear();
|
directiveLog.clear();
|
||||||
|
|
||||||
// Second change detection also fails, but this time ngAfterViewInit should not be
|
// Second change detection also fails, but this time ngAfterViewInit should not be
|
||||||
// called.
|
// called.
|
||||||
try {
|
try {
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('Second detectChanges() should not have run detection.');
|
throw new Error('Second detectChanges() should not have run detection.');
|
||||||
}
|
}
|
||||||
expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]);
|
expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ngAfterViewChecked', () => {
|
describe('ngAfterViewChecked', () => {
|
||||||
@ -1073,111 +1078,119 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('ngOnDestroy', () => {
|
describe('ngOnDestroy', () => {
|
||||||
it('should be called on view destruction', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
const ctx = createCompFixture('<div testDirective="dir"></div>');
|
'should be called on view destruction', fakeAsync(() => {
|
||||||
ctx.detectChanges(false);
|
const ctx = createCompFixture('<div testDirective="dir"></div>');
|
||||||
|
ctx.detectChanges(false);
|
||||||
|
|
||||||
ctx.destroy();
|
ctx.destroy();
|
||||||
|
|
||||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['dir.ngOnDestroy']);
|
expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['dir.ngOnDestroy']);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should be called after processing the content and view children', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.overrideComponent(AnotherComponent, {
|
'should be called after processing the content and view children', fakeAsync(() => {
|
||||||
set: new Component(
|
TestBed.overrideComponent(AnotherComponent, {
|
||||||
{selector: 'other-cmp', template: '<div testDirective="viewChild"></div>'})
|
set: new Component(
|
||||||
});
|
{selector: 'other-cmp', template: '<div testDirective="viewChild"></div>'})
|
||||||
|
});
|
||||||
|
|
||||||
const ctx = createCompFixture(
|
const ctx = createCompFixture(
|
||||||
'<div testDirective="parent"><div *ngFor="let x of [0,1]" testDirective="contentChild{{x}}"></div>' +
|
'<div testDirective="parent"><div *ngFor="let x of [0,1]" testDirective="contentChild{{x}}"></div>' +
|
||||||
'<other-cmp></other-cmp></div>',
|
'<other-cmp></other-cmp></div>',
|
||||||
TestComponent);
|
TestComponent);
|
||||||
|
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
ctx.destroy();
|
ctx.destroy();
|
||||||
|
|
||||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||||
'contentChild0.ngOnDestroy', 'contentChild1.ngOnDestroy', 'viewChild.ngOnDestroy',
|
'contentChild0.ngOnDestroy', 'contentChild1.ngOnDestroy', 'viewChild.ngOnDestroy',
|
||||||
'parent.ngOnDestroy'
|
'parent.ngOnDestroy'
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should be called in reverse order so the child is always notified before the parent',
|
fixmeIvy('unknown').it(
|
||||||
fakeAsync(() => {
|
'should be called in reverse order so the child is always notified before the parent',
|
||||||
const ctx = createCompFixture(
|
fakeAsync(() => {
|
||||||
'<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>');
|
const ctx = createCompFixture(
|
||||||
|
'<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>');
|
||||||
|
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
ctx.destroy();
|
ctx.destroy();
|
||||||
|
|
||||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||||
'child.ngOnDestroy', 'parent.ngOnDestroy', 'sibling.ngOnDestroy'
|
'child.ngOnDestroy', 'parent.ngOnDestroy', 'sibling.ngOnDestroy'
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should deliver synchronous events to parent', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
const ctx = createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>');
|
'should deliver synchronous events to parent', fakeAsync(() => {
|
||||||
|
const ctx = createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>');
|
||||||
|
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
ctx.destroy();
|
ctx.destroy();
|
||||||
|
|
||||||
expect(ctx.componentInstance.a).toEqual('destroyed');
|
expect(ctx.componentInstance.a).toEqual('destroyed');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call ngOnDestroy on pipes', fakeAsync(() => {
|
fixmeIvy('unknown').it('should call ngOnDestroy on pipes', fakeAsync(() => {
|
||||||
const ctx = createCompFixture('{{true | pipeWithOnDestroy }}');
|
const ctx = createCompFixture('{{true | pipeWithOnDestroy }}');
|
||||||
|
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
ctx.destroy();
|
ctx.destroy();
|
||||||
|
|
||||||
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
expect(directiveLog.filter(['ngOnDestroy'])).toEqual([
|
||||||
'pipeWithOnDestroy.ngOnDestroy'
|
'pipeWithOnDestroy.ngOnDestroy'
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call ngOnDestroy on an injectable class', fakeAsync(() => {
|
fixmeIvy('unknown').it('should call ngOnDestroy on an injectable class', fakeAsync(() => {
|
||||||
TestBed.overrideDirective(
|
TestBed.overrideDirective(
|
||||||
TestDirective, {set: {providers: [InjectableWithLifecycle]}});
|
TestDirective, {set: {providers: [InjectableWithLifecycle]}});
|
||||||
|
|
||||||
const ctx = createCompFixture('<div testDirective="dir"></div>', TestComponent);
|
const ctx = createCompFixture(
|
||||||
|
'<div testDirective="dir"></div>', TestComponent);
|
||||||
|
|
||||||
ctx.debugElement.children[0].injector.get(InjectableWithLifecycle);
|
ctx.debugElement.children[0].injector.get(InjectableWithLifecycle);
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
|
|
||||||
ctx.destroy();
|
ctx.destroy();
|
||||||
|
|
||||||
// We don't care about the exact order in this test.
|
// We don't care about the exact order in this test.
|
||||||
expect(directiveLog.filter(['ngOnDestroy']).sort()).toEqual([
|
expect(directiveLog.filter(['ngOnDestroy']).sort()).toEqual([
|
||||||
'dir.ngOnDestroy', 'injectable.ngOnDestroy'
|
'dir.ngOnDestroy', 'injectable.ngOnDestroy'
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('enforce no new changes', () => {
|
describe('enforce no new changes', () => {
|
||||||
it('should throw when a record gets changed after it has been checked', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
@Directive({selector: '[changed]'})
|
'should throw when a record gets changed after it has been checked', fakeAsync(() => {
|
||||||
class ChangingDirective {
|
@Directive({selector: '[changed]'})
|
||||||
@Input() changed: any;
|
class ChangingDirective {
|
||||||
}
|
@Input() changed: any;
|
||||||
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [ChangingDirective]});
|
TestBed.configureTestingModule({declarations: [ChangingDirective]});
|
||||||
|
|
||||||
const ctx = createCompFixture('<div [someProp]="a" [changed]="b"></div>', TestData);
|
const ctx = createCompFixture('<div [someProp]="a" [changed]="b"></div>', TestData);
|
||||||
|
|
||||||
ctx.componentInstance.b = 1;
|
ctx.componentInstance.b = 1;
|
||||||
|
|
||||||
expect(() => ctx.checkNoChanges())
|
expect(() => ctx.checkNoChanges())
|
||||||
.toThrowError(/Previous value: 'changed: undefined'\. Current value: 'changed: 1'/g);
|
.toThrowError(
|
||||||
}));
|
/Previous value: 'changed: undefined'\. Current value: 'changed: 1'/g);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should warn when the view has been created in a cd hook', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
const ctx = createCompFixture('<div *gh9882>{{ a }}</div>', TestData);
|
'should warn when the view has been created in a cd hook', fakeAsync(() => {
|
||||||
ctx.componentInstance.a = 1;
|
const ctx = createCompFixture('<div *gh9882>{{ a }}</div>', TestData);
|
||||||
expect(() => ctx.detectChanges())
|
ctx.componentInstance.a = 1;
|
||||||
.toThrowError(
|
expect(() => ctx.detectChanges())
|
||||||
/It seems like the view has been created after its parent and its children have been dirty checked/);
|
.toThrowError(
|
||||||
}));
|
/It seems like the view has been created after its parent and its children have been dirty checked/);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should not throw when two arrays are structurally the same', fakeAsync(() => {
|
it('should not throw when two arrays are structurally the same', fakeAsync(() => {
|
||||||
const ctx = _bindSimpleValue('a', TestData);
|
const ctx = _bindSimpleValue('a', TestData);
|
||||||
@ -1187,27 +1200,27 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
expect(() => ctx.checkNoChanges()).not.toThrow();
|
expect(() => ctx.checkNoChanges()).not.toThrow();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not break the next run', fakeAsync(() => {
|
fixmeIvy('unknown').it('should not break the next run', fakeAsync(() => {
|
||||||
const ctx = _bindSimpleValue('a', TestData);
|
const ctx = _bindSimpleValue('a', TestData);
|
||||||
ctx.componentInstance.a = 'value';
|
ctx.componentInstance.a = 'value';
|
||||||
expect(() => ctx.checkNoChanges()).toThrow();
|
expect(() => ctx.checkNoChanges()).toThrow();
|
||||||
|
|
||||||
ctx.detectChanges();
|
ctx.detectChanges();
|
||||||
expect(renderLog.loggedValues).toEqual(['value']);
|
expect(renderLog.loggedValues).toEqual(['value']);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('mode', () => {
|
describe('mode', () => {
|
||||||
it('Detached', fakeAsync(() => {
|
fixmeIvy('unknown').it('Detached', fakeAsync(() => {
|
||||||
const ctx = createCompFixture('<comp-with-ref></comp-with-ref>');
|
const ctx = createCompFixture('<comp-with-ref></comp-with-ref>');
|
||||||
const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0];
|
const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0];
|
||||||
cmp.value = 'hello';
|
cmp.value = 'hello';
|
||||||
cmp.changeDetectorRef.detach();
|
cmp.changeDetectorRef.detach();
|
||||||
|
|
||||||
ctx.detectChanges();
|
ctx.detectChanges();
|
||||||
|
|
||||||
expect(renderLog.log).toEqual([]);
|
expect(renderLog.log).toEqual([]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('Detached should disable OnPush', fakeAsync(() => {
|
it('Detached should disable OnPush', fakeAsync(() => {
|
||||||
const ctx = createCompFixture('<push-cmp [value]="value"></push-cmp>');
|
const ctx = createCompFixture('<push-cmp [value]="value"></push-cmp>');
|
||||||
@ -1260,34 +1273,36 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('Reattaches in the original cd mode', fakeAsync(() => {
|
fixmeIvy('unknown').it('Reattaches in the original cd mode', fakeAsync(() => {
|
||||||
const ctx = createCompFixture('<push-cmp></push-cmp>');
|
const ctx = createCompFixture('<push-cmp></push-cmp>');
|
||||||
const cmp: PushComp = queryDirs(ctx.debugElement, PushComp)[0];
|
const cmp: PushComp = queryDirs(ctx.debugElement, PushComp)[0];
|
||||||
cmp.changeDetectorRef.detach();
|
cmp.changeDetectorRef.detach();
|
||||||
cmp.changeDetectorRef.reattach();
|
cmp.changeDetectorRef.reattach();
|
||||||
|
|
||||||
// renderCount should NOT be incremented with each CD as CD mode should be resetted to
|
// renderCount should NOT be incremented with each CD as CD mode
|
||||||
// on-push
|
// should be resetted to
|
||||||
ctx.detectChanges();
|
// on-push
|
||||||
expect(cmp.renderCount).toBeGreaterThan(0);
|
ctx.detectChanges();
|
||||||
const count = cmp.renderCount;
|
expect(cmp.renderCount).toBeGreaterThan(0);
|
||||||
|
const count = cmp.renderCount;
|
||||||
|
|
||||||
ctx.detectChanges();
|
ctx.detectChanges();
|
||||||
expect(cmp.renderCount).toBe(count);
|
expect(cmp.renderCount).toBe(count);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('multi directive order', () => {
|
describe('multi directive order', () => {
|
||||||
it('should follow the DI order for the same element', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
const ctx =
|
'should follow the DI order for the same element', fakeAsync(() => {
|
||||||
createCompFixture('<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>');
|
const ctx =
|
||||||
|
createCompFixture('<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>');
|
||||||
|
|
||||||
ctx.detectChanges(false);
|
ctx.detectChanges(false);
|
||||||
ctx.destroy();
|
ctx.destroy();
|
||||||
|
|
||||||
expect(directiveLog.filter(['set'])).toEqual(['0.set', '1.set', '2.set']);
|
expect(directiveLog.filter(['set'])).toEqual(['0.set', '1.set', '2.set']);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('nested view recursion', () => {
|
describe('nested view recursion', () => {
|
||||||
@ -1424,25 +1439,26 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
expect(log).toEqual(['inner-start', 'main-tpl', 'outer-tpl']);
|
expect(log).toEqual(['inner-start', 'main-tpl', 'outer-tpl']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dirty check projected views if the declaration place is dirty checked', () => {
|
fixmeIvy('unknown').it(
|
||||||
ctx.detectChanges(false);
|
'should dirty check projected views if the declaration place is dirty checked', () => {
|
||||||
log = [];
|
ctx.detectChanges(false);
|
||||||
innerComp.cdRef.detach();
|
log = [];
|
||||||
mainComp.cdRef.detectChanges();
|
innerComp.cdRef.detach();
|
||||||
|
mainComp.cdRef.detectChanges();
|
||||||
|
|
||||||
expect(log).toEqual(['main-start', 'outer-start', 'main-tpl', 'outer-tpl']);
|
expect(log).toEqual(['main-start', 'outer-start', 'main-tpl', 'outer-tpl']);
|
||||||
|
|
||||||
log = [];
|
log = [];
|
||||||
outerComp.cdRef.detectChanges();
|
outerComp.cdRef.detectChanges();
|
||||||
|
|
||||||
expect(log).toEqual(['outer-start', 'outer-tpl']);
|
expect(log).toEqual(['outer-start', 'outer-tpl']);
|
||||||
|
|
||||||
log = [];
|
log = [];
|
||||||
outerComp.cdRef.detach();
|
outerComp.cdRef.detach();
|
||||||
mainComp.cdRef.detectChanges();
|
mainComp.cdRef.detectChanges();
|
||||||
|
|
||||||
expect(log).toEqual(['main-start', 'main-tpl']);
|
expect(log).toEqual(['main-start', 'main-tpl']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1516,7 +1532,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
|
|||||||
childThrows: LifetimeMethods;
|
childThrows: LifetimeMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('calling init', () => {
|
fixmeIvy('unknown').describe('calling init', () => {
|
||||||
function initialize(options: Options) {
|
function initialize(options: Options) {
|
||||||
@Component({selector: 'my-child', template: ''})
|
@Component({selector: 'my-child', template: ''})
|
||||||
class MyChild {
|
class MyChild {
|
||||||
|
@ -700,30 +700,31 @@ function declareTests(config?: {useJit: boolean}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (getDOM().supportsDOMEvents()) {
|
if (getDOM().supportsDOMEvents()) {
|
||||||
it('should be checked when an async pipe requests a check', fakeAsync(() => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule(
|
'should be checked when an async pipe requests a check', fakeAsync(() => {
|
||||||
{declarations: [MyComp, PushCmpWithAsyncPipe], imports: [CommonModule]});
|
TestBed.configureTestingModule(
|
||||||
const template = '<push-cmp-with-async #cmp></push-cmp-with-async>';
|
{declarations: [MyComp, PushCmpWithAsyncPipe], imports: [CommonModule]});
|
||||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
const template = '<push-cmp-with-async #cmp></push-cmp-with-async>';
|
||||||
const fixture = TestBed.createComponent(MyComp);
|
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||||
|
const fixture = TestBed.createComponent(MyComp);
|
||||||
|
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
const cmp: PushCmpWithAsyncPipe =
|
const cmp: PushCmpWithAsyncPipe =
|
||||||
fixture.debugElement.children[0].references !['cmp'];
|
fixture.debugElement.children[0].references !['cmp'];
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(cmp.numberOfChecks).toEqual(1);
|
expect(cmp.numberOfChecks).toEqual(1);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(cmp.numberOfChecks).toEqual(1);
|
expect(cmp.numberOfChecks).toEqual(1);
|
||||||
|
|
||||||
cmp.resolve(2);
|
cmp.resolve(2);
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(cmp.numberOfChecks).toEqual(2);
|
expect(cmp.numberOfChecks).toEqual(2);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1872,7 +1873,7 @@ function declareTests(config?: {useJit: boolean}) {
|
|||||||
|
|
||||||
if (getDOM().supportsDOMEvents()) {
|
if (getDOM().supportsDOMEvents()) {
|
||||||
describe('svg', () => {
|
describe('svg', () => {
|
||||||
it('should support svg elements', () => {
|
fixmeIvy('unknown').it('should support svg elements', () => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||||
const template = '<svg><use xlink:href="Port" /></svg>';
|
const template = '<svg><use xlink:href="Port" /></svg>';
|
||||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||||
@ -1891,7 +1892,7 @@ function declareTests(config?: {useJit: boolean}) {
|
|||||||
expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink');
|
expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support foreignObjects with document fragments', () => {
|
fixmeIvy('unknown').it('should support foreignObjects with document fragments', () => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||||
const template =
|
const template =
|
||||||
'<svg><foreignObject><xhtml:div><p>Test</p></xhtml:div></foreignObject></svg>';
|
'<svg><foreignObject><xhtml:div><p>Test</p></xhtml:div></foreignObject></svg>';
|
||||||
@ -1913,7 +1914,7 @@ function declareTests(config?: {useJit: boolean}) {
|
|||||||
|
|
||||||
describe('attributes', () => {
|
describe('attributes', () => {
|
||||||
|
|
||||||
it('should support attributes with namespace', () => {
|
fixmeIvy('unknown').it('should support attributes with namespace', () => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]});
|
TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]});
|
||||||
const template = '<svg:use xlink:href="#id" />';
|
const template = '<svg:use xlink:href="#id" />';
|
||||||
TestBed.overrideComponent(SomeCmp, {set: {template}});
|
TestBed.overrideComponent(SomeCmp, {set: {template}});
|
||||||
@ -1924,7 +1925,7 @@ function declareTests(config?: {useJit: boolean}) {
|
|||||||
.toEqual('#id');
|
.toEqual('#id');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support binding to attributes with namespace', () => {
|
fixmeIvy('unknown').it('should support binding to attributes with namespace', () => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]});
|
TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]});
|
||||||
const template = '<svg:use [attr.xlink:href]="value" />';
|
const template = '<svg:use [attr.xlink:href]="value" />';
|
||||||
TestBed.overrideComponent(SomeCmp, {set: {template}});
|
TestBed.overrideComponent(SomeCmp, {set: {template}});
|
||||||
|
@ -370,21 +370,22 @@ describe('projection', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (getDOM().supportsNativeShadowDOM()) {
|
if (getDOM().supportsNativeShadowDOM()) {
|
||||||
it('should support native content projection and isolate styles per component', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]});
|
'should support native content projection and isolate styles per component', () => {
|
||||||
TestBed.overrideComponent(MainComp, {
|
TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]});
|
||||||
set: {
|
TestBed.overrideComponent(MainComp, {
|
||||||
template: '<simple-native1><div>A</div></simple-native1>' +
|
set: {
|
||||||
'<simple-native2><div>B</div></simple-native2>'
|
template: '<simple-native1><div>A</div></simple-native1>' +
|
||||||
}
|
'<simple-native2><div>B</div></simple-native2>'
|
||||||
});
|
}
|
||||||
const main = TestBed.createComponent(MainComp);
|
});
|
||||||
|
const main = TestBed.createComponent(MainComp);
|
||||||
|
|
||||||
const childNodes = getDOM().childNodes(main.nativeElement);
|
const childNodes = getDOM().childNodes(main.nativeElement);
|
||||||
expect(childNodes[0]).toHaveText('div {color: red}SIMPLE1(A)');
|
expect(childNodes[0]).toHaveText('div {color: red}SIMPLE1(A)');
|
||||||
expect(childNodes[1]).toHaveText('div {color: blue}SIMPLE2(B)');
|
expect(childNodes[1]).toHaveText('div {color: blue}SIMPLE2(B)');
|
||||||
main.destroy();
|
main.destroy();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getDOM().supportsDOMEvents()) {
|
if (getDOM().supportsDOMEvents()) {
|
||||||
|
@ -428,7 +428,7 @@ function declareTestsUsingBootstrap() {
|
|||||||
if (getDOM().supportsDOMEvents()) {
|
if (getDOM().supportsDOMEvents()) {
|
||||||
// This test needs a real DOM....
|
// This test needs a real DOM....
|
||||||
|
|
||||||
it('should keep change detecting if there was an error', (done) => {
|
fixmeIvy('unknown').it('should keep change detecting if there was an error', (done) => {
|
||||||
@Component({
|
@Component({
|
||||||
selector: COMP_SELECTOR,
|
selector: COMP_SELECTOR,
|
||||||
template:
|
template:
|
||||||
|
@ -10,6 +10,7 @@ import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, Compon
|
|||||||
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
|
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
|
import {fixmeIvy} from '@angular/private/testing';
|
||||||
|
|
||||||
@Directive({selector: '[simpleDirective]'})
|
@Directive({selector: '[simpleDirective]'})
|
||||||
class SimpleDirective {
|
class SimpleDirective {
|
||||||
@ -291,7 +292,7 @@ class TestComp {
|
|||||||
expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2');
|
expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should instantiate viewProviders that have dependencies', () => {
|
fixmeIvy('unknown').it('should instantiate viewProviders that have dependencies', () => {
|
||||||
TestBed.configureTestingModule({declarations: [SimpleComponent]});
|
TestBed.configureTestingModule({declarations: [SimpleComponent]});
|
||||||
const viewProviders = [
|
const viewProviders = [
|
||||||
{provide: 'injectable1', useValue: 'injectable1'}, {
|
{provide: 'injectable1', useValue: 'injectable1'}, {
|
||||||
@ -428,7 +429,7 @@ class TestComp {
|
|||||||
expect(ctx.debugElement.injector.get('eager2')).toBe('v2: v1');
|
expect(ctx.debugElement.injector.get('eager2')).toBe('v2: v1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inject providers that were declared after it', () => {
|
fixmeIvy('unknown').it('should inject providers that were declared after it', () => {
|
||||||
@Component({
|
@Component({
|
||||||
template: '',
|
template: '',
|
||||||
providers: [
|
providers: [
|
||||||
@ -464,7 +465,7 @@ class TestComp {
|
|||||||
expect(comp.componentInstance.a).toBe('aValue');
|
expect(comp.componentInstance.a).toBe('aValue');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support ngOnDestroy for lazy providers', () => {
|
fixmeIvy('unknown').it('should support ngOnDestroy for lazy providers', () => {
|
||||||
let created = false;
|
let created = false;
|
||||||
let destroyed = false;
|
let destroyed = false;
|
||||||
|
|
||||||
@ -496,7 +497,7 @@ class TestComp {
|
|||||||
expect(destroyed).toBe(true);
|
expect(destroyed).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should instantiate view providers lazily', () => {
|
fixmeIvy('unknown').it('should instantiate view providers lazily', () => {
|
||||||
let created = false;
|
let created = false;
|
||||||
TestBed.configureTestingModule({declarations: [SimpleComponent]});
|
TestBed.configureTestingModule({declarations: [SimpleComponent]});
|
||||||
TestBed.overrideComponent(
|
TestBed.overrideComponent(
|
||||||
@ -551,38 +552,45 @@ class TestComp {
|
|||||||
.toEqual('parentService');
|
.toEqual('parentService');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should instantiate directives that depend on providers of a component', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
|
'should instantiate directives that depend on providers of a component', () => {
|
||||||
TestBed.overrideComponent(
|
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
|
||||||
SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
TestBed.overrideComponent(
|
||||||
TestBed.overrideComponent(SimpleComponent, {set: {template: '<div needsService></div>'}});
|
SimpleComponent,
|
||||||
const el = createComponent('<div simpleComponent></div>');
|
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
||||||
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
TestBed.overrideComponent(
|
||||||
.toEqual('hostService');
|
SimpleComponent, {set: {template: '<div needsService></div>'}});
|
||||||
});
|
const el = createComponent('<div simpleComponent></div>');
|
||||||
|
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
||||||
|
.toEqual('hostService');
|
||||||
|
});
|
||||||
|
|
||||||
it('should instantiate directives that depend on view providers of a component', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
|
'should instantiate directives that depend on view providers of a component', () => {
|
||||||
TestBed.overrideComponent(
|
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
|
||||||
SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
TestBed.overrideComponent(
|
||||||
TestBed.overrideComponent(SimpleComponent, {set: {template: '<div needsService></div>'}});
|
SimpleComponent,
|
||||||
const el = createComponent('<div simpleComponent></div>');
|
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
||||||
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
TestBed.overrideComponent(
|
||||||
.toEqual('hostService');
|
SimpleComponent, {set: {template: '<div needsService></div>'}});
|
||||||
});
|
const el = createComponent('<div simpleComponent></div>');
|
||||||
|
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
||||||
|
.toEqual('hostService');
|
||||||
|
});
|
||||||
|
|
||||||
it('should instantiate directives in a root embedded view that depend on view providers of a component',
|
fixmeIvy('unknown').it(
|
||||||
() => {
|
'should instantiate directives in a root embedded view that depend on view providers of a component',
|
||||||
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
|
() => {
|
||||||
TestBed.overrideComponent(
|
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
|
||||||
SimpleComponent,
|
TestBed.overrideComponent(
|
||||||
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
SimpleComponent,
|
||||||
TestBed.overrideComponent(
|
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
||||||
SimpleComponent, {set: {template: '<div *ngIf="true" needsService></div>'}});
|
TestBed.overrideComponent(
|
||||||
const el = createComponent('<div simpleComponent></div>');
|
SimpleComponent, {set: {template: '<div *ngIf="true" needsService></div>'}});
|
||||||
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
const el = createComponent('<div simpleComponent></div>');
|
||||||
.toEqual('hostService');
|
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
||||||
});
|
.toEqual('hostService');
|
||||||
|
});
|
||||||
|
|
||||||
it('should instantiate directives that depend on instances in the app injector', () => {
|
it('should instantiate directives that depend on instances in the app injector', () => {
|
||||||
TestBed.configureTestingModule({declarations: [NeedsAppService]});
|
TestBed.configureTestingModule({declarations: [NeedsAppService]});
|
||||||
@ -590,54 +598,57 @@ class TestComp {
|
|||||||
expect(el.children[0].injector.get(NeedsAppService).service).toEqual('appService');
|
expect(el.children[0].injector.get(NeedsAppService).service).toEqual('appService');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not instantiate a directive with cyclic dependencies', () => {
|
fixmeIvy('unknown').it('should not instantiate a directive with cyclic dependencies', () => {
|
||||||
TestBed.configureTestingModule({declarations: [CycleDirective]});
|
TestBed.configureTestingModule({declarations: [CycleDirective]});
|
||||||
expect(() => createComponent('<div cycleDirective></div>'))
|
expect(() => createComponent('<div cycleDirective></div>'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
/Template parse errors:\nCannot instantiate cyclic dependency! CycleDirective \("\[ERROR ->\]<div cycleDirective><\/div>"\): .*TestComp.html@0:0/);
|
/Template parse errors:\nCannot instantiate cyclic dependency! CycleDirective \("\[ERROR ->\]<div cycleDirective><\/div>"\): .*TestComp.html@0:0/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not instantiate a directive in a view that has a host dependency on providers' +
|
fixmeIvy('unknown').it(
|
||||||
' of the component',
|
'should not instantiate a directive in a view that has a host dependency on providers' +
|
||||||
() => {
|
' of the component',
|
||||||
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsServiceFromHost]});
|
() => {
|
||||||
TestBed.overrideComponent(
|
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsServiceFromHost]});
|
||||||
SimpleComponent,
|
TestBed.overrideComponent(
|
||||||
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
SimpleComponent,
|
||||||
TestBed.overrideComponent(
|
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
||||||
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
|
TestBed.overrideComponent(
|
||||||
|
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
|
||||||
|
|
||||||
expect(() => createComponent('<div simpleComponent></div>'))
|
expect(() => createComponent('<div simpleComponent></div>'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/);
|
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not instantiate a directive in a view that has a host dependency on providers' +
|
fixmeIvy('unknown').it(
|
||||||
' of a decorator directive',
|
'should not instantiate a directive in a view that has a host dependency on providers' +
|
||||||
() => {
|
' of a decorator directive',
|
||||||
TestBed.configureTestingModule(
|
() => {
|
||||||
{declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]});
|
TestBed.configureTestingModule(
|
||||||
TestBed.overrideComponent(
|
{declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]});
|
||||||
SimpleComponent,
|
TestBed.overrideComponent(
|
||||||
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
SimpleComponent,
|
||||||
TestBed.overrideComponent(
|
{set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
|
||||||
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
|
TestBed.overrideComponent(
|
||||||
|
SimpleComponent, {set: {template: '<div needsServiceFromHost><div>'}});
|
||||||
|
|
||||||
expect(() => createComponent('<div simpleComponent someOtherDirective></div>'))
|
expect(() => createComponent('<div simpleComponent someOtherDirective></div>'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/);
|
/Template parse errors:\nNo provider for service \("\[ERROR ->\]<div needsServiceFromHost><div>"\): .*SimpleComponent.html@0:0/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not instantiate a directive in a view that has a self dependency on a parent directive',
|
fixmeIvy('unknown').it(
|
||||||
() => {
|
'should not instantiate a directive in a view that has a self dependency on a parent directive',
|
||||||
TestBed.configureTestingModule(
|
() => {
|
||||||
{declarations: [SimpleDirective, NeedsDirectiveFromSelf]});
|
TestBed.configureTestingModule(
|
||||||
expect(
|
{declarations: [SimpleDirective, NeedsDirectiveFromSelf]});
|
||||||
() =>
|
expect(
|
||||||
createComponent('<div simpleDirective><div needsDirectiveFromSelf></div></div>'))
|
() => createComponent(
|
||||||
.toThrowError(
|
'<div simpleDirective><div needsDirectiveFromSelf></div></div>'))
|
||||||
/Template parse errors:\nNo provider for SimpleDirective \("<div simpleDirective>\[ERROR ->\]<div needsDirectiveFromSelf><\/div><\/div>"\): .*TestComp.html@0:21/);
|
.toThrowError(
|
||||||
});
|
/Template parse errors:\nNo provider for SimpleDirective \("<div simpleDirective>\[ERROR ->\]<div needsDirectiveFromSelf><\/div><\/div>"\): .*TestComp.html@0:21/);
|
||||||
|
});
|
||||||
|
|
||||||
it('should instantiate directives that depend on other directives', fakeAsync(() => {
|
it('should instantiate directives that depend on other directives', fakeAsync(() => {
|
||||||
TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]});
|
TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]});
|
||||||
@ -662,48 +673,54 @@ class TestComp {
|
|||||||
expect(d.dependency).toBeNull();
|
expect(d.dependency).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should instantiate directives that depends on the host component', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsComponentFromHost]});
|
'should instantiate directives that depends on the host component', () => {
|
||||||
TestBed.overrideComponent(
|
TestBed.configureTestingModule(
|
||||||
SimpleComponent, {set: {template: '<div needsComponentFromHost></div>'}});
|
{declarations: [SimpleComponent, NeedsComponentFromHost]});
|
||||||
const el = createComponent('<div simpleComponent></div>');
|
TestBed.overrideComponent(
|
||||||
const d = el.children[0].children[0].injector.get(NeedsComponentFromHost);
|
SimpleComponent, {set: {template: '<div needsComponentFromHost></div>'}});
|
||||||
expect(d.dependency).toBeAnInstanceOf(SimpleComponent);
|
const el = createComponent('<div simpleComponent></div>');
|
||||||
});
|
const d = el.children[0].children[0].injector.get(NeedsComponentFromHost);
|
||||||
|
expect(d.dependency).toBeAnInstanceOf(SimpleComponent);
|
||||||
|
});
|
||||||
|
|
||||||
it('should instantiate host views for components that have a @Host dependency ', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule({declarations: [NeedsHostAppService]});
|
'should instantiate host views for components that have a @Host dependency ', () => {
|
||||||
const el = createComponent('', [], NeedsHostAppService);
|
TestBed.configureTestingModule({declarations: [NeedsHostAppService]});
|
||||||
expect(el.componentInstance.service).toEqual('appService');
|
const el = createComponent('', [], NeedsHostAppService);
|
||||||
});
|
expect(el.componentInstance.service).toEqual('appService');
|
||||||
|
});
|
||||||
|
|
||||||
it('should not instantiate directives that depend on other directives on the host element', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule(
|
'should not instantiate directives that depend on other directives on the host element',
|
||||||
{declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]});
|
() => {
|
||||||
TestBed.overrideComponent(
|
TestBed.configureTestingModule(
|
||||||
SimpleComponent, {set: {template: '<div needsDirectiveFromHost></div>'}});
|
{declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]});
|
||||||
expect(() => createComponent('<div simpleComponent simpleDirective></div>'))
|
TestBed.overrideComponent(
|
||||||
.toThrowError(
|
SimpleComponent, {set: {template: '<div needsDirectiveFromHost></div>'}});
|
||||||
/Template parse errors:\nNo provider for SimpleDirective \("\[ERROR ->\]<div needsDirectiveFromHost><\/div>"\): .*SimpleComponent.html@0:0/);
|
expect(() => createComponent('<div simpleComponent simpleDirective></div>'))
|
||||||
});
|
.toThrowError(
|
||||||
|
/Template parse errors:\nNo provider for SimpleDirective \("\[ERROR ->\]<div needsDirectiveFromHost><\/div>"\): .*SimpleComponent.html@0:0/);
|
||||||
|
});
|
||||||
|
|
||||||
it('should allow to use the NgModule injector from a root ViewContainerRef.parentInjector',
|
fixmeIvy('unknown').it(
|
||||||
() => {
|
'should allow to use the NgModule injector from a root ViewContainerRef.parentInjector',
|
||||||
@Component({template: ''})
|
() => {
|
||||||
class MyComp {
|
@Component({template: ''})
|
||||||
constructor(public vc: ViewContainerRef) {}
|
class MyComp {
|
||||||
}
|
constructor(public vc: ViewContainerRef) {}
|
||||||
|
}
|
||||||
|
|
||||||
const compFixture = TestBed
|
const compFixture = TestBed
|
||||||
.configureTestingModule({
|
.configureTestingModule({
|
||||||
declarations: [MyComp],
|
declarations: [MyComp],
|
||||||
providers: [{provide: 'someToken', useValue: 'someValue'}]
|
providers: [{provide: 'someToken', useValue: 'someValue'}]
|
||||||
})
|
})
|
||||||
.createComponent(MyComp);
|
.createComponent(MyComp);
|
||||||
|
|
||||||
expect(compFixture.componentInstance.vc.parentInjector.get('someToken'))
|
expect(compFixture.componentInstance.vc.parentInjector.get('someToken'))
|
||||||
.toBe('someValue');
|
.toBe('someValue');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('static attributes', () => {
|
describe('static attributes', () => {
|
||||||
@ -734,85 +751,97 @@ class TestComp {
|
|||||||
.toBe(el.children[0].nativeElement);
|
.toBe(el.children[0].nativeElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inject ChangeDetectorRef of the component\'s view into the component', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule({declarations: [PushComponentNeedsChangeDetectorRef]});
|
'should inject ChangeDetectorRef of the component\'s view into the component', () => {
|
||||||
const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>');
|
TestBed.configureTestingModule({declarations: [PushComponentNeedsChangeDetectorRef]});
|
||||||
cf.detectChanges();
|
const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>');
|
||||||
const compEl = cf.debugElement.children[0];
|
cf.detectChanges();
|
||||||
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
const compEl = cf.debugElement.children[0];
|
||||||
comp.counter = 1;
|
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
||||||
cf.detectChanges();
|
comp.counter = 1;
|
||||||
expect(compEl.nativeElement).toHaveText('0');
|
cf.detectChanges();
|
||||||
comp.changeDetectorRef.markForCheck();
|
expect(compEl.nativeElement).toHaveText('0');
|
||||||
cf.detectChanges();
|
comp.changeDetectorRef.markForCheck();
|
||||||
expect(compEl.nativeElement).toHaveText('1');
|
cf.detectChanges();
|
||||||
});
|
expect(compEl.nativeElement).toHaveText('1');
|
||||||
|
});
|
||||||
|
|
||||||
it('should inject ChangeDetectorRef of the containing component into directives', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule(
|
'should inject ChangeDetectorRef of the containing component into directives', () => {
|
||||||
{declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]});
|
TestBed.configureTestingModule({
|
||||||
TestBed.overrideComponent(PushComponentNeedsChangeDetectorRef, {
|
declarations:
|
||||||
set: {
|
[PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
|
||||||
template:
|
});
|
||||||
'{{counter}}<div directiveNeedsChangeDetectorRef></div><div *ngIf="true" directiveNeedsChangeDetectorRef></div>'
|
TestBed.overrideComponent(PushComponentNeedsChangeDetectorRef, {
|
||||||
}
|
set: {
|
||||||
});
|
template:
|
||||||
const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>');
|
'{{counter}}<div directiveNeedsChangeDetectorRef></div><div *ngIf="true" directiveNeedsChangeDetectorRef></div>'
|
||||||
cf.detectChanges();
|
}
|
||||||
const compEl = cf.debugElement.children[0];
|
});
|
||||||
const comp: PushComponentNeedsChangeDetectorRef =
|
const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>');
|
||||||
compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
cf.detectChanges();
|
||||||
comp.counter = 1;
|
const compEl = cf.debugElement.children[0];
|
||||||
cf.detectChanges();
|
const comp: PushComponentNeedsChangeDetectorRef =
|
||||||
expect(compEl.nativeElement).toHaveText('0');
|
compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
||||||
expect(compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
|
comp.counter = 1;
|
||||||
.toEqual(comp.changeDetectorRef);
|
cf.detectChanges();
|
||||||
expect(compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
|
expect(compEl.nativeElement).toHaveText('0');
|
||||||
.toEqual(comp.changeDetectorRef);
|
expect(
|
||||||
comp.changeDetectorRef.markForCheck();
|
compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
|
||||||
cf.detectChanges();
|
.toEqual(comp.changeDetectorRef);
|
||||||
expect(compEl.nativeElement).toHaveText('1');
|
expect(
|
||||||
});
|
compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
|
||||||
|
.toEqual(comp.changeDetectorRef);
|
||||||
|
comp.changeDetectorRef.markForCheck();
|
||||||
|
cf.detectChanges();
|
||||||
|
expect(compEl.nativeElement).toHaveText('1');
|
||||||
|
});
|
||||||
|
|
||||||
it('should inject ChangeDetectorRef of a same element component into a directive', () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed.configureTestingModule(
|
'should inject ChangeDetectorRef of a same element component into a directive', () => {
|
||||||
{declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]});
|
TestBed.configureTestingModule({
|
||||||
const cf = createComponentFixture(
|
declarations:
|
||||||
'<div componentNeedsChangeDetectorRef directiveNeedsChangeDetectorRef></div>');
|
[PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
|
||||||
cf.detectChanges();
|
});
|
||||||
const compEl = cf.debugElement.children[0];
|
const cf = createComponentFixture(
|
||||||
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
'<div componentNeedsChangeDetectorRef directiveNeedsChangeDetectorRef></div>');
|
||||||
const dir = compEl.injector.get(DirectiveNeedsChangeDetectorRef);
|
cf.detectChanges();
|
||||||
comp.counter = 1;
|
const compEl = cf.debugElement.children[0];
|
||||||
cf.detectChanges();
|
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
||||||
expect(compEl.nativeElement).toHaveText('0');
|
const dir = compEl.injector.get(DirectiveNeedsChangeDetectorRef);
|
||||||
dir.changeDetectorRef.markForCheck();
|
comp.counter = 1;
|
||||||
cf.detectChanges();
|
cf.detectChanges();
|
||||||
expect(compEl.nativeElement).toHaveText('1');
|
expect(compEl.nativeElement).toHaveText('0');
|
||||||
});
|
dir.changeDetectorRef.markForCheck();
|
||||||
|
cf.detectChanges();
|
||||||
|
expect(compEl.nativeElement).toHaveText('1');
|
||||||
|
});
|
||||||
|
|
||||||
it(`should not inject ChangeDetectorRef of a parent element's component into a directive`, () => {
|
fixmeIvy('unknown').it(
|
||||||
TestBed
|
`should not inject ChangeDetectorRef of a parent element's component into a directive`,
|
||||||
.configureTestingModule({
|
() => {
|
||||||
declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
|
TestBed
|
||||||
})
|
.configureTestingModule({
|
||||||
.overrideComponent(
|
declarations:
|
||||||
PushComponentNeedsChangeDetectorRef,
|
[PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
|
||||||
{set: {template: '<ng-content></ng-content>{{counter}}'}});
|
})
|
||||||
const cf = createComponentFixture(
|
.overrideComponent(
|
||||||
'<div componentNeedsChangeDetectorRef><div directiveNeedsChangeDetectorRef></div></div>');
|
PushComponentNeedsChangeDetectorRef,
|
||||||
cf.detectChanges();
|
{set: {template: '<ng-content></ng-content>{{counter}}'}});
|
||||||
const compEl = cf.debugElement.children[0];
|
const cf = createComponentFixture(
|
||||||
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
'<div componentNeedsChangeDetectorRef><div directiveNeedsChangeDetectorRef></div></div>');
|
||||||
const dirEl = compEl.children[0];
|
cf.detectChanges();
|
||||||
const dir = dirEl.injector.get(DirectiveNeedsChangeDetectorRef);
|
const compEl = cf.debugElement.children[0];
|
||||||
comp.counter = 1;
|
const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef);
|
||||||
cf.detectChanges();
|
const dirEl = compEl.children[0];
|
||||||
expect(compEl.nativeElement).toHaveText('0');
|
const dir = dirEl.injector.get(DirectiveNeedsChangeDetectorRef);
|
||||||
dir.changeDetectorRef.markForCheck();
|
comp.counter = 1;
|
||||||
cf.detectChanges();
|
cf.detectChanges();
|
||||||
expect(compEl.nativeElement).toHaveText('0');
|
expect(compEl.nativeElement).toHaveText('0');
|
||||||
});
|
dir.changeDetectorRef.markForCheck();
|
||||||
|
cf.detectChanges();
|
||||||
|
expect(compEl.nativeElement).toHaveText('0');
|
||||||
|
});
|
||||||
|
|
||||||
it('should inject ViewContainerRef', () => {
|
it('should inject ViewContainerRef', () => {
|
||||||
TestBed.configureTestingModule({declarations: [NeedsViewContainerRef]});
|
TestBed.configureTestingModule({declarations: [NeedsViewContainerRef]});
|
||||||
@ -822,7 +851,7 @@ class TestComp {
|
|||||||
.toBe(el.children[0].nativeElement);
|
.toBe(el.children[0].nativeElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inject ViewContainerRef', () => {
|
fixmeIvy('unknown').it('should inject ViewContainerRef', () => {
|
||||||
@Component({template: ''})
|
@Component({template: ''})
|
||||||
class TestComp {
|
class TestComp {
|
||||||
constructor(public vcr: ViewContainerRef) {}
|
constructor(public vcr: ViewContainerRef) {}
|
||||||
@ -847,7 +876,7 @@ class TestComp {
|
|||||||
expect(component.instance.vcr.parentInjector.get('someToken')).toBe('someNewValue');
|
expect(component.instance.vcr.parentInjector.get('someToken')).toBe('someNewValue');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inject TemplateRef', () => {
|
fixmeIvy('unknown').it('should inject TemplateRef', () => {
|
||||||
TestBed.configureTestingModule({declarations: [NeedsViewContainerRef, NeedsTemplateRef]});
|
TestBed.configureTestingModule({declarations: [NeedsViewContainerRef, NeedsTemplateRef]});
|
||||||
const el =
|
const el =
|
||||||
createComponent('<ng-template needsViewContainerRef needsTemplateRef></ng-template>');
|
createComponent('<ng-template needsViewContainerRef needsTemplateRef></ng-template>');
|
||||||
@ -855,7 +884,7 @@ class TestComp {
|
|||||||
.toEqual(el.childNodes[0].injector.get(NeedsViewContainerRef).viewContainer.element);
|
.toEqual(el.childNodes[0].injector.get(NeedsViewContainerRef).viewContainer.element);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if there is no TemplateRef', () => {
|
fixmeIvy('unknown').it('should throw if there is no TemplateRef', () => {
|
||||||
TestBed.configureTestingModule({declarations: [NeedsTemplateRef]});
|
TestBed.configureTestingModule({declarations: [NeedsTemplateRef]});
|
||||||
expect(() => createComponent('<div needsTemplateRef></div>'))
|
expect(() => createComponent('<div needsTemplateRef></div>'))
|
||||||
.toThrowError(/No provider for TemplateRef!/);
|
.toThrowError(/No provider for TemplateRef!/);
|
||||||
@ -870,7 +899,7 @@ class TestComp {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('pipes', () => {
|
describe('pipes', () => {
|
||||||
it('should instantiate pipes that have dependencies', () => {
|
fixmeIvy('unknown').it('should instantiate pipes that have dependencies', () => {
|
||||||
TestBed.configureTestingModule({declarations: [SimpleDirective, PipeNeedsService]});
|
TestBed.configureTestingModule({declarations: [SimpleDirective, PipeNeedsService]});
|
||||||
|
|
||||||
const el = createComponent(
|
const el = createComponent(
|
||||||
@ -879,7 +908,7 @@ class TestComp {
|
|||||||
expect(el.children[0].injector.get(SimpleDirective).value.service).toEqual('pipeService');
|
expect(el.children[0].injector.get(SimpleDirective).value.service).toEqual('pipeService');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should overwrite pipes with later entry in the pipes array', () => {
|
fixmeIvy('unknown').it('should overwrite pipes with later entry in the pipes array', () => {
|
||||||
TestBed.configureTestingModule(
|
TestBed.configureTestingModule(
|
||||||
{declarations: [SimpleDirective, DuplicatePipe1, DuplicatePipe2]});
|
{declarations: [SimpleDirective, DuplicatePipe1, DuplicatePipe2]});
|
||||||
const el = createComponent('<div [simpleDirective]="true | duplicatePipe"></div>');
|
const el = createComponent('<div [simpleDirective]="true | duplicatePipe"></div>');
|
||||||
@ -898,7 +927,7 @@ class TestComp {
|
|||||||
expect(el.children[0].injector.get(SimpleDirective).value.changeDetectorRef).toEqual(cdRef);
|
expect(el.children[0].injector.get(SimpleDirective).value.changeDetectorRef).toEqual(cdRef);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should cache pure pipes', () => {
|
fixmeIvy('unknown').it('should cache pure pipes', () => {
|
||||||
TestBed.configureTestingModule({declarations: [SimpleDirective, PurePipe]});
|
TestBed.configureTestingModule({declarations: [SimpleDirective, PurePipe]});
|
||||||
const el = createComponent(
|
const el = createComponent(
|
||||||
'<div [simpleDirective]="true | purePipe"></div><div [simpleDirective]="true | purePipe"></div>' +
|
'<div [simpleDirective]="true | purePipe"></div><div [simpleDirective]="true | purePipe"></div>' +
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import {SecurityContext} from '@angular/core';
|
import {SecurityContext} from '@angular/core';
|
||||||
import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, ViewFlags, ViewState, asElementData, directiveDef, elementDef, rootRenderNodes} from '@angular/core/src/view/index';
|
import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, ViewFlags, ViewState, asElementData, directiveDef, elementDef, rootRenderNodes} from '@angular/core/src/view/index';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
|
import {fixmeIvy} from '@angular/private/testing';
|
||||||
|
|
||||||
import {callMostRecentEventListenerHandler, compViewDef, createAndGetRootNodes, createRootView, isBrowser, recordNodeToRemove} from './helper';
|
import {callMostRecentEventListenerHandler, compViewDef, createAndGetRootNodes, createRootView, isBrowser, recordNodeToRemove} from './helper';
|
||||||
|
|
||||||
@ -199,62 +200,64 @@ const addEventListener = '__zone_symbol__addEventListener' as 'addEventListener'
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isBrowser()) {
|
if (isBrowser()) {
|
||||||
it('should support OnPush components', () => {
|
fixmeIvy('FW-665: Discovery util fails with "Unable to find context associated with ..."')
|
||||||
let compInputValue: any;
|
.it('should support OnPush components', () => {
|
||||||
class AComp {
|
let compInputValue: any;
|
||||||
a: any;
|
class AComp {
|
||||||
}
|
a: any;
|
||||||
|
}
|
||||||
|
|
||||||
const update = jasmine.createSpy('updater');
|
const update = jasmine.createSpy('updater');
|
||||||
|
|
||||||
const addListenerSpy = spyOn(HTMLElement.prototype, addEventListener).and.callThrough();
|
const addListenerSpy =
|
||||||
|
spyOn(HTMLElement.prototype, addEventListener).and.callThrough();
|
||||||
|
|
||||||
const {view} = createAndGetRootNodes(compViewDef(
|
const {view} = createAndGetRootNodes(compViewDef(
|
||||||
[
|
[
|
||||||
elementDef(
|
elementDef(
|
||||||
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
|
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
|
||||||
() => {
|
() => {
|
||||||
return compViewDef(
|
return compViewDef(
|
||||||
[
|
[
|
||||||
elementDef(
|
elementDef(
|
||||||
0, NodeFlags.None, null, null, 0, 'span', null, null,
|
0, NodeFlags.None, null, null, 0, 'span', null, null,
|
||||||
[[null !, 'click']]),
|
[[null !, 'click']]),
|
||||||
],
|
],
|
||||||
update, null, ViewFlags.OnPush);
|
update, null, ViewFlags.OnPush);
|
||||||
}),
|
}),
|
||||||
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], {a: [0, 'a']}),
|
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], {a: [0, 'a']}),
|
||||||
],
|
],
|
||||||
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
|
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
|
||||||
|
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
|
|
||||||
// auto detach
|
// auto detach
|
||||||
update.calls.reset();
|
update.calls.reset();
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
expect(update).not.toHaveBeenCalled();
|
expect(update).not.toHaveBeenCalled();
|
||||||
|
|
||||||
// auto attach on input changes
|
// auto attach on input changes
|
||||||
update.calls.reset();
|
update.calls.reset();
|
||||||
compInputValue = 'v1';
|
compInputValue = 'v1';
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
expect(update).toHaveBeenCalled();
|
expect(update).toHaveBeenCalled();
|
||||||
|
|
||||||
// auto detach
|
// auto detach
|
||||||
update.calls.reset();
|
update.calls.reset();
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
expect(update).not.toHaveBeenCalled();
|
expect(update).not.toHaveBeenCalled();
|
||||||
|
|
||||||
// auto attach on events
|
// auto attach on events
|
||||||
callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent');
|
callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent');
|
||||||
update.calls.reset();
|
update.calls.reset();
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
expect(update).toHaveBeenCalled();
|
expect(update).toHaveBeenCalled();
|
||||||
|
|
||||||
// auto detach
|
// auto detach
|
||||||
update.calls.reset();
|
update.calls.reset();
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
expect(update).not.toHaveBeenCalled();
|
expect(update).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should not stop dirty checking views that threw errors in change detection', () => {
|
it('should not stop dirty checking views that threw errors in change detection', () => {
|
||||||
|
@ -11,6 +11,7 @@ import {getDebugContext} from '@angular/core/src/errors';
|
|||||||
import {BindingFlags, NodeFlags, Services, ViewData, ViewDefinition, asElementData, elementDef} from '@angular/core/src/view/index';
|
import {BindingFlags, NodeFlags, Services, ViewData, ViewDefinition, asElementData, elementDef} from '@angular/core/src/view/index';
|
||||||
import {TestBed} from '@angular/core/testing';
|
import {TestBed} from '@angular/core/testing';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
|
import {fixmeIvy} from '@angular/private/testing';
|
||||||
|
|
||||||
import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes, isBrowser, recordNodeToRemove} from './helper';
|
import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes, isBrowser, recordNodeToRemove} from './helper';
|
||||||
|
|
||||||
@ -184,26 +185,27 @@ const removeEventListener = '__zone_symbol__removeEventListener' as 'removeEvent
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should listen to DOM events', () => {
|
fixmeIvy('FW-665: Discovery util fails with "Unable to find context associated with ..."')
|
||||||
const handleEventSpy = jasmine.createSpy('handleEvent');
|
.it('should listen to DOM events', () => {
|
||||||
const removeListenerSpy =
|
const handleEventSpy = jasmine.createSpy('handleEvent');
|
||||||
spyOn(HTMLElement.prototype, removeEventListener).and.callThrough();
|
const removeListenerSpy =
|
||||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
spyOn(HTMLElement.prototype, removeEventListener).and.callThrough();
|
||||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
||||||
handleEventSpy)]));
|
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
||||||
|
handleEventSpy)]));
|
||||||
|
|
||||||
rootNodes[0].click();
|
rootNodes[0].click();
|
||||||
|
|
||||||
expect(handleEventSpy).toHaveBeenCalled();
|
expect(handleEventSpy).toHaveBeenCalled();
|
||||||
let handleEventArgs = handleEventSpy.calls.mostRecent().args;
|
let handleEventArgs = handleEventSpy.calls.mostRecent().args;
|
||||||
expect(handleEventArgs[0]).toBe(view);
|
expect(handleEventArgs[0]).toBe(view);
|
||||||
expect(handleEventArgs[1]).toBe('click');
|
expect(handleEventArgs[1]).toBe('click');
|
||||||
expect(handleEventArgs[2]).toBeTruthy();
|
expect(handleEventArgs[2]).toBeTruthy();
|
||||||
|
|
||||||
Services.destroyView(view);
|
Services.destroyView(view);
|
||||||
|
|
||||||
expect(removeListenerSpy).toHaveBeenCalled();
|
expect(removeListenerSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should listen to window events', () => {
|
it('should listen to window events', () => {
|
||||||
const handleEventSpy = jasmine.createSpy('handleEvent');
|
const handleEventSpy = jasmine.createSpy('handleEvent');
|
||||||
@ -251,49 +253,52 @@ const removeEventListener = '__zone_symbol__removeEventListener' as 'removeEvent
|
|||||||
expect(removeListenerSpy).toHaveBeenCalled();
|
expect(removeListenerSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should preventDefault only if the handler returns false', () => {
|
fixmeIvy('FW-665: Discovery util fails with "Unable to find context associated with ..."')
|
||||||
let eventHandlerResult: any;
|
.it('should preventDefault only if the handler returns false', () => {
|
||||||
let preventDefaultSpy: jasmine.Spy = undefined !;
|
let eventHandlerResult: any;
|
||||||
|
let preventDefaultSpy: jasmine.Spy = undefined !;
|
||||||
|
|
||||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
||||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
||||||
(view, eventName, event) => {
|
(view, eventName, event) => {
|
||||||
preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();
|
preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();
|
||||||
return eventHandlerResult;
|
return eventHandlerResult;
|
||||||
})]));
|
})]));
|
||||||
|
|
||||||
eventHandlerResult = undefined;
|
eventHandlerResult = undefined;
|
||||||
rootNodes[0].click();
|
rootNodes[0].click();
|
||||||
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
eventHandlerResult = true;
|
eventHandlerResult = true;
|
||||||
rootNodes[0].click();
|
rootNodes[0].click();
|
||||||
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
eventHandlerResult = 'someString';
|
eventHandlerResult = 'someString';
|
||||||
rootNodes[0].click();
|
rootNodes[0].click();
|
||||||
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
||||||
|
|
||||||
eventHandlerResult = false;
|
eventHandlerResult = false;
|
||||||
rootNodes[0].click();
|
rootNodes[0].click();
|
||||||
expect(preventDefaultSpy).toHaveBeenCalled();
|
expect(preventDefaultSpy).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report debug info on event errors', () => {
|
fixmeIvy('FW-665: Discovery util fails with "Unable to find context associated with ..."')
|
||||||
const handleErrorSpy = spyOn(TestBed.get(ErrorHandler), 'handleError');
|
.it('should report debug info on event errors', () => {
|
||||||
const addListenerSpy = spyOn(HTMLElement.prototype, addEventListener).and.callThrough();
|
const handleErrorSpy = spyOn(TestBed.get(ErrorHandler), 'handleError');
|
||||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
const addListenerSpy =
|
||||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
spyOn(HTMLElement.prototype, addEventListener).and.callThrough();
|
||||||
() => { throw new Error('Test'); })]));
|
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
||||||
|
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
||||||
|
() => { throw new Error('Test'); })]));
|
||||||
|
|
||||||
callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent');
|
callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent');
|
||||||
const err = handleErrorSpy.calls.mostRecent().args[0];
|
const err = handleErrorSpy.calls.mostRecent().args[0];
|
||||||
expect(err).toBeTruthy();
|
expect(err).toBeTruthy();
|
||||||
expect(err.message).toBe('Test');
|
expect(err.message).toBe('Test');
|
||||||
const debugCtx = getDebugContext(err);
|
const debugCtx = getDebugContext(err);
|
||||||
expect(debugCtx.view).toBe(view);
|
expect(debugCtx.view).toBe(view);
|
||||||
expect(debugCtx.nodeIndex).toBe(0);
|
expect(debugCtx.nodeIndex).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user