diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts index 013d28e5b9..7c973a01cc 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts @@ -120,4 +120,70 @@ describe('r3_view_compiler', () => { expectEmit(result.source, bV_call, 'Incorrect bV call'); }); }); + + describe('animations', () => { + it('should keep @attr but suppress [@attr]', () => { + const files: MockDirectory = { + app: { + 'example.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-app', + template: '
' + }) + export class MyApp { + } + + @NgModule({declarations: [MyApp]}) + export class MyModule {}` + } + }; + + const template = ` + const _c0 = ["@attrOnly", ""]; + // ... + template: function MyApp_Template(rf, ctx) { + if (rf & 1) { + $i0$.ɵelement(0, "div", _c0); + // ... + } + // ... + }`; + const result = compile(files, angularFiles); + expectEmit(result.source, template, 'Incorrect initialization attributes'); + }); + + it('should dedup multiple [@event] listeners', () => { + const files: MockDirectory = { + app: { + 'example.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-app', + template: '
' + }) + export class MyApp { + } + + @NgModule({declarations: [MyApp]}) + export class MyModule {}` + } + }; + + const template = ` + const _c0 = [1, "mySelector"]; + // ... + template: function MyApp_Template(rf, ctx) { + if (rf & 1) { + $i0$.ɵelementStart(0, "div", _c0); + // ... + } + // ... + }`; + const result = compile(files, angularFiles); + expectEmit(result.source, template, 'Incorrect initialization attributes'); + }); + }); }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts index 3827ff7294..9a99dc7f98 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts @@ -214,7 +214,6 @@ describe('compiler compliance: styling', () => { }; const template = ` - const $e0_attrs$ = ["@foo", ""]; const $e1_attrs$ = ["@bar", ""]; const $e2_attrs$ = ["@baz", ""]; … @@ -224,7 +223,7 @@ describe('compiler compliance: styling', () => { vars: 1, template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { - $r3$.ɵelement(0, "div", $e0_attrs$); + $r3$.ɵelement(0, "div"); $r3$.ɵelement(1, "div", $e1_attrs$); $r3$.ɵelement(2, "div", $e2_attrs$); } diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index 188c0e4712..293b32571c 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -10,7 +10,7 @@ import {flatten, sanitizeIdentifier} from '../../compile_metadata'; import {BindingForm, BuiltinFunctionCall, LocalResolver, convertActionBinding, convertPropertyBinding} from '../../compiler_util/expression_converter'; import {ConstantPool} from '../../constant_pool'; import * as core from '../../core'; -import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast'; +import {AST, ASTWithSource, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast'; import {Lexer} from '../../expression_parser/lexer'; import {Parser} from '../../expression_parser/parser'; import * as i18n from '../../i18n/i18n_ast'; @@ -967,6 +967,29 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver styles?: StylingBuilder): o.Expression[] { const attrExprs: o.Expression[] = []; const nonSyntheticInputs: t.BoundAttribute[] = []; + const alreadySeen = new Set(); + + function isASTWithSource(ast: AST): ast is ASTWithSource { + return ast instanceof ASTWithSource; + } + + function isLiteralPrimitive(ast: AST): ast is LiteralPrimitive { + return ast instanceof LiteralPrimitive; + } + + function addAttrExpr(key: string | number, value?: o.Expression): void { + if (typeof key === 'string') { + if (!alreadySeen.has(key)) { + attrExprs.push(o.literal(key)); + if (value !== undefined) { + attrExprs.push(value); + } + alreadySeen.add(key); + } + } else { + attrExprs.push(o.literal(key)); + } + } if (inputs.length) { const EMPTY_STRING_EXPR = asLiteral(''); @@ -976,7 +999,13 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // may be supported differently in future versions of angular. However, // @triggers should always just be treated as regular attributes (it's up // to the renderer to detect and use them in a special way). - attrExprs.push(asLiteral(prepareSyntheticAttributeName(input.name)), EMPTY_STRING_EXPR); + const valueExp = input.value; + if (isASTWithSource(valueExp)) { + const literal = valueExp.ast; + if (isLiteralPrimitive(literal) && literal.value === undefined) { + addAttrExpr(prepareSyntheticAttributeName(input.name), EMPTY_STRING_EXPR); + } + } } else { nonSyntheticInputs.push(input); } @@ -991,9 +1020,9 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } if (nonSyntheticInputs.length || outputs.length) { - attrExprs.push(o.literal(core.AttributeMarker.SelectOnly)); - nonSyntheticInputs.forEach((i: t.BoundAttribute) => attrExprs.push(asLiteral(i.name))); - outputs.forEach((o: t.BoundEvent) => attrExprs.push(asLiteral(o.name))); + addAttrExpr(core.AttributeMarker.SelectOnly); + nonSyntheticInputs.forEach((i: t.BoundAttribute) => addAttrExpr(i.name)); + outputs.forEach((o: t.BoundEvent) => addAttrExpr(o.name)); } return attrExprs; diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 6ed84dd888..03ffe747ec 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -394,8 +394,9 @@ function renderComponentOrTemplate( hostView: LView, context: T, templateFn?: ComponentTemplate) { const rendererFactory = hostView[RENDERER_FACTORY]; const oldView = enterView(hostView, hostView[HOST_NODE]); + const normalExecutionPath = !getCheckNoChangesMode(); try { - if (rendererFactory.begin) { + if (normalExecutionPath && rendererFactory.begin) { rendererFactory.begin(); } @@ -414,7 +415,7 @@ function renderComponentOrTemplate( templateFn && templateFn(RenderFlags.Update, context !); refreshDescendantViews(hostView); } finally { - if (rendererFactory.end) { + if (normalExecutionPath && rendererFactory.end) { rendererFactory.end(); } leaveView(oldView); diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index 7c0734fb82..aca4fdda3c 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -109,83 +109,81 @@ const DEFAULT_COMPONENT_ID = '1'; expect(cmp.status).toEqual('done'); })); - fixmeIvy('unknown').it( - 'should always run .start callbacks before .done callbacks even for noop animations', - fakeAsync(() => { - @Component({ - selector: 'cmp', - template: ` + it('should always run .start callbacks before .done callbacks even for noop animations', + fakeAsync(() => { + @Component({ + selector: 'cmp', + template: `
`, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => go', []), - ]), - ] - }) - class Cmp { - exp: any = false; - log: string[] = []; - cb(status: string) { this.log.push(status); } - } + animations: [ + trigger( + 'myAnimation', + [ + transition('* => go', []), + ]), + ] + }) + class Cmp { + exp: any = false; + log: string[] = []; + cb(status: string) { this.log.push(status); } + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - expect(cmp.log).toEqual([]); + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + expect(cmp.log).toEqual([]); - flushMicrotasks(); - expect(cmp.log).toEqual(['start', 'done']); - })); + flushMicrotasks(); + expect(cmp.log).toEqual(['start', 'done']); + })); - fixmeIvy('unknown').it( - 'should emit the correct totalTime value for a noop-animation', fakeAsync(() => { - @Component({ - selector: 'cmp', - template: ` + it('should emit the correct totalTime value for a noop-animation', fakeAsync(() => { + @Component({ + selector: 'cmp', + template: `
`, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - animate('1s', style({opacity: 0})), - ]), - ]), - ] - }) - class Cmp { - exp: any = false; - log: AnimationEvent[] = []; - cb(event: AnimationEvent) { this.log.push(event); } - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + animate('1s', style({opacity: 0})), + ]), + ]), + ] + }) + class Cmp { + exp: any = false; + log: AnimationEvent[] = []; + cb(event: AnimationEvent) { this.log.push(event); } + } - TestBed.configureTestingModule({ - declarations: [Cmp], - providers: [ - {provide: AnimationDriver, useClass: NoopAnimationDriver}, - ], - }); + TestBed.configureTestingModule({ + declarations: [Cmp], + providers: [ + {provide: AnimationDriver, useClass: NoopAnimationDriver}, + ], + }); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - expect(cmp.log).toEqual([]); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + expect(cmp.log).toEqual([]); - flushMicrotasks(); - expect(cmp.log.length).toEqual(2); - const [start, end] = cmp.log; - expect(start.totalTime).toEqual(1000); - expect(end.totalTime).toEqual(1000); - })); + flushMicrotasks(); + expect(cmp.log.length).toEqual(2); + const [start, end] = cmp.log; + expect(start.totalTime).toEqual(1000); + expect(end.totalTime).toEqual(1000); + })); }); describe('component fixture integration', () => { @@ -299,7 +297,7 @@ const DEFAULT_COMPONENT_ID = '1'; }); describe('animation triggers', () => { - fixmeIvy('unknown').it('should trigger a state change animation from void => state', () => { + it('should trigger a state change animation from void => state', () => { @Component({ selector: 'if-cmp', template: ` @@ -329,53 +327,51 @@ const DEFAULT_COMPONENT_ID = '1'; ]); }); - fixmeIvy('unknown').it( - 'should allow a transition to use a function to determine what method to run', () => { - let valueToMatch = ''; - let capturedElement: any; - const transitionFn = (fromState: string, toState: string, element: any) => { - capturedElement = element; - return toState == valueToMatch; - }; + it('should allow a transition to use a function to determine what method to run', () => { + let valueToMatch = ''; + let capturedElement: any; + const transitionFn = (fromState: string, toState: string, element: any) => { + capturedElement = element; + return toState == valueToMatch; + }; - @Component({ - selector: 'if-cmp', - template: '
', - animations: [ - trigger( - 'myAnimation', - [transition( - transitionFn, [style({opacity: 0}), animate(1234, style({opacity: 1}))])]), - ] - }) - class Cmp { - @ViewChild('element') - element: any; - exp: any = ''; - } + @Component({ + selector: 'if-cmp', + template: '
', + animations: [ + trigger('myAnimation', [transition( + transitionFn, + [style({opacity: 0}), animate(1234, style({opacity: 1}))])]), + ] + }) + class Cmp { + @ViewChild('element') + element: any; + exp: any = ''; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - valueToMatch = cmp.exp = 'something'; - fixture.detectChanges(); - const element = cmp.element.nativeElement; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + valueToMatch = cmp.exp = 'something'; + fixture.detectChanges(); + const element = cmp.element.nativeElement; - let players = getLog(); - expect(players.length).toEqual(1); - let [p1] = players; - expect(p1.totalTime).toEqual(1234); - expect(capturedElement).toEqual(element); - resetLog(); + let players = getLog(); + expect(players.length).toEqual(1); + let [p1] = players; + expect(p1.totalTime).toEqual(1234); + expect(capturedElement).toEqual(element); + resetLog(); - valueToMatch = 'something-else'; - cmp.exp = 'this-wont-match'; - fixture.detectChanges(); + valueToMatch = 'something-else'; + cmp.exp = 'this-wont-match'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(0); - }); + players = getLog(); + expect(players.length).toEqual(0); + }); fixmeIvy('unknown').it( 'should allow a transition to use a function to determine what method to run and expose any parameter values', @@ -573,105 +569,102 @@ const DEFAULT_COMPONENT_ID = '1'; expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']); })); - fixmeIvy('unknown').it( - 'should only turn a view removal as into `void` state transition', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should only turn a view removal as into `void` state transition', () => { + @Component({ + selector: 'if-cmp', + template: `
`, - animations: [trigger( - 'myAnimation', - [ - transition( - 'void <=> *', - [style({width: '0px'}), animate(1000, style({width: '100px'}))]), - transition( - '* => *', - [style({height: '0px'}), animate(1000, style({height: '100px'}))]), - ])] - }) - class Cmp { - exp1: any = false; - exp2: any = false; - } + animations: [trigger( + 'myAnimation', + [ + transition( + 'void <=> *', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), + transition( + '* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]), + ])] + }) + class Cmp { + exp1: any = false; + exp2: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - function resetState() { - cmp.exp2 = 'something'; - fixture.detectChanges(); - engine.flush(); - resetLog(); - } + function resetState() { + cmp.exp2 = 'something'; + fixture.detectChanges(); + engine.flush(); + resetLog(); + } - cmp.exp1 = true; - cmp.exp2 = null; + cmp.exp1 = true; + cmp.exp2 = null; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, width: '0px'}, {offset: 1, width: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); - resetState(); - cmp.exp2 = false; + resetState(); + cmp.exp2 = false; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp2 = 0; + resetState(); + cmp.exp2 = 0; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp2 = ''; + resetState(); + cmp.exp2 = ''; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp2 = undefined; + resetState(); + cmp.exp2 = undefined; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp1 = false; - cmp.exp2 = 'abc'; + resetState(); + cmp.exp1 = false; + cmp.exp2 = 'abc'; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, width: '0px'}, {offset: 1, width: '100px'} - ]); - }); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); + }); - fixmeIvy('unknown').it('should stringify boolean triggers to `1` and `0`', () => { + it('should stringify boolean triggers to `1` and `0`', () => { @Component({ selector: 'if-cmp', template: ` @@ -1577,61 +1570,62 @@ const DEFAULT_COMPONENT_ID = '1'; } }); - it('should animate removals of nodes to the `void` state for each animation trigger, but treat all auto styles as pre styles', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + fixmeIvy('unknown').it( + 'should animate removals of nodes to the `void` state for each animation trigger, but treat all auto styles as pre styles', + () => { + @Component({ + selector: 'ani-cmp', + template: `
`, - animations: [ - trigger( - 'trig1', [transition('state => void', [animate(1000, style({opacity: 0}))])]), - trigger('trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])]) - ] - }) - class Cmp { - public exp = true; - public exp2 = 'state'; - } + animations: [ + trigger( + 'trig1', [transition('state => void', [animate(1000, style({opacity: 0}))])]), + trigger('trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])]) + ] + }) + class Cmp { + public exp = true; + public exp2 = 'state'; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = true; - fixture.detectChanges(); - engine.flush(); - resetLog(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; + fixture.detectChanges(); + engine.flush(); + resetLog(); - const element = getDOM().querySelector(fixture.nativeElement, '.ng-if'); - assertHasParent(element, true); + const element = getDOM().querySelector(fixture.nativeElement, '.ng-if'); + assertHasParent(element, true); - cmp.exp = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp = false; + fixture.detectChanges(); + engine.flush(); - assertHasParent(element, true); + assertHasParent(element, true); - expect(getLog().length).toEqual(2); + expect(getLog().length).toEqual(2); - const player2 = getLog().pop() !; - const player1 = getLog().pop() !; + const player2 = getLog().pop() !; + const player1 = getLog().pop() !; - expect(player2.keyframes).toEqual([ - {width: PRE_STYLE, offset: 0}, - {width: '0px', offset: 1}, - ]); + expect(player2.keyframes).toEqual([ + {width: PRE_STYLE, offset: 0}, + {width: '0px', offset: 1}, + ]); - expect(player1.keyframes).toEqual([ - {opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1} - ]); + expect(player1.keyframes).toEqual([ + {opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1} + ]); - player2.finish(); - player1.finish(); - assertHasParent(element, false); - }); + player2.finish(); + player1.finish(); + assertHasParent(element, false); + }); it('should properly cancel all existing animations when a removal occurs', () => { @Component({ @@ -1977,48 +1971,49 @@ const DEFAULT_COMPONENT_ID = '1'; expect(players[0].duration).toEqual(5678); }); - it('should not render animations when the object expression value is the same as it was previously', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + fixmeIvy('unknown').it( + 'should not render animations when the object expression value is the same as it was previously', + () => { + @Component({ + selector: 'ani-cmp', + template: `
`, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => *', [animate(1234, style({opacity: 0}))]), - ]), - ] - }) - class Cmp { - public exp: any; - public params: any; - } + animations: [ + trigger( + 'myAnimation', + [ + transition('* => *', [animate(1234, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + public exp: any; + public params: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = '1'; - cmp.params = {}; - fixture.detectChanges(); - engine.flush(); - let players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - resetLog(); + cmp.exp = '1'; + cmp.params = {}; + fixture.detectChanges(); + engine.flush(); + let players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); + resetLog(); - cmp.exp = '1'; - cmp.params = {}; - fixture.detectChanges(); - engine.flush(); - players = getLog(); - expect(players.length).toEqual(0); - }); + cmp.exp = '1'; + cmp.params = {}; + fixture.detectChanges(); + engine.flush(); + players = getLog(); + expect(players.length).toEqual(0); + }); fixmeIvy('unknown').it( 'should update the final state styles when params update even if the expression hasn\'t changed', @@ -2459,88 +2454,85 @@ const DEFAULT_COMPONENT_ID = '1'; }); describe('animation listeners', () => { - fixmeIvy('unknown').it( - 'should trigger a `start` state change listener for when the animation changes state from void => state', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should trigger a `start` state change listener for when the animation changes state from void => state', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: `
`, - animations: [trigger( - 'myAnimation', - [transition( - 'void => *', - [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any = false; - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + animations: [trigger( + 'myAnimation', + [transition( + 'void => *', + [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any = false; + // TODO(issue/24571): remove '!'. + event !: AnimationEvent; - callback = (event: any) => { this.event = event; }; - } + callback = (event: any) => { this.event = event; }; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'true'; - fixture.detectChanges(); - flushMicrotasks(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'true'; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation'); - expect(cmp.event.phaseName).toEqual('start'); - expect(cmp.event.totalTime).toEqual(500); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('true'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation'); + expect(cmp.event.phaseName).toEqual('start'); + expect(cmp.event.totalTime).toEqual(500); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('true'); + })); - fixmeIvy('unknown').it( - 'should trigger a `done` state change listener for when the animation changes state from a => b', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should trigger a `done` state change listener for when the animation changes state from a => b', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: `
`, - animations: [trigger( - 'myAnimation123', - [transition( - '* => b', - [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any = false; - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + animations: [trigger( + 'myAnimation123', + [transition( + '* => b', [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any = false; + // TODO(issue/24571): remove '!'. + event !: AnimationEvent; - callback = (event: any) => { this.event = event; }; - } + callback = (event: any) => { this.event = event; }; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); - expect(cmp.event).toBeFalsy(); + expect(cmp.event).toBeFalsy(); - const player = engine.players.pop(); - player.finish(); - flushMicrotasks(); + const player = engine.players.pop(); + player.finish(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation123'); - expect(cmp.event.phaseName).toEqual('done'); - expect(cmp.event.totalTime).toEqual(999); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('b'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation123'); + expect(cmp.event.phaseName).toEqual('done'); + expect(cmp.event.totalTime).toEqual(999); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('b'); + })); it('should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => { @Component({ @@ -2767,42 +2759,41 @@ const DEFAULT_COMPONENT_ID = '1'; expect(cmp.event.toState).toEqual('TRUE'); })); - fixmeIvy('unknown').it( - 'should always fire callbacks even when a transition is not detected', fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: ` + it('should always fire callbacks even when a transition is not detected', fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: `
`, - animations: [trigger('myAnimation', [])] - }) - class Cmp { - // TODO(issue/24571): remove '!'. - exp !: string; - log: any[] = []; - callback = (event: any) => this.log.push(`${event.phaseName} => ${event.toState}`); - } + animations: [trigger('myAnimation', [])] + }) + class Cmp { + // TODO(issue/24571): remove '!'. + exp !: string; + log: any[] = []; + callback = (event: any) => this.log.push(`${event.phaseName} => ${event.toState}`); + } - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], - declarations: [Cmp] - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], + declarations: [Cmp] + }); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'a'; - fixture.detectChanges(); - flushMicrotasks(); - expect(cmp.log).toEqual(['start => a', 'done => a']); + cmp.exp = 'a'; + fixture.detectChanges(); + flushMicrotasks(); + expect(cmp.log).toEqual(['start => a', 'done => a']); - cmp.log = []; - cmp.exp = 'b'; - fixture.detectChanges(); - flushMicrotasks(); + cmp.log = []; + cmp.exp = 'b'; + fixture.detectChanges(); + flushMicrotasks(); - 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', fakeAsync(() => { @@ -2844,11 +2835,10 @@ const DEFAULT_COMPONENT_ID = '1'; expect(cmp.log).toEqual(['start => void', 'done => void']); })); - fixmeIvy('unknown').it( - 'should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: ` + it('should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: `
`, - animations: [ - trigger( - 'parent', - [ - transition( - '* => go', - [ - style({width: '0px'}), - animate(1000, style({width: '100px'})), - query( - '.child', - [ - animateChild({duration: '1s'}), - ]), - animate(1000, style({width: '0px'})), - ]), - ]), - trigger( - 'child', - [ - transition( - '* => go', - [ - style({height: '0px'}), - animate(1000, style({height: '100px'})), - ]), - ]) - ] - }) - class Cmp { - log: string[] = []; - // TODO(issue/24571): remove '!'. - exp1 !: string; - // TODO(issue/24571): remove '!'. - exp2 !: string; + animations: [ + trigger( + 'parent', + [ + transition( + '* => go', + [ + style({width: '0px'}), + animate(1000, style({width: '100px'})), + query( + '.child', + [ + animateChild({duration: '1s'}), + ]), + animate(1000, style({width: '0px'})), + ]), + ]), + trigger( + 'child', + [ + transition( + '* => go', + [ + style({height: '0px'}), + animate(1000, style({height: '100px'})), + ]), + ]) + ] + }) + class Cmp { + log: string[] = []; + // TODO(issue/24571): remove '!'. + exp1 !: string; + // TODO(issue/24571): remove '!'. + exp2 !: string; - cb(name: string, event: AnimationEvent) { this.log.push(name); } - } + cb(name: string, event: AnimationEvent) { this.log.push(name); } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp1 = 'go'; - cmp.exp2 = 'go'; - fixture.detectChanges(); - engine.flush(); - flushMicrotasks(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp1 = 'go'; + cmp.exp2 = 'go'; + fixture.detectChanges(); + engine.flush(); + flushMicrotasks(); - expect(cmp.log).toEqual(['parent-start', 'child-start']); - cmp.log = []; + expect(cmp.log).toEqual(['parent-start', 'child-start']); + cmp.log = []; - const players = getLog(); - expect(players.length).toEqual(3); - const [p1, p2, p3] = players; + const players = getLog(); + expect(players.length).toEqual(3); + const [p1, p2, p3] = players; - p1.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual([]); + p1.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual([]); - p2.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual([]); + p2.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual([]); - p3.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual(['parent-done', 'child-done']); - })); + p3.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual(['parent-done', 'child-done']); + })); fixmeIvy('unknown').it( 'should fire callbacks and collect the correct the totalTime and element details for any queried sub animations', @@ -3597,64 +3587,63 @@ const DEFAULT_COMPONENT_ID = '1'; /only state\(\) and transition\(\) definitions can sit inside of a trigger\(\)/); }); - fixmeIvy('unknown').it( - 'should combine multiple errors together into one exception when an animation fails to be built', - () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should combine multiple errors together into one exception when an animation fails to be built', + () => { + @Component({ + selector: 'if-cmp', + template: `
`, - animations: [ - trigger( - 'foo', - [ - transition(':enter', []), - transition( - '* => *', - [ - query('foo', animate(1000, style({background: 'red'}))), - ]), - ]), - trigger( - 'bar', - [ - transition(':enter', []), - transition( - '* => *', - [ - query('bar', animate(1000, style({background: 'blue'}))), - ]), - ]), - ] - }) - class Cmp { - fooExp: any = false; - barExp: any = false; - } + animations: [ + trigger( + 'foo', + [ + transition(':enter', []), + transition( + '* => *', + [ + query('foo', animate(1000, style({background: 'red'}))), + ]), + ]), + trigger( + 'bar', + [ + transition(':enter', []), + transition( + '* => *', + [ + query('bar', animate(1000, style({background: 'blue'}))), + ]), + ]), + ] + }) + class Cmp { + fooExp: any = false; + barExp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); - cmp.fooExp = 'go'; - cmp.barExp = 'go'; + cmp.fooExp = 'go'; + cmp.barExp = 'go'; - let errorMsg: string = ''; - try { - fixture.detectChanges(); - } catch (e) { - errorMsg = e.message; - } + let errorMsg: string = ''; + try { + fixture.detectChanges(); + } catch (e) { + errorMsg = e.message; + } - expect(errorMsg).toMatch(/@foo has failed due to:/); - expect(errorMsg).toMatch(/`query\("foo"\)` returned zero elements/); - expect(errorMsg).toMatch(/@bar has failed due to:/); - expect(errorMsg).toMatch(/`query\("bar"\)` returned zero elements/); - }); + expect(errorMsg).toMatch(/@foo has failed due to:/); + expect(errorMsg).toMatch(/`query\("foo"\)` returned zero elements/); + expect(errorMsg).toMatch(/@bar has failed due to:/); + expect(errorMsg).toMatch(/`query\("bar"\)` returned zero elements/); + }); it('should not throw an error if styles overlap in separate transitions', () => { @Component({ @@ -3741,18 +3730,17 @@ const DEFAULT_COMPONENT_ID = '1'; }); }); - fixmeIvy('unknown').it( - 'should throw when using an @prop binding without the animation module', () => { - @Component({template: `
`}) - class Cmp { - } + it('should throw when using an @prop binding without the animation module', () => { + @Component({template: `
`}) + class Cmp { + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const comp = TestBed.createComponent(Cmp); - expect(() => comp.detectChanges()) - .toThrowError( - 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); - }); + TestBed.configureTestingModule({declarations: [Cmp]}); + const comp = TestBed.createComponent(Cmp); + expect(() => comp.detectChanges()) + .toThrowError( + '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', () => { @Component({template: `
`}) diff --git a/packages/core/test/animation/animation_query_integration_spec.ts b/packages/core/test/animation/animation_query_integration_spec.ts index f30cf1d597..5586803080 100644 --- a/packages/core/test/animation/animation_query_integration_spec.ts +++ b/packages/core/test/animation/animation_query_integration_spec.ts @@ -853,12 +853,11 @@ import {HostListener} from '../../src/metadata/directives'; }); }); - fixmeIvy('unknown').it( - 'should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', + () => { + @Component({ + selector: 'ani-cmp', + template: `
{{ item }} @@ -866,56 +865,56 @@ import {HostListener} from '../../src/metadata/directives';
Leave!
`, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => 0', []), - transition( - '* => *', - [ - query( - '.child:enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - query( - '.incorrect-child:leave', - [ - animate(1000, style({opacity: 0})), - ]), - ]), - ]), - ] - }) - class Cmp { - @ViewChild('container') public container: any; - public items: any[] = []; - } + animations: [ + trigger( + 'myAnimation', + [ + transition('* => 0', []), + transition( + '* => *', + [ + query( + '.child:enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + query( + '.incorrect-child:leave', + [ + animate(1000, style({opacity: 0})), + ]), + ]), + ]), + ] + }) + class Cmp { + @ViewChild('container') public container: any; + public items: any[] = []; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.items = []; - fixture.detectChanges(); + cmp.items = []; + fixture.detectChanges(); - cmp.items = [0, 1, 2, 3, 4]; + cmp.items = [0, 1, 2, 3, 4]; - expect(() => { fixture.detectChanges(); }).toThrow(); + expect(() => { fixture.detectChanges(); }).toThrow(); - const children = cmp.container.nativeElement.querySelectorAll('.child'); - expect(children.length).toEqual(5); + const children = cmp.container.nativeElement.querySelectorAll('.child'); + expect(children.length).toEqual(5); - for (let i = 0; i < children.length; i++) { - let child = children[i]; - expect(child.classList.contains(ENTER_CLASSNAME)).toBe(false); - expect(child.classList.contains(LEAVE_CLASSNAME)).toBe(false); - } - }); + for (let i = 0; i < children.length; i++) { + let child = children[i]; + expect(child.classList.contains(ENTER_CLASSNAME)).toBe(false); + expect(child.classList.contains(LEAVE_CLASSNAME)).toBe(false); + } + }); it('should find elements that have been removed via :leave', () => { @Component({ @@ -2520,9 +2519,8 @@ import {HostListener} from '../../src/metadata/directives'; expect(p4.element.classList.contains('d')); }); - fixmeIvy('unknown').it( - 'should collect multiple root levels of :enter and :leave nodes', () => { - @Component({ + it('should collect multiple root levels of :enter and :leave nodes', () => { + @Component({ selector: 'ani-cmp', animations: [ trigger('pageAnimation', [ @@ -2557,88 +2555,88 @@ import {HostListener} from '../../src/metadata/directives'; ` }) class Cmp { - get title() { - if (this.page1) { - return 'hello from page1'; - } - return 'greetings from page2'; - } - - page1 = false; - page2 = false; - loading = false; - - get status() { - if (this.loading) return 'loading'; - if (this.page1) return 'page1'; - if (this.page2) return 'page2'; - return ''; - } + get title() { + if (this.page1) { + return 'hello from page1'; } + return 'greetings from page2'; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + page1 = false; + page2 = false; + loading = false; - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.loading = true; - fixture.detectChanges(); - engine.flush(); + get status() { + if (this.loading) return 'loading'; + if (this.page1) return 'page1'; + if (this.page2) return 'page2'; + return ''; + } + } - let players = getLog(); - resetLog(); - cancelAllPlayers(players); + TestBed.configureTestingModule({declarations: [Cmp]}); - cmp.page1 = true; - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.loading = true; + fixture.detectChanges(); + engine.flush(); - let p1: MockAnimationPlayer; - let p2: MockAnimationPlayer; - let p3: MockAnimationPlayer; + let players = getLog(); + resetLog(); + cancelAllPlayers(players); - players = getLog(); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; + cmp.page1 = true; + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); - expect(p1.element.classList.contains('loading')).toBe(true); - expect(p2.element.classList.contains('title')).toBe(true); - expect(p3.element.classList.contains('page1')).toBe(true); + let p1: MockAnimationPlayer; + let p2: MockAnimationPlayer; + let p3: MockAnimationPlayer; - resetLog(); - cancelAllPlayers(players); + players = getLog(); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; - cmp.page1 = false; - cmp.loading = true; - fixture.detectChanges(); + expect(p1.element.classList.contains('loading')).toBe(true); + expect(p2.element.classList.contains('title')).toBe(true); + expect(p3.element.classList.contains('page1')).toBe(true); - players = getLog(); - cancelAllPlayers(players); + resetLog(); + cancelAllPlayers(players); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; + cmp.page1 = false; + cmp.loading = true; + fixture.detectChanges(); - expect(p1.element.classList.contains('title')).toBe(true); - expect(p2.element.classList.contains('page1')).toBe(true); - expect(p3.element.classList.contains('loading')).toBe(true); + players = getLog(); + cancelAllPlayers(players); - resetLog(); - cancelAllPlayers(players); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; - cmp.page2 = true; - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); + expect(p1.element.classList.contains('title')).toBe(true); + expect(p2.element.classList.contains('page1')).toBe(true); + expect(p3.element.classList.contains('loading')).toBe(true); - players = getLog(); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; + resetLog(); + cancelAllPlayers(players); - expect(p1.element.classList.contains('loading')).toBe(true); - expect(p2.element.classList.contains('title')).toBe(true); - expect(p3.element.classList.contains('page2')).toBe(true); - }); + cmp.page2 = true; + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); + + players = getLog(); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; + + expect(p1.element.classList.contains('loading')).toBe(true); + expect(p2.element.classList.contains('title')).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', fakeAsync(() => { diff --git a/packages/core/test/animation/animation_router_integration_spec.ts b/packages/core/test/animation/animation_router_integration_spec.ts index 2dbc90591e..e904623ec9 100644 --- a/packages/core/test/animation/animation_router_integration_spec.ts +++ b/packages/core/test/animation/animation_router_integration_spec.ts @@ -34,354 +34,349 @@ import {RouterTestingModule} from '@angular/router/testing'; }); }); - fixmeIvy('unknown').it( - 'should query the old and new routes via :leave and :enter', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':leave', animateChild()), - query(':enter', animateChild()), - ]), - ]), - ], - template: ` + it('should query the old and new routes via :leave and :enter', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':leave', animateChild()), + query(':enter', animateChild()), + ]), + ]), + ], + template: `
` - }) - class ContainerCmp { - constructor(public router: Router) {} + }) + class ContainerCmp { + constructor(public router: Router) {} - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } - } + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; + } + } - @Component({ - selector: 'page1', - template: `page1`, - animations: [ - trigger( - 'page1Animation', - [ - transition( - ':leave', - [ - style({width: '200px'}), - animate(1000, style({width: '0px'})), - ]), - ]), - ] - }) - class Page1Cmp { - @HostBinding('@page1Animation') public doAnimate = true; - } + @Component({ + selector: 'page1', + template: `page1`, + animations: [ + trigger( + 'page1Animation', + [ + transition( + ':leave', + [ + style({width: '200px'}), + animate(1000, style({width: '0px'})), + ]), + ]), + ] + }) + class Page1Cmp { + @HostBinding('@page1Animation') public doAnimate = true; + } - @Component({ - selector: 'page2', - template: `page2`, - animations: [ - trigger( - 'page2Animation', - [ - transition( - ':enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - ]), - ] - }) - class Page2Cmp { - @HostBinding('@page2Animation') public doAnimate = true; - } + @Component({ + selector: 'page2', + template: `page2`, + animations: [ + trigger( + 'page2Animation', + [ + transition( + ':enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + ]), + ] + }) + class Page2Cmp { + @HostBinding('@page2Animation') public doAnimate = true; + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); - const player = engine.players[0] !; - const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; + const player = engine.players[0] !; + const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; - expect(players.length).toEqual(2); - const [p1, p2] = players; + expect(players.length).toEqual(2); + const [p1, p2] = players; - expect(p1.duration).toEqual(1000); - expect(p1.keyframes).toEqual([ - {offset: 0, width: '200px'}, - {offset: 1, width: '0px'}, - ]); + expect(p1.duration).toEqual(1000); + expect(p1.keyframes).toEqual([ + {offset: 0, width: '200px'}, + {offset: 1, width: '0px'}, + ]); - expect(p2.duration).toEqual(2000); - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: .5, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); - })); + expect(p2.duration).toEqual(2000); + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: .5, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); + })); - fixmeIvy('unknown').it( - 'should allow inner enter animations to be emulated within a routed item', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':enter', animateChild()), - ]), - ]), - ], - template: ` + it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':enter', animateChild()), + ]), + ]), + ], + template: `
` - }) - class ContainerCmp { - constructor(public router: Router) {} + }) + class ContainerCmp { + constructor(public router: Router) {} - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } - } + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; + } + } - @Component({selector: 'page1', template: `page1`, animations: []}) - class Page1Cmp { - } + @Component({selector: 'page1', template: `page1`, animations: []}) + class Page1Cmp { + } - @Component({ - selector: 'page2', - template: ` + @Component({ + selector: 'page2', + template: `

Page 2

`, - animations: [ - trigger( - 'page2Animation', - [ - transition( - ':enter', - [query('.if-one', animateChild()), query('.if-two', animateChild())]), - ]), - trigger( - 'ifAnimation', - [transition( - ':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) - ] - }) - class Page2Cmp { - @HostBinding('@page2Animation') public doAnimate = true; + animations: [ + trigger( + 'page2Animation', + [ + transition( + ':enter', + [query('.if-one', animateChild()), query('.if-two', animateChild())]), + ]), + trigger( + 'ifAnimation', + [transition( + ':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) + ] + }) + class Page2Cmp { + @HostBinding('@page2Animation') public doAnimate = true; - public exp = true; - } + public exp = true; + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); - const player = engine.players[0] !; - const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; + const player = engine.players[0] !; + const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; - expect(players.length).toEqual(2); - const [p1, p2] = players; + expect(players.length).toEqual(2); + const [p1, p2] = players; - expect(p1.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); + expect(p1.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: .5, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); - })); + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: .5, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); + })); - fixmeIvy('unknown').it( - 'should allow inner leave animations to be emulated within a routed item', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':leave', animateChild()), - ]), - ]), - ], - template: ` + it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':leave', animateChild()), + ]), + ]), + ], + template: `
` - }) - class ContainerCmp { - constructor(public router: Router) {} + }) + class ContainerCmp { + constructor(public router: Router) {} - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } - } + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; + } + } - @Component({ - selector: 'page1', - template: ` + @Component({ + selector: 'page1', + template: `

Page 1

`, - animations: [ - trigger( - 'page1Animation', - [ - transition( - ':leave', - [query('.if-one', animateChild()), query('.if-two', animateChild())]), - ]), - trigger( - 'ifAnimation', - [transition( - ':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]), - ] - }) - class Page1Cmp { - @HostBinding('@page1Animation') public doAnimate = true; + animations: [ + trigger( + 'page1Animation', + [ + transition( + ':leave', + [query('.if-one', animateChild()), query('.if-two', animateChild())]), + ]), + trigger( + 'ifAnimation', + [transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]), + ] + }) + class Page1Cmp { + @HostBinding('@page1Animation') public doAnimate = true; - public exp = true; - } + public exp = true; + } - @Component({selector: 'page2', template: `page2`, animations: []}) - class Page2Cmp { - } + @Component({selector: 'page2', template: `page2`, animations: []}) + class Page2Cmp { + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); - const player = engine.players[0] !; - const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; + const player = engine.players[0] !; + const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; - expect(players.length).toEqual(2); - const [p1, p2] = players; + expect(players.length).toEqual(2); + const [p1, p2] = players; - expect(p1.keyframes).toEqual([ - {offset: 0, opacity: '1'}, - {offset: 1, opacity: '0'}, - ]); + expect(p1.keyframes).toEqual([ + {offset: 0, opacity: '1'}, + {offset: 1, opacity: '0'}, + ]); - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '1'}, - {offset: .5, opacity: '1'}, - {offset: 1, opacity: '0'}, - ]); - })); + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '1'}, + {offset: .5, opacity: '1'}, + {offset: 1, opacity: '0'}, + ]); + })); - fixmeIvy('unknown').it( - 'should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - animations: [ - trigger( - 'pageAnimation', - [ - transition( - 'page1 => page2', - [ - query('.router-container :leave', animate('1s', style({opacity: 0}))), - query('.router-container :enter', animate('1s', style({opacity: 1}))), - ]), - ]), - ], - template: ` + it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + animations: [ + trigger( + 'pageAnimation', + [ + transition( + 'page1 => page2', + [ + query('.router-container :leave', animate('1s', style({opacity: 0}))), + query('.router-container :enter', animate('1s', style({opacity: 1}))), + ]), + ]), + ], + template: `
@@ -394,139 +389,136 @@ import {RouterTestingModule} from '@angular/router/testing';
` - }) - class ContainerCmp { - loading = false; + }) + class ContainerCmp { + 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`}) - class Page1Cmp { - } + @Component({selector: 'page1', template: `page1`}) + class Page1Cmp { + } - @Component({selector: 'page2', template: `page2`}) - class Page2Cmp { - } + @Component({selector: 'page2', template: `page2`}) + class Page2Cmp { + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - cmp.loading = true; - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + cmp.loading = true; + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); - const players = engine.players; - expect(players.length).toEqual(1); - const [p1] = players; + const players = engine.players; + expect(players.length).toEqual(1); + const [p1] = players; - const innerPlayers = p1.getRealPlayer().players; - expect(innerPlayers.length).toEqual(2); + const innerPlayers = p1.getRealPlayer().players; + expect(innerPlayers.length).toEqual(2); - const [ip1, ip2] = innerPlayers; - expect(ip1.element.innerText).toEqual('page1'); - expect(ip2.element.innerText).toEqual('page2'); - })); + const [ip1, ip2] = innerPlayers; + expect(ip1.element.innerText).toEqual('page1'); + expect(ip2.element.innerText).toEqual('page2'); + })); - fixmeIvy('unknown').it( - 'should allow a recursive set of :leave animations to occur for nested routes', - fakeAsync(() => { - @Component( - {selector: 'ani-cmp', template: ''}) - class ContainerCmp { - constructor(private _router: Router) {} - log: string[] = []; + it('should allow a recursive set of :leave animations to occur for nested routes', + fakeAsync(() => { + @Component({selector: 'ani-cmp', template: ''}) + 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({ - selector: 'recur-page', - template: 'Depth: {{ depth }} \n ', - animations: [ - trigger( - 'pageAnimations', - [ - transition( - ':leave', [group([ - sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]), - query('@*', animateChild(), {optional: true}) - ])]), - ]), - ] - }) - class RecurPageCmp { - @HostBinding('@pageAnimations') public animatePage = true; + @Component({ + selector: 'recur-page', + template: 'Depth: {{ depth }} \n ', + animations: [ + trigger( + 'pageAnimations', + [ + transition(':leave', [group([ + sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]), + query('@*', animateChild(), {optional: 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) { - this.route.data.subscribe(data => { - this.container.log.push(`DEPTH ${data.depth}`); - this.depth = data.depth; - }); - } - } + constructor(private container: ContainerCmp, private route: ActivatedRoute) { + this.route.data.subscribe(data => { + this.container.log.push(`DEPTH ${data.depth}`); + this.depth = data.depth; + }); + } + } - TestBed.configureTestingModule({ - declarations: [ContainerCmp, RecurPageCmp], - imports: [RouterTestingModule.withRoutes([{ - path: 'recur', - component: RecurPageCmp, - outlet: 'recur', - data: {depth: 0}, - children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}] - }])] - }); + TestBed.configureTestingModule({ + declarations: [ContainerCmp, RecurPageCmp], + imports: [RouterTestingModule.withRoutes([{ + path: 'recur', + component: RecurPageCmp, + outlet: 'recur', + data: {depth: 0}, + children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}] + }])] + }); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.enter(); - tick(); - fixture.detectChanges(); - flushMicrotasks(); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.enter(); + tick(); + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.log).toEqual([ - 'DEPTH 0', - 'DEPTH 1', - ]); + expect(cmp.log).toEqual([ + 'DEPTH 0', + 'DEPTH 1', + ]); - cmp.leave(); - tick(); - fixture.detectChanges(); + cmp.leave(); + tick(); + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); + const players = getLog(); + expect(players.length).toEqual(2); - const [p1, p2] = players; - expect(p1.element.getAttribute('data-depth')).toEqual('0'); - expect(p2.element.getAttribute('data-depth')).toEqual('1'); - })); + const [p1, p2] = players; + expect(p1.element.getAttribute('data-depth')).toEqual('0'); + expect(p2.element.getAttribute('data-depth')).toEqual('1'); + })); }); }); diff --git a/packages/core/test/animation/animations_with_web_animations_integration_spec.ts b/packages/core/test/animation/animations_with_web_animations_integration_spec.ts index 7b2ec1ec2a..e510e7bd2d 100644 --- a/packages/core/test/animation/animations_with_web_animations_integration_spec.ts +++ b/packages/core/test/animation/animations_with_web_animations_integration_spec.ts @@ -242,10 +242,9 @@ import {fixmeIvy} from '@angular/private/testing'; ]); }); - fixmeIvy('unknown').it( - 'should treat * styles as ! for queried items that are collected in a container that is being removed', - () => { - @Component({ + it('should treat * styles as ! for queried items that are collected in a container that is being removed', + () => { + @Component({ selector: 'my-app', styles: [` .list .outer { @@ -286,58 +285,58 @@ import {fixmeIvy} from '@angular/private/testing'; ] }) 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 fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.empty(); - fixture.detectChanges(); - let player = engine.players[0] !as TransitionAnimationPlayer; - player.finish(); + cmp.empty(); + fixture.detectChanges(); + let player = engine.players[0] !as TransitionAnimationPlayer; + player.finish(); - cmp.full(); - fixture.detectChanges(); + cmp.full(); + fixture.detectChanges(); - player = engine.players[0] !as TransitionAnimationPlayer; - let queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; - expect(queriedPlayers.length).toEqual(5); + player = engine.players[0] !as TransitionAnimationPlayer; + let queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; + expect(queriedPlayers.length).toEqual(5); - let i = 0; - for (i = 0; i < queriedPlayers.length; i++) { - let player = queriedPlayers[i] as ɵWebAnimationsPlayer; - expect(player.keyframes).toEqual([ - {height: '0px', offset: 0}, - {height: '50px', offset: 1}, - ]); - player.finish(); - } + let i = 0; + for (i = 0; i < queriedPlayers.length; i++) { + let player = queriedPlayers[i] as ɵWebAnimationsPlayer; + expect(player.keyframes).toEqual([ + {height: '0px', offset: 0}, + {height: '50px', offset: 1}, + ]); + player.finish(); + } - cmp.empty(); - fixture.detectChanges(); + cmp.empty(); + fixture.detectChanges(); - player = engine.players[0] !as TransitionAnimationPlayer; - queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; - expect(queriedPlayers.length).toEqual(5); + player = engine.players[0] !as TransitionAnimationPlayer; + queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; + expect(queriedPlayers.length).toEqual(5); - for (i = 0; i < queriedPlayers.length; i++) { - let player = queriedPlayers[i] as ɵWebAnimationsPlayer; - expect(player.keyframes).toEqual([ - {height: '50px', offset: 0}, - {height: '0px', offset: 1}, - ]); - } - }); + for (i = 0; i < queriedPlayers.length; i++) { + let player = queriedPlayers[i] as ɵWebAnimationsPlayer; + expect(player.keyframes).toEqual([ + {height: '50px', offset: 0}, + {height: '0px', offset: 1}, + ]); + } + }); it('should compute intermediate styles properly when an animation is cancelled', () => { @Component({ diff --git a/packages/platform-browser/animations/test/animation_renderer_spec.ts b/packages/platform-browser/animations/test/animation_renderer_spec.ts index 733aa52763..2f26069c0f 100644 --- a/packages/platform-browser/animations/test/animation_renderer_spec.ts +++ b/packages/platform-browser/animations/test/animation_renderer_spec.ts @@ -279,36 +279,35 @@ import {el} from '../../testing/src/browser_util'; }); }); - fixmeIvy(`FW-802: Animation 'start' and 'end' hooks are invoked twice`) - .it('should provide hooks at the start and end of change detection', () => { - @Component({ - selector: 'my-cmp', - template: ` + it('should provide hooks at the start and end of change detection', () => { + @Component({ + selector: 'my-cmp', + template: `
`, - animations: [trigger('myAnimation', [])] - }) - class Cmp { - public exp: any; - } + animations: [trigger('myAnimation', [])] + }) + class Cmp { + public exp: any; + } - TestBed.configureTestingModule({ - providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], - declarations: [Cmp] - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], + declarations: [Cmp] + }); - const renderer = TestBed.get(RendererFactory2) as ExtendedAnimationRendererFactory; - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const renderer = TestBed.get(RendererFactory2) as ExtendedAnimationRendererFactory; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - renderer.log = []; - fixture.detectChanges(); - expect(renderer.log).toEqual(['begin', 'end']); + renderer.log = []; + fixture.detectChanges(); + expect(renderer.log).toEqual(['begin', 'end']); - renderer.log = []; - fixture.detectChanges(); - expect(renderer.log).toEqual(['begin', 'end']); - }); + renderer.log = []; + fixture.detectChanges(); + expect(renderer.log).toEqual(['begin', 'end']); + }); }); })();