fix(ivy): ensure animation @bindings work for {key:value} and empty bindings (#28026)
PR Close #28026
This commit is contained in:

committed by
Andrew Kushnir

parent
0136274f33
commit
94c0b7a362
@ -688,10 +688,19 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||||||
const instruction = mapBindingToInstruction(input.type);
|
const instruction = mapBindingToInstruction(input.type);
|
||||||
if (input.type === BindingType.Animation) {
|
if (input.type === BindingType.Animation) {
|
||||||
const value = input.value.visit(this._valueConverter);
|
const value = input.value.visit(this._valueConverter);
|
||||||
// setProperty without a value doesn't make any sense
|
// animation bindings can be presented in the following formats:
|
||||||
if (value.name || value.value) {
|
// 1j [@binding]="fooExp"
|
||||||
const bindingName = prepareSyntheticPropertyName(input.name);
|
// 2. [@binding]="{value:fooExp, params:{...}}"
|
||||||
|
// 3. [@binding]
|
||||||
|
// 4. @binding
|
||||||
|
// only formats 1. and 2. include the actual binding of a value to
|
||||||
|
// an expression and therefore only those should be the only two that
|
||||||
|
// are allowed. The check below ensures that a binding with no expression
|
||||||
|
// does not get an empty `elementProperty` instruction created for it.
|
||||||
|
const hasValue = value && (value instanceof LiteralPrimitive) ? !!value.value : true;
|
||||||
|
if (hasValue) {
|
||||||
this.allocateBindingSlots(value);
|
this.allocateBindingSlots(value);
|
||||||
|
const bindingName = prepareSyntheticPropertyName(input.name);
|
||||||
this.updateInstruction(input.sourceSpan, R3.elementProperty, () => {
|
this.updateInstruction(input.sourceSpan, R3.elementProperty, () => {
|
||||||
return [
|
return [
|
||||||
o.literal(elementIndex), o.literal(bindingName),
|
o.literal(elementIndex), o.literal(bindingName),
|
||||||
|
@ -373,48 +373,48 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
expect(players.length).toEqual(0);
|
expect(players.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('unknown').it(
|
it('should allow a transition to use a function to determine what method to run and expose any parameter values',
|
||||||
'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',
|
||||||
template: '<div [@myAnimation]="{value:exp, params: {doMatch:doMatch}}"></div>',
|
template: '<div [@myAnimation]="{value:exp, params: {doMatch:doMatch}}"></div>',
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'myAnimation',
|
'myAnimation',
|
||||||
[transition(
|
[transition(
|
||||||
transitionFn, [style({opacity: 0}), animate(3333, style({opacity: 1}))])]),
|
transitionFn, [style({opacity: 0}), animate(3333, style({opacity: 1}))])]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
doMatch = false;
|
doMatch = false;
|
||||||
exp: any = '';
|
exp: any = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
cmp.doMatch = true;
|
cmp.doMatch = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let players = getLog();
|
let players = getLog();
|
||||||
expect(players.length).toEqual(1);
|
expect(players.length).toEqual(1);
|
||||||
let [p1] = players;
|
let [p1] = players;
|
||||||
expect(p1.totalTime).toEqual(3333);
|
expect(p1.totalTime).toEqual(3333);
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
cmp.doMatch = false;
|
cmp.doMatch = false;
|
||||||
cmp.exp = 'this-wont-match';
|
cmp.exp = 'this-wont-match';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
players = getLog();
|
players = getLog();
|
||||||
expect(players.length).toEqual(0);
|
expect(players.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow a state value to be `0`', () => {
|
it('should allow a state value to be `0`', () => {
|
||||||
@Component({
|
@Component({
|
||||||
@ -1567,62 +1567,64 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('FW-932: Animation @triggers are not reported to the renderer in Ivy as they are in VE').it(
|
fixmeIvy(
|
||||||
'should animate removals of nodes to the `void` state for each animation trigger, but treat all auto styles as pre styles',
|
'FW-932: Animation @triggers are not reported to the renderer in Ivy as they are in VE')
|
||||||
() => {
|
.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',
|
@Component({
|
||||||
template: `
|
selector: 'ani-cmp',
|
||||||
|
template: `
|
||||||
<div *ngIf="exp" class="ng-if" [@trig1]="exp2" @trig2></div>
|
<div *ngIf="exp" class="ng-if" [@trig1]="exp2" @trig2></div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger('trig1', [transition(
|
||||||
'trig1', [transition('state => void', [animate(1000, style({opacity: 0}))])]),
|
'state => void', [animate(1000, style({opacity: 0}))])]),
|
||||||
trigger('trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])])
|
trigger(
|
||||||
]
|
'trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])])
|
||||||
})
|
]
|
||||||
class Cmp {
|
})
|
||||||
public exp = true;
|
class Cmp {
|
||||||
public exp2 = 'state';
|
public exp = true;
|
||||||
}
|
public exp2 = 'state';
|
||||||
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
cmp.exp = true;
|
cmp.exp = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
const element = getDOM().querySelector(fixture.nativeElement, '.ng-if');
|
const element = getDOM().querySelector(fixture.nativeElement, '.ng-if');
|
||||||
assertHasParent(element, true);
|
assertHasParent(element, true);
|
||||||
|
|
||||||
cmp.exp = false;
|
cmp.exp = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
assertHasParent(element, true);
|
assertHasParent(element, true);
|
||||||
|
|
||||||
expect(getLog().length).toEqual(2);
|
expect(getLog().length).toEqual(2);
|
||||||
|
|
||||||
const player2 = getLog().pop() !;
|
const player2 = getLog().pop() !;
|
||||||
const player1 = getLog().pop() !;
|
const player1 = getLog().pop() !;
|
||||||
|
|
||||||
expect(player2.keyframes).toEqual([
|
expect(player2.keyframes).toEqual([
|
||||||
{width: PRE_STYLE, offset: 0},
|
{width: PRE_STYLE, offset: 0},
|
||||||
{width: '0px', offset: 1},
|
{width: '0px', offset: 1},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(player1.keyframes).toEqual([
|
expect(player1.keyframes).toEqual([
|
||||||
{opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1}
|
{opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
player2.finish();
|
player2.finish();
|
||||||
player1.finish();
|
player1.finish();
|
||||||
assertHasParent(element, false);
|
assertHasParent(element, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should properly cancel all existing animations when a removal occurs', () => {
|
it('should properly cancel all existing animations when a removal occurs', () => {
|
||||||
@Component({
|
@Component({
|
||||||
@ -1926,147 +1928,146 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
expect(p.contains(c2)).toBeTruthy();
|
expect(p.contains(c2)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('unknown').it(
|
it('should detect trigger changes based on object.value properties', () => {
|
||||||
'should detect trigger changes based on object.value properties', () => {
|
@Component({
|
||||||
@Component({
|
selector: 'ani-cmp',
|
||||||
selector: 'ani-cmp',
|
template: `
|
||||||
template: `
|
|
||||||
<div [@myAnimation]="{value:exp}"></div>
|
<div [@myAnimation]="{value:exp}"></div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'myAnimation',
|
'myAnimation',
|
||||||
[
|
[
|
||||||
transition('* => 1', [animate(1234, style({opacity: 0}))]),
|
transition('* => 1', [animate(1234, style({opacity: 0}))]),
|
||||||
transition('* => 2', [animate(5678, style({opacity: 0}))]),
|
transition('* => 2', [animate(5678, style({opacity: 0}))]),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
public exp: any;
|
public exp: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
|
|
||||||
cmp.exp = '1';
|
cmp.exp = '1';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
let players = getLog();
|
let players = getLog();
|
||||||
expect(players.length).toEqual(1);
|
expect(players.length).toEqual(1);
|
||||||
expect(players[0].duration).toEqual(1234);
|
expect(players[0].duration).toEqual(1234);
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
cmp.exp = '2';
|
cmp.exp = '2';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
players = getLog();
|
players = getLog();
|
||||||
expect(players.length).toEqual(1);
|
expect(players.length).toEqual(1);
|
||||||
expect(players[0].duration).toEqual(5678);
|
expect(players[0].duration).toEqual(5678);
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('FW-932: Animation @triggers are not reported to the renderer in Ivy as they are in VE').it(
|
fixmeIvy(
|
||||||
'should not render animations when the object expression value is the same as it was previously',
|
'FW-932: Animation @triggers are not reported to the renderer in Ivy as they are in VE')
|
||||||
() => {
|
.it('should not render animations when the object expression value is the same as it was previously',
|
||||||
@Component({
|
() => {
|
||||||
selector: 'ani-cmp',
|
@Component({
|
||||||
template: `
|
selector: 'ani-cmp',
|
||||||
|
template: `
|
||||||
<div [@myAnimation]="{value:exp,params:params}"></div>
|
<div [@myAnimation]="{value:exp,params:params}"></div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'myAnimation',
|
'myAnimation',
|
||||||
[
|
[
|
||||||
transition('* => *', [animate(1234, style({opacity: 0}))]),
|
transition('* => *', [animate(1234, style({opacity: 0}))]),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
public exp: any;
|
public exp: any;
|
||||||
public params: any;
|
public params: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
|
|
||||||
cmp.exp = '1';
|
cmp.exp = '1';
|
||||||
cmp.params = {};
|
cmp.params = {};
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
let players = getLog();
|
let players = getLog();
|
||||||
expect(players.length).toEqual(1);
|
expect(players.length).toEqual(1);
|
||||||
expect(players[0].duration).toEqual(1234);
|
expect(players[0].duration).toEqual(1234);
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
cmp.exp = '1';
|
cmp.exp = '1';
|
||||||
cmp.params = {};
|
cmp.params = {};
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
players = getLog();
|
players = getLog();
|
||||||
expect(players.length).toEqual(0);
|
expect(players.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('unknown').it(
|
it('should update the final state styles when params update even if the expression hasn\'t changed',
|
||||||
'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',
|
template: `
|
||||||
template: `
|
|
||||||
<div [@myAnimation]="{value:exp,params:{color:color}}"></div>
|
<div [@myAnimation]="{value:exp,params:{color:color}}"></div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'myAnimation',
|
'myAnimation',
|
||||||
[
|
[
|
||||||
state('*', style({color: '{{ color }}'}), {params: {color: 'black'}}),
|
state('*', style({color: '{{ color }}'}), {params: {color: 'black'}}),
|
||||||
transition('* => 1', animate(500))
|
transition('* => 1', animate(500))
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
public exp: any;
|
public exp: any;
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
public color !: string | null;
|
public color !: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
|
|
||||||
cmp.exp = '1';
|
cmp.exp = '1';
|
||||||
cmp.color = 'red';
|
cmp.color = 'red';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const player = getLog()[0] !;
|
const player = getLog()[0] !;
|
||||||
const element = player.element;
|
const element = player.element;
|
||||||
player.finish();
|
player.finish();
|
||||||
|
|
||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
expect(getDOM().hasStyle(element, 'color', 'red')).toBeTruthy();
|
expect(getDOM().hasStyle(element, 'color', 'red')).toBeTruthy();
|
||||||
|
|
||||||
cmp.exp = '1';
|
cmp.exp = '1';
|
||||||
cmp.color = 'blue';
|
cmp.color = 'blue';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy();
|
expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy();
|
||||||
|
|
||||||
cmp.exp = '1';
|
cmp.exp = '1';
|
||||||
cmp.color = null;
|
cmp.color = null;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
expect(getDOM().hasStyle(element, 'color', 'black')).toBeTruthy();
|
expect(getDOM().hasStyle(element, 'color', 'black')).toBeTruthy();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should substitute in values if the provided state match is an object with values', () => {
|
it('should substitute in values if the provided state match is an object with values', () => {
|
||||||
@Component({
|
@Component({
|
||||||
@ -2105,73 +2106,72 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('unknown').it(
|
it('should retain substituted styles on the element once the animation is complete if referenced in the final state',
|
||||||
'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',
|
template: `
|
||||||
template: `
|
|
||||||
<div [@myAnimation]="{value:exp, params: { color: color }}"></div>
|
<div [@myAnimation]="{value:exp, params: { color: color }}"></div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger(
|
trigger(
|
||||||
'myAnimation',
|
'myAnimation',
|
||||||
[
|
[
|
||||||
state(
|
state(
|
||||||
'start', style({
|
'start', style({
|
||||||
color: '{{ color }}',
|
color: '{{ color }}',
|
||||||
fontSize: '{{ fontSize }}px',
|
fontSize: '{{ fontSize }}px',
|
||||||
width: '{{ width }}'
|
width: '{{ width }}'
|
||||||
}),
|
}),
|
||||||
{params: {color: 'red', fontSize: '200', width: '10px'}}),
|
{params: {color: 'red', fontSize: '200', width: '10px'}}),
|
||||||
|
|
||||||
state(
|
state(
|
||||||
'final',
|
'final',
|
||||||
style(
|
style(
|
||||||
{color: '{{ color }}', fontSize: '{{ fontSize }}px', width: '888px'}),
|
{color: '{{ color }}', fontSize: '{{ fontSize }}px', width: '888px'}),
|
||||||
{params: {color: 'green', fontSize: '50', width: '100px'}}),
|
{params: {color: 'green', fontSize: '50', width: '100px'}}),
|
||||||
|
|
||||||
transition('start => final', animate(500)),
|
transition('start => final', animate(500)),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
public exp: any;
|
public exp: any;
|
||||||
public color: any;
|
public color: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
|
|
||||||
cmp.exp = 'start';
|
cmp.exp = 'start';
|
||||||
cmp.color = 'red';
|
cmp.color = 'red';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
cmp.exp = 'final';
|
cmp.exp = 'final';
|
||||||
cmp.color = 'blue';
|
cmp.color = 'blue';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const players = getLog();
|
const players = getLog();
|
||||||
expect(players.length).toEqual(1);
|
expect(players.length).toEqual(1);
|
||||||
const [p1] = players;
|
const [p1] = players;
|
||||||
|
|
||||||
expect(p1.keyframes).toEqual([
|
expect(p1.keyframes).toEqual([
|
||||||
{color: 'red', fontSize: '200px', width: '10px', offset: 0},
|
{color: 'red', fontSize: '200px', width: '10px', offset: 0},
|
||||||
{color: 'blue', fontSize: '50px', width: '888px', offset: 1}
|
{color: 'blue', fontSize: '50px', width: '888px', offset: 1}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const element = p1.element;
|
const element = p1.element;
|
||||||
p1.finish();
|
p1.finish();
|
||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
|
|
||||||
expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy();
|
expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy();
|
||||||
expect(getDOM().hasStyle(element, 'fontSize', '50px')).toBeTruthy();
|
expect(getDOM().hasStyle(element, 'fontSize', '50px')).toBeTruthy();
|
||||||
expect(getDOM().hasStyle(element, 'width', '888px')).toBeTruthy();
|
expect(getDOM().hasStyle(element, 'width', '888px')).toBeTruthy();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should only evaluate final state param substitutions from the expression and state values and not from the transition options ',
|
it('should only evaluate final state param substitutions from the expression and state values and not from the transition options ',
|
||||||
fakeAsync(() => {
|
fakeAsync(() => {
|
||||||
|
@ -2444,28 +2444,27 @@ import {HostListener} from '../../src/metadata/directives';
|
|||||||
expect(element.innerText.trim()).toMatch(/this\s+child/mg);
|
expect(element.innerText.trim()).toMatch(/this\s+child/mg);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
fixmeIvy('unknown').it(
|
it('should only mark outermost *directive nodes :enter and :leave when inserts and removals occur',
|
||||||
'should only mark outermost *directive nodes :enter and :leave when inserts and removals occur',
|
() => {
|
||||||
() => {
|
@Component({
|
||||||
@Component({
|
selector: 'ani-cmp',
|
||||||
selector: 'ani-cmp',
|
animations: [
|
||||||
animations: [
|
trigger(
|
||||||
trigger(
|
'anim',
|
||||||
'anim',
|
[
|
||||||
[
|
transition(
|
||||||
transition(
|
'* => enter',
|
||||||
'* => enter',
|
[
|
||||||
[
|
query(':enter', [animate(1000, style({color: 'red'}))]),
|
||||||
query(':enter', [animate(1000, style({color: 'red'}))]),
|
]),
|
||||||
]),
|
transition(
|
||||||
transition(
|
'* => leave',
|
||||||
'* => leave',
|
[
|
||||||
[
|
query(':leave', [animate(1000, style({color: 'blue'}))]),
|
||||||
query(':leave', [animate(1000, style({color: 'blue'}))]),
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
],
|
||||||
],
|
template: `
|
||||||
template: `
|
|
||||||
<section class="container" [@anim]="exp ? 'enter' : 'leave'">
|
<section class="container" [@anim]="exp ? 'enter' : 'leave'">
|
||||||
<div class="a" *ngIf="exp">
|
<div class="a" *ngIf="exp">
|
||||||
<div class="b" *ngIf="exp">
|
<div class="b" *ngIf="exp">
|
||||||
@ -2481,43 +2480,43 @@ import {HostListener} from '../../src/metadata/directives';
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
// TODO(issue/24571): remove '!'.
|
// TODO(issue/24571): remove '!'.
|
||||||
public exp !: boolean;
|
public exp !: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
const engine = TestBed.get(ɵAnimationEngine);
|
const engine = TestBed.get(ɵAnimationEngine);
|
||||||
const fixture = TestBed.createComponent(Cmp);
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
const container = fixture.elementRef.nativeElement;
|
const container = fixture.elementRef.nativeElement;
|
||||||
|
|
||||||
cmp.exp = true;
|
cmp.exp = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
let players = getLog();
|
let players = getLog();
|
||||||
resetLog();
|
resetLog();
|
||||||
expect(players.length).toEqual(2);
|
expect(players.length).toEqual(2);
|
||||||
const [p1, p2] = players;
|
const [p1, p2] = players;
|
||||||
|
|
||||||
expect(p1.element.classList.contains('a'));
|
expect(p1.element.classList.contains('a'));
|
||||||
expect(p2.element.classList.contains('d'));
|
expect(p2.element.classList.contains('d'));
|
||||||
|
|
||||||
cmp.exp = false;
|
cmp.exp = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
engine.flush();
|
engine.flush();
|
||||||
|
|
||||||
players = getLog();
|
players = getLog();
|
||||||
resetLog();
|
resetLog();
|
||||||
expect(players.length).toEqual(2);
|
expect(players.length).toEqual(2);
|
||||||
const [p3, p4] = players;
|
const [p3, p4] = players;
|
||||||
|
|
||||||
expect(p3.element.classList.contains('a'));
|
expect(p3.element.classList.contains('a'));
|
||||||
expect(p4.element.classList.contains('d'));
|
expect(p4.element.classList.contains('d'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should collect multiple root levels of :enter and :leave nodes', () => {
|
it('should collect multiple root levels of :enter and :leave nodes', () => {
|
||||||
@Component({
|
@Component({
|
||||||
|
Reference in New Issue
Block a user