test(ivy): run browser-specific @angular/core tests on CI (#27545)

PR Close #27545
This commit is contained in:
Pawel Kozlowski 2018-12-07 14:05:03 +01:00 committed by Alex Rickabaugh
parent aa48810d80
commit 5657126d86
12 changed files with 2751 additions and 2645 deletions

View File

@ -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",
], ],

View File

@ -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 {AUTO_STYLE, AnimationEvent, AnimationOptions, AnimationPlayer, NoopAnimationPlayer, animate, animateChild, group, keyframes, query, state, style, transition, trigger, ɵPRE_STYLE as PRE_STYLE} from '@angular/animations'; import {AUTO_STYLE, AnimationEvent, AnimationOptions, animate, animateChild, group, keyframes, query, state, style, transition, trigger, ɵPRE_STYLE as PRE_STYLE} from '@angular/animations';
import {AnimationDriver, ɵAnimationEngine, ɵNoopAnimationDriver as NoopAnimationDriver} from '@angular/animations/browser'; import {AnimationDriver, ɵAnimationEngine, ɵNoopAnimationDriver as NoopAnimationDriver} from '@angular/animations/browser';
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing'; import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
import {ChangeDetectorRef, Component, HostBinding, HostListener, Inject, RendererFactory2, ViewChild} from '@angular/core'; import {ChangeDetectorRef, Component, HostBinding, HostListener, Inject, RendererFactory2, ViewChild} from '@angular/core';
import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing';
import {ɵDomRendererFactory2} from '@angular/platform-browser'; import {ɵDomRendererFactory2} from '@angular/platform-browser';
import {ANIMATION_MODULE_TYPE, BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {ANIMATION_MODULE_TYPE, BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
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 {TestBed, fakeAsync, flushMicrotasks} from '../../testing';
const DEFAULT_NAMESPACE_ID = 'id'; const DEFAULT_NAMESPACE_ID = 'id';
const DEFAULT_COMPONENT_ID = '1'; const DEFAULT_COMPONENT_ID = '1';
@ -66,7 +66,8 @@ const DEFAULT_COMPONENT_ID = '1';
} }
describe('fakeAsync testing', () => { describe('fakeAsync testing', () => {
it('should only require one flushMicrotasks call to kick off animation callbacks', fixmeIvy('unknown').it(
'should only require one flushMicrotasks call to kick off animation callbacks',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'cmp', selector: 'cmp',
@ -109,7 +110,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.status).toEqual('done'); expect(cmp.status).toEqual('done');
})); }));
it('should always run .start callbacks before .done callbacks even for noop animations', fixmeIvy('unknown').it(
'should always run .start callbacks before .done callbacks even for noop animations',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'cmp', selector: 'cmp',
@ -141,7 +143,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.log).toEqual(['start', 'done']); expect(cmp.log).toEqual(['start', 'done']);
})); }));
it('should emit the correct totalTime value for a noop-animation', fakeAsync(() => { fixmeIvy('unknown').it(
'should emit the correct totalTime value for a noop-animation', fakeAsync(() => {
@Component({ @Component({
selector: 'cmp', selector: 'cmp',
template: ` template: `
@ -297,7 +300,7 @@ const DEFAULT_COMPONENT_ID = '1';
}); });
describe('animation triggers', () => { describe('animation triggers', () => {
it('should trigger a state change animation from void => state', () => { fixmeIvy('unknown').it('should trigger a state change animation from void => state', () => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
template: ` template: `
@ -327,7 +330,8 @@ const DEFAULT_COMPONENT_ID = '1';
]); ]);
}); });
it('should allow a transition to use a function to determine what method to run', () => { fixmeIvy('unknown').it(
'should allow a transition to use a function to determine what method to run', () => {
let valueToMatch = ''; let valueToMatch = '';
let capturedElement: any; let capturedElement: any;
const transitionFn = (fromState: string, toState: string, element: any) => { const transitionFn = (fromState: string, toState: string, element: any) => {
@ -339,9 +343,10 @@ const DEFAULT_COMPONENT_ID = '1';
selector: 'if-cmp', selector: 'if-cmp',
template: '<div #element [@myAnimation]="exp"></div>', template: '<div #element [@myAnimation]="exp"></div>',
animations: [ animations: [
trigger('myAnimation', [transition( trigger(
transitionFn, 'myAnimation',
[style({opacity: 0}), animate(1234, style({opacity: 1}))])]), [transition(
transitionFn, [style({opacity: 0}), animate(1234, style({opacity: 1}))])]),
] ]
}) })
class Cmp { class Cmp {
@ -373,12 +378,12 @@ const DEFAULT_COMPONENT_ID = '1';
expect(players.length).toEqual(0); expect(players.length).toEqual(0);
}); });
it('should allow a transition to use a function to determine what method to run and expose any parameter values', fixmeIvy('unknown').it(
'should allow a transition to use a function to determine what method to run and expose any parameter values',
() => { () => {
const transitionFn = const transitionFn =
(fromState: string, toState: string, element: any, params: {[key: string]: any}) => { (fromState: string, toState: string, element: any,
return params['doMatch'] == true; params: {[key: string]: any}) => { return params['doMatch'] == true; };
};
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -454,7 +459,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(player.duration).toEqual(1234); expect(player.duration).toEqual(1234);
}); });
it('should always cancel the previous transition if a follow-up transition is not matched', fixmeIvy('unknown').it(
'should always cancel the previous transition if a follow-up transition is not matched',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -464,7 +470,8 @@ const DEFAULT_COMPONENT_ID = '1';
animations: [trigger( animations: [trigger(
'myAnimation', 'myAnimation',
[transition( [transition(
'a => b', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], 'a => b',
[style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])],
}) })
class Cmp { class Cmp {
exp: any; exp: any;
@ -533,7 +540,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(completed).toBe(true); expect(completed).toBe(true);
})); }));
it('should always fire inner callbacks even if no animation is fired when a view is inserted', fixmeIvy('unknown').it(
'should always fire inner callbacks even if no animation is fired when a view is inserted',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -569,7 +577,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']); expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']);
})); }));
it('should only turn a view removal as into `void` state transition', () => { fixmeIvy('unknown').it(
'should only turn a view removal as into `void` state transition', () => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
template: ` template: `
@ -579,9 +588,11 @@ const DEFAULT_COMPONENT_ID = '1';
'myAnimation', 'myAnimation',
[ [
transition( transition(
'void <=> *', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), 'void <=> *',
[style({width: '0px'}), animate(1000, style({width: '100px'}))]),
transition( transition(
'* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]), '* => *',
[style({height: '0px'}), animate(1000, style({height: '100px'}))]),
])] ])]
}) })
class Cmp { class Cmp {
@ -664,7 +675,7 @@ const DEFAULT_COMPONENT_ID = '1';
]); ]);
}); });
it('should stringify boolean triggers to `1` and `0`', () => { fixmeIvy('unknown').it('should stringify boolean triggers to `1` and `0`', () => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
template: ` template: `
@ -817,7 +828,8 @@ const DEFAULT_COMPONENT_ID = '1';
}); });
describe('host bindings', () => { describe('host bindings', () => {
it('should trigger a state change animation from state => state on the component host element', fixmeIvy('unknown').it(
'should trigger a state change animation from state => state on the component host element',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'my-cmp', selector: 'my-cmp',
@ -849,11 +861,14 @@ const DEFAULT_COMPONENT_ID = '1';
const data = getLog().pop() !; const data = getLog().pop() !;
expect(data.element).toEqual(fixture.elementRef.nativeElement); expect(data.element).toEqual(fixture.elementRef.nativeElement);
expect(data.keyframes).toEqual([{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}]); expect(data.keyframes).toEqual([
{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}
]);
})); }));
// nonAnimationRenderer => animationRenderer // nonAnimationRenderer => animationRenderer
it('should trigger a leave animation when the inner components host binding updates', fixmeIvy('unknown').it(
'should trigger a leave animation when the inner components host binding updates',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'parent-cmp', selector: 'parent-cmp',
@ -955,7 +970,8 @@ const DEFAULT_COMPONENT_ID = '1';
})); }));
// animationRenderer => animationRenderer // animationRenderer => animationRenderer
it('should trigger a leave animation when both the inner and outer components trigger on the same element', fixmeIvy('unknown').it(
'should trigger a leave animation when both the inner and outer components trigger on the same element',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'parent-cmp', selector: 'parent-cmp',
@ -976,7 +992,8 @@ const DEFAULT_COMPONENT_ID = '1';
selector: 'child-cmp', selector: 'child-cmp',
template: '...', template: '...',
animations: [trigger( animations: [trigger(
'host', [transition( 'host',
[transition(
':leave', ':leave',
[style({width: '100px'}), animate(1000, style({width: '0px'}))])])] [style({width: '100px'}), animate(1000, style({width: '0px'}))])])]
}) })
@ -1922,7 +1939,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(p.contains(c2)).toBeTruthy(); expect(p.contains(c2)).toBeTruthy();
}); });
it('should detect trigger changes based on object.value properties', () => { fixmeIvy('unknown').it(
'should detect trigger changes based on object.value properties', () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
template: ` template: `
@ -2006,7 +2024,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(players.length).toEqual(0); expect(players.length).toEqual(0);
}); });
it('should update the final state styles when params update even if the expression hasn\'t changed', fixmeIvy('unknown').it(
'should update the final state styles when params update even if the expression hasn\'t changed',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
@ -2098,7 +2117,8 @@ const DEFAULT_COMPONENT_ID = '1';
]); ]);
}); });
it('should retain substituted styles on the element once the animation is complete if referenced in the final state', fixmeIvy('unknown').it(
'should retain substituted styles on the element once the animation is complete if referenced in the final state',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
@ -2443,7 +2463,8 @@ const DEFAULT_COMPONENT_ID = '1';
}); });
describe('animation listeners', () => { describe('animation listeners', () => {
it('should trigger a `start` state change listener for when the animation changes state from void => state', fixmeIvy('unknown').it(
'should trigger a `start` state change listener for when the animation changes state from void => state',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -2480,7 +2501,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.event.toState).toEqual('true'); expect(cmp.event.toState).toEqual('true');
})); }));
it('should trigger a `done` state change listener for when the animation changes state from a => b', fixmeIvy('unknown').it(
'should trigger a `done` state change listener for when the animation changes state from a => b',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -2490,7 +2512,8 @@ const DEFAULT_COMPONENT_ID = '1';
animations: [trigger( animations: [trigger(
'myAnimation123', 'myAnimation123',
[transition( [transition(
'* => b', [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])], '* => b',
[style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])],
}) })
class Cmp { class Cmp {
exp: any = false; exp: any = false;
@ -2523,7 +2546,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.event.toState).toEqual('b'); expect(cmp.event.toState).toEqual('b');
})); }));
it('should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => { fixmeIvy('unknown').it(
'should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
template: ` template: `
@ -2587,7 +2611,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.event2.triggerName).toBeTruthy('ani2'); expect(cmp.event2.triggerName).toBeTruthy('ani2');
})); }));
it('should handle callbacks for multiple triggers running simultaneously on the same element', fixmeIvy('unknown').it(
'should handle callbacks for multiple triggers running simultaneously on the same element',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -2709,7 +2734,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(elm.innerText.trim()).toEqual(''); expect(elm.innerText.trim()).toEqual('');
})); }));
it('should trigger a state change listener for when the animation changes state from void => state on the host element', fixmeIvy('unknown').it(
'should trigger a state change listener for when the animation changes state from void => state on the host element',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'my-cmp', selector: 'my-cmp',
@ -2747,7 +2773,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.event.toState).toEqual('TRUE'); expect(cmp.event.toState).toEqual('TRUE');
})); }));
it('should always fire callbacks even when a transition is not detected', fakeAsync(() => { fixmeIvy('unknown').it(
'should always fire callbacks even when a transition is not detected', fakeAsync(() => {
@Component({ @Component({
selector: 'my-cmp', selector: 'my-cmp',
template: ` template: `
@ -2783,7 +2810,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.log).toEqual(['start => b', 'done => b']); expect(cmp.log).toEqual(['start => b', 'done => b']);
})); }));
it('should fire callback events for leave animations even if there is no leave transition', fixmeIvy('unknown').it(
'should fire callback events for leave animations even if there is no leave transition',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'my-cmp', selector: 'my-cmp',
@ -2823,7 +2851,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.log).toEqual(['start => void', 'done => void']); expect(cmp.log).toEqual(['start => void', 'done => void']);
})); }));
it('should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { fixmeIvy('unknown').it(
'should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => {
@Component({ @Component({
selector: 'my-cmp', selector: 'my-cmp',
template: ` template: `
@ -2907,7 +2936,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.log).toEqual(['parent-done', 'child-done']); expect(cmp.log).toEqual(['parent-done', 'child-done']);
})); }));
it('should fire callbacks and collect the correct the totalTime and element details for any queried sub animations', fixmeIvy('unknown').it(
'should fire callbacks and collect the correct the totalTime and element details for any queried sub animations',
fakeAsync( fakeAsync(
() => { () => {
@Component({ @Component({
@ -3255,7 +3285,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(parent.childElementCount).toEqual(0); expect(parent.childElementCount).toEqual(0);
}); });
it('should properly resolve animation event listeners when disabled', fakeAsync(() => { fixmeIvy('unknown').it(
'should properly resolve animation event listeners when disabled', fakeAsync(() => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
template: ` template: `
@ -3360,7 +3391,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(getLog().length).toEqual(1); expect(getLog().length).toEqual(1);
}); });
it('should treat the property as true when the expression is missing', () => { fixmeIvy('unknown').it(
'should treat the property as true when the expression is missing', () => {
@Component({ @Component({
selector: 'parent-cmp', selector: 'parent-cmp',
animations: [ animations: [
@ -3397,7 +3429,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(getLog().length).toEqual(0); expect(getLog().length).toEqual(0);
}); });
it('should respect parent/sub animations when the respective area in the DOM is disabled', fixmeIvy('unknown').it(
'should respect parent/sub animations when the respective area in the DOM is disabled',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'parent-cmp', selector: 'parent-cmp',
@ -3569,7 +3602,8 @@ const DEFAULT_COMPONENT_ID = '1';
/only state\(\) and transition\(\) definitions can sit inside of a trigger\(\)/); /only state\(\) and transition\(\) definitions can sit inside of a trigger\(\)/);
}); });
it('should combine multiple errors together into one exception when an animation fails to be built', fixmeIvy('unknown').it(
'should combine multiple errors together into one exception when an animation fails to be built',
() => { () => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -3658,7 +3692,8 @@ const DEFAULT_COMPONENT_ID = '1';
expect(() => { TestBed.createComponent(Cmp); }).not.toThrowError(); expect(() => { TestBed.createComponent(Cmp); }).not.toThrowError();
}); });
it('should continue to clean up DOM-related animation artificats even if a compiler-level error is thrown midway', fixmeIvy('unknown').it(
'should continue to clean up DOM-related animation artificats even if a compiler-level error is thrown midway',
() => { () => {
@Component({ @Component({
selector: 'if-cmp', selector: 'if-cmp',
@ -3711,7 +3746,8 @@ const DEFAULT_COMPONENT_ID = '1';
}); });
}); });
it('should throw when using an @prop binding without the animation module', () => { fixmeIvy('unknown').it(
'should throw when using an @prop binding without the animation module', () => {
@Component({template: `<div [@myAnimation]="true"></div>`}) @Component({template: `<div [@myAnimation]="true"></div>`})
class Cmp { class Cmp {
} }
@ -3723,7 +3759,8 @@ const DEFAULT_COMPONENT_ID = '1';
'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.');
}); });
it('should throw when using an @prop listener without the animation module', () => { fixmeIvy('unknown').it(
'should throw when using an @prop listener without the animation module', () => {
@Component({template: `<div (@myAnimation.start)="a = true"></div>`}) @Component({template: `<div (@myAnimation.start)="a = true"></div>`})
class Cmp { class Cmp {
a: any; a: any;

View File

@ -12,12 +12,11 @@ import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '@angular/animations/browser/src/
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing'; import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {Component, HostBinding, ViewChild} from '@angular/core'; import {Component, HostBinding, ViewChild} from '@angular/core';
import {TestBed, fakeAsync, flushMicrotasks} 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 {HostListener} from '../../src/metadata/directives'; import {HostListener} from '../../src/metadata/directives';
import {TestBed} from '../../testing';
import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
(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)
@ -296,7 +295,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(p6.element.classList.contains('b3')).toBeTruthy(); expect(p6.element.classList.contains('b3')).toBeTruthy();
}); });
it('should be able to query all active animations using :animating in a query', () => { fixmeIvy('unknown').it(
'should be able to query all active animations using :animating in a query', () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
template: ` template: `
@ -802,7 +802,7 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(player.element.style.height).toEqual('444px'); expect(player.element.style.height).toEqual('444px');
}); });
it('should find newly inserted items in the component via :enter', () => { fixmeIvy('unknown').it('should find newly inserted items in the component via :enter', () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
template: ` template: `
@ -853,7 +853,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
}); });
}); });
it('should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', fixmeIvy('unknown').it(
'should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built',
() => { () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
@ -2234,7 +2235,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(p3.element.classList.contains('parent1')).toBeTruthy(); expect(p3.element.classList.contains('parent1')).toBeTruthy();
}); });
it('should emulate a leave animation on the nearest sub host elements when a parent is removed', fixmeIvy('unknown').it(
'should emulate a leave animation on the nearest sub host elements when a parent is removed',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
@ -2438,7 +2440,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(element.innerText.trim()).toMatch(/this\s+child/mg); expect(element.innerText.trim()).toMatch(/this\s+child/mg);
})); }));
it('should only mark outermost *directive nodes :enter and :leave when inserts and removals occur', fixmeIvy('unknown').it(
'should only mark outermost *directive nodes :enter and :leave when inserts and removals occur',
() => { () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
@ -2512,7 +2515,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(p4.element.classList.contains('d')); expect(p4.element.classList.contains('d'));
}); });
it('should collect multiple root levels of :enter and :leave nodes', () => { fixmeIvy('unknown').it(
'should collect multiple root levels of :enter and :leave nodes', () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
animations: [ animations: [
@ -2631,7 +2635,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(p3.element.classList.contains('page2')).toBe(true); expect(p3.element.classList.contains('page2')).toBe(true);
}); });
it('should emulate leave animation callbacks for all sub elements that have leave triggers within the component', fixmeIvy('unknown').it(
'should emulate leave animation callbacks for all sub elements that have leave triggers within the component',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
@ -2732,7 +2737,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(engine.players[0].getRealPlayer()).toBe(players[1]); expect(engine.players[0].getRealPlayer()).toBe(players[1]);
}); });
it('should fire and synchronize the start/done callbacks on sub triggers even if they are not allowed to animate within the animation', fixmeIvy('unknown').it(
'should fire and synchronize the start/done callbacks on sub triggers even if they are not allowed to animate within the animation',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'parent-cmp', selector: 'parent-cmp',
@ -2832,7 +2838,8 @@ import {fakeAsync, flushMicrotasks} from '../../testing/src/fake_async';
expect(child.log).toEqual(['child-start', 'child-done']); expect(child.log).toEqual(['child-start', 'child-done']);
})); }));
it('should fire and synchronize the start/done callbacks on multiple blocked sub triggers', fixmeIvy('unknown').it(
'should fire and synchronize the start/done callbacks on multiple blocked sub triggers',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'cmp', selector: 'cmp',

View File

@ -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,7 +34,8 @@ import {RouterTestingModule} from '@angular/router/testing';
}); });
}); });
it('should query the old and new routes via :leave and :enter', fakeAsync(() => { fixmeIvy('unknown').it(
'should query the old and new routes via :leave and :enter', fakeAsync(() => {
@Component({ @Component({
animations: [ animations: [
trigger( trigger(
@ -150,7 +152,8 @@ import {RouterTestingModule} from '@angular/router/testing';
]); ]);
})); }));
it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => { fixmeIvy('unknown').it(
'should allow inner enter animations to be emulated within a routed item', fakeAsync(() => {
@Component({ @Component({
animations: [ animations: [
trigger( trigger(
@ -255,7 +258,8 @@ import {RouterTestingModule} from '@angular/router/testing';
]); ]);
})); }));
it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => { fixmeIvy('unknown').it(
'should allow inner leave animations to be emulated within a routed item', fakeAsync(() => {
@Component({ @Component({
animations: [ animations: [
trigger( trigger(
@ -301,7 +305,8 @@ import {RouterTestingModule} from '@angular/router/testing';
]), ]),
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 { class Page1Cmp {
@ -359,7 +364,8 @@ import {RouterTestingModule} from '@angular/router/testing';
]); ]);
})); }));
it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries', fixmeIvy('unknown').it(
'should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries',
fakeAsync(() => { fakeAsync(() => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
@ -445,9 +451,11 @@ import {RouterTestingModule} from '@angular/router/testing';
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(
'should allow a recursive set of :leave animations to occur for nested routes',
fakeAsync(() => { fakeAsync(() => {
@Component({selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'}) @Component(
{selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'})
class ContainerCmp { class ContainerCmp {
constructor(private _router: Router) {} constructor(private _router: Router) {}
log: string[] = []; log: string[] = [];
@ -464,7 +472,8 @@ import {RouterTestingModule} from '@angular/router/testing';
trigger( trigger(
'pageAnimations', 'pageAnimations',
[ [
transition(':leave', [group([ transition(
':leave', [group([
sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]), sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]),
query('@*', animateChild(), {optional: true}) query('@*', animateChild(), {optional: true})
])]), ])]),

View File

@ -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,7 +242,8 @@ 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',

View File

@ -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,7 +446,8 @@ 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')
.it('should ignore empty bindings', fakeAsync(() => {
const ctx = _bindSimpleProp('[someProp]', TestData); const ctx = _bindSimpleProp('[someProp]', TestData);
ctx.componentInstance.a = 'value'; ctx.componentInstance.a = 'value';
ctx.detectChanges(false); ctx.detectChanges(false);
@ -537,7 +539,8 @@ 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(
'should record unwrapped values via ngOnChanges', fakeAsync(() => {
const ctx = createCompFixture( const ctx = createCompFixture(
'<div [testDirective]="\'aName\' | wrappedPipe" [a]="1" [b]="2 | wrappedPipe"></div>'); '<div [testDirective]="\'aName\' | wrappedPipe" [a]="1" [b]="2 | wrappedPipe"></div>');
const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0]; const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0];
@ -588,7 +591,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
})); }));
it('should call pure pipes that are used multiple times only when the arguments change', fixmeIvy('unknown').it(
'should call pure pipes that are used multiple times only when the arguments change',
fakeAsync(() => { fakeAsync(() => {
const ctx = createCompFixture( const ctx = createCompFixture(
`<div [someProp]="name | countingPipe"></div><div [someProp]="age | countingPipe"></div>` + `<div [someProp]="name | countingPipe"></div><div [someProp]="age | countingPipe"></div>` +
@ -994,7 +998,8 @@ 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(
'should not call ngAfterViewInit again if it throws', fakeAsync(() => {
const ctx = const ctx =
createCompFixture('<div testDirective="dir" throwOn="ngAfterViewInit"></div>'); createCompFixture('<div testDirective="dir" throwOn="ngAfterViewInit"></div>');
@ -1073,7 +1078,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}); });
describe('ngOnDestroy', () => { describe('ngOnDestroy', () => {
it('should be called on view destruction', fakeAsync(() => { fixmeIvy('unknown').it(
'should be called on view destruction', fakeAsync(() => {
const ctx = createCompFixture('<div testDirective="dir"></div>'); const ctx = createCompFixture('<div testDirective="dir"></div>');
ctx.detectChanges(false); ctx.detectChanges(false);
@ -1082,7 +1088,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
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(
'should be called after processing the content and view children', fakeAsync(() => {
TestBed.overrideComponent(AnotherComponent, { TestBed.overrideComponent(AnotherComponent, {
set: new Component( set: new Component(
{selector: 'other-cmp', template: '<div testDirective="viewChild"></div>'}) {selector: 'other-cmp', template: '<div testDirective="viewChild"></div>'})
@ -1102,7 +1109,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
]); ]);
})); }));
it('should be called in reverse order so the child is always notified before the parent', fixmeIvy('unknown').it(
'should be called in reverse order so the child is always notified before the parent',
fakeAsync(() => { fakeAsync(() => {
const ctx = createCompFixture( const ctx = createCompFixture(
'<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>'); '<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>');
@ -1115,7 +1123,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
]); ]);
})); }));
it('should deliver synchronous events to parent', fakeAsync(() => { fixmeIvy('unknown').it(
'should deliver synchronous events to parent', fakeAsync(() => {
const ctx = createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>'); const ctx = createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>');
ctx.detectChanges(false); ctx.detectChanges(false);
@ -1124,7 +1133,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
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);
@ -1135,11 +1144,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
]); ]);
})); }));
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);
@ -1155,7 +1165,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}); });
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(
'should throw when a record gets changed after it has been checked', fakeAsync(() => {
@Directive({selector: '[changed]'}) @Directive({selector: '[changed]'})
class ChangingDirective { class ChangingDirective {
@Input() changed: any; @Input() changed: any;
@ -1168,10 +1179,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
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(
'should warn when the view has been created in a cd hook', fakeAsync(() => {
const ctx = createCompFixture('<div *gh9882>{{ a }}</div>', TestData); const ctx = createCompFixture('<div *gh9882>{{ a }}</div>', TestData);
ctx.componentInstance.a = 1; ctx.componentInstance.a = 1;
expect(() => ctx.detectChanges()) expect(() => ctx.detectChanges())
@ -1187,7 +1200,7 @@ 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();
@ -1198,7 +1211,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}); });
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';
@ -1260,13 +1273,14 @@ 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
// should be resetted to
// on-push // on-push
ctx.detectChanges(); ctx.detectChanges();
expect(cmp.renderCount).toBeGreaterThan(0); expect(cmp.renderCount).toBeGreaterThan(0);
@ -1279,7 +1293,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}); });
describe('multi directive order', () => { describe('multi directive order', () => {
it('should follow the DI order for the same element', fakeAsync(() => { fixmeIvy('unknown').it(
'should follow the DI order for the same element', fakeAsync(() => {
const ctx = const ctx =
createCompFixture('<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>'); createCompFixture('<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>');
@ -1424,7 +1439,8 @@ 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(
'should dirty check projected views if the declaration place is dirty checked', () => {
ctx.detectChanges(false); ctx.detectChanges(false);
log = []; log = [];
innerComp.cdRef.detach(); innerComp.cdRef.detach();
@ -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 {

View File

@ -700,7 +700,8 @@ 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(
'should be checked when an async pipe requests a check', fakeAsync(() => {
TestBed.configureTestingModule( TestBed.configureTestingModule(
{declarations: [MyComp, PushCmpWithAsyncPipe], imports: [CommonModule]}); {declarations: [MyComp, PushCmpWithAsyncPipe], imports: [CommonModule]});
const template = '<push-cmp-with-async #cmp></push-cmp-with-async>'; const template = '<push-cmp-with-async #cmp></push-cmp-with-async>';
@ -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}});

View File

@ -370,7 +370,8 @@ describe('projection', () => {
}); });
if (getDOM().supportsNativeShadowDOM()) { if (getDOM().supportsNativeShadowDOM()) {
it('should support native content projection and isolate styles per component', () => { fixmeIvy('unknown').it(
'should support native content projection and isolate styles per component', () => {
TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]}); TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]});
TestBed.overrideComponent(MainComp, { TestBed.overrideComponent(MainComp, {
set: { set: {

View File

@ -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:

View File

@ -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,27 +552,34 @@ class TestComp {
.toEqual('parentService'); .toEqual('parentService');
}); });
it('should instantiate directives that depend on providers of a component', () => { fixmeIvy('unknown').it(
'should instantiate directives that depend on providers of a component', () => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent( TestBed.overrideComponent(
SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); SimpleComponent,
TestBed.overrideComponent(SimpleComponent, {set: {template: '<div needsService></div>'}}); {set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsService></div>'}});
const el = createComponent('<div simpleComponent></div>'); const el = createComponent('<div simpleComponent></div>');
expect(el.children[0].children[0].injector.get(NeedsService).service) expect(el.children[0].children[0].injector.get(NeedsService).service)
.toEqual('hostService'); .toEqual('hostService');
}); });
it('should instantiate directives that depend on view providers of a component', () => { fixmeIvy('unknown').it(
'should instantiate directives that depend on view providers of a component', () => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent( TestBed.overrideComponent(
SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); SimpleComponent,
TestBed.overrideComponent(SimpleComponent, {set: {template: '<div needsService></div>'}}); {set: {providers: [{provide: 'service', useValue: 'hostService'}]}});
TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsService></div>'}});
const el = createComponent('<div simpleComponent></div>'); const el = createComponent('<div simpleComponent></div>');
expect(el.children[0].children[0].injector.get(NeedsService).service) expect(el.children[0].children[0].injector.get(NeedsService).service)
.toEqual('hostService'); .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.configureTestingModule({declarations: [SimpleComponent, NeedsService]});
TestBed.overrideComponent( TestBed.overrideComponent(
@ -590,14 +598,15 @@ 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(
'should not instantiate a directive in a view that has a host dependency on providers' +
' of the component', ' of the component',
() => { () => {
TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsServiceFromHost]}); TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsServiceFromHost]});
@ -612,7 +621,8 @@ class TestComp {
/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(
'should not instantiate a directive in a view that has a host dependency on providers' +
' of a decorator directive', ' of a decorator directive',
() => { () => {
TestBed.configureTestingModule( TestBed.configureTestingModule(
@ -628,13 +638,14 @@ class TestComp {
/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( TestBed.configureTestingModule(
{declarations: [SimpleDirective, NeedsDirectiveFromSelf]}); {declarations: [SimpleDirective, NeedsDirectiveFromSelf]});
expect( expect(
() => () => createComponent(
createComponent('<div simpleDirective><div needsDirectiveFromSelf></div></div>')) '<div simpleDirective><div needsDirectiveFromSelf></div></div>'))
.toThrowError( .toThrowError(
/Template parse errors:\nNo provider for SimpleDirective \("<div simpleDirective>\[ERROR ->\]<div needsDirectiveFromSelf><\/div><\/div>"\): .*TestComp.html@0:21/); /Template parse errors:\nNo provider for SimpleDirective \("<div simpleDirective>\[ERROR ->\]<div needsDirectiveFromSelf><\/div><\/div>"\): .*TestComp.html@0:21/);
}); });
@ -662,8 +673,10 @@ 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.configureTestingModule(
{declarations: [SimpleComponent, NeedsComponentFromHost]});
TestBed.overrideComponent( TestBed.overrideComponent(
SimpleComponent, {set: {template: '<div needsComponentFromHost></div>'}}); SimpleComponent, {set: {template: '<div needsComponentFromHost></div>'}});
const el = createComponent('<div simpleComponent></div>'); const el = createComponent('<div simpleComponent></div>');
@ -671,13 +684,16 @@ class TestComp {
expect(d.dependency).toBeAnInstanceOf(SimpleComponent); expect(d.dependency).toBeAnInstanceOf(SimpleComponent);
}); });
it('should instantiate host views for components that have a @Host dependency ', () => { fixmeIvy('unknown').it(
'should instantiate host views for components that have a @Host dependency ', () => {
TestBed.configureTestingModule({declarations: [NeedsHostAppService]}); TestBed.configureTestingModule({declarations: [NeedsHostAppService]});
const el = createComponent('', [], NeedsHostAppService); const el = createComponent('', [], NeedsHostAppService);
expect(el.componentInstance.service).toEqual('appService'); expect(el.componentInstance.service).toEqual('appService');
}); });
it('should not instantiate directives that depend on other directives on the host element', () => { fixmeIvy('unknown').it(
'should not instantiate directives that depend on other directives on the host element',
() => {
TestBed.configureTestingModule( TestBed.configureTestingModule(
{declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]}); {declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]});
TestBed.overrideComponent( TestBed.overrideComponent(
@ -687,7 +703,8 @@ class TestComp {
/Template parse errors:\nNo provider for SimpleDirective \("\[ERROR ->\]<div needsDirectiveFromHost><\/div>"\): .*SimpleComponent.html@0:0/); /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: ''}) @Component({template: ''})
class MyComp { class MyComp {
@ -734,7 +751,8 @@ 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(
'should inject ChangeDetectorRef of the component\'s view into the component', () => {
TestBed.configureTestingModule({declarations: [PushComponentNeedsChangeDetectorRef]}); TestBed.configureTestingModule({declarations: [PushComponentNeedsChangeDetectorRef]});
const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>'); const cf = createComponentFixture('<div componentNeedsChangeDetectorRef></div>');
cf.detectChanges(); cf.detectChanges();
@ -748,9 +766,12 @@ class TestComp {
expect(compEl.nativeElement).toHaveText('1'); 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({
declarations:
[PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
});
TestBed.overrideComponent(PushComponentNeedsChangeDetectorRef, { TestBed.overrideComponent(PushComponentNeedsChangeDetectorRef, {
set: { set: {
template: template:
@ -765,18 +786,23 @@ class TestComp {
comp.counter = 1; comp.counter = 1;
cf.detectChanges(); cf.detectChanges();
expect(compEl.nativeElement).toHaveText('0'); expect(compEl.nativeElement).toHaveText('0');
expect(compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef) expect(
compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
.toEqual(comp.changeDetectorRef); .toEqual(comp.changeDetectorRef);
expect(compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef) expect(
compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef)
.toEqual(comp.changeDetectorRef); .toEqual(comp.changeDetectorRef);
comp.changeDetectorRef.markForCheck(); comp.changeDetectorRef.markForCheck();
cf.detectChanges(); cf.detectChanges();
expect(compEl.nativeElement).toHaveText('1'); 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({
declarations:
[PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
});
const cf = createComponentFixture( const cf = createComponentFixture(
'<div componentNeedsChangeDetectorRef directiveNeedsChangeDetectorRef></div>'); '<div componentNeedsChangeDetectorRef directiveNeedsChangeDetectorRef></div>');
cf.detectChanges(); cf.detectChanges();
@ -791,10 +817,13 @@ class TestComp {
expect(compEl.nativeElement).toHaveText('1'); expect(compEl.nativeElement).toHaveText('1');
}); });
it(`should not inject ChangeDetectorRef of a parent element's component into a directive`, () => { fixmeIvy('unknown').it(
`should not inject ChangeDetectorRef of a parent element's component into a directive`,
() => {
TestBed TestBed
.configureTestingModule({ .configureTestingModule({
declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] declarations:
[PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]
}) })
.overrideComponent( .overrideComponent(
PushComponentNeedsChangeDetectorRef, PushComponentNeedsChangeDetectorRef,
@ -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>' +

View File

@ -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,7 +200,8 @@ 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 ..."')
.it('should support OnPush components', () => {
let compInputValue: any; let compInputValue: any;
class AComp { class AComp {
a: any; a: any;
@ -207,7 +209,8 @@ const addEventListener = '__zone_symbol__addEventListener' as 'addEventListener'
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(
[ [

View File

@ -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,7 +185,8 @@ 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 ..."')
.it('should listen to DOM events', () => {
const handleEventSpy = jasmine.createSpy('handleEvent'); const handleEventSpy = jasmine.createSpy('handleEvent');
const removeListenerSpy = const removeListenerSpy =
spyOn(HTMLElement.prototype, removeEventListener).and.callThrough(); spyOn(HTMLElement.prototype, removeEventListener).and.callThrough();
@ -251,7 +253,8 @@ 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 ..."')
.it('should preventDefault only if the handler returns false', () => {
let eventHandlerResult: any; let eventHandlerResult: any;
let preventDefaultSpy: jasmine.Spy = undefined !; let preventDefaultSpy: jasmine.Spy = undefined !;
@ -279,9 +282,11 @@ const removeEventListener = '__zone_symbol__removeEventListener' as 'removeEvent
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 ..."')
.it('should report debug info on event errors', () => {
const handleErrorSpy = spyOn(TestBed.get(ErrorHandler), 'handleError'); const handleErrorSpy = spyOn(TestBed.get(ErrorHandler), 'handleError');
const addListenerSpy = spyOn(HTMLElement.prototype, addEventListener).and.callThrough(); const addListenerSpy =
spyOn(HTMLElement.prototype, addEventListener).and.callThrough();
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']],
() => { throw new Error('Test'); })])); () => { throw new Error('Test'); })]));