test(core): animation renderer factory in render3 (#20855)

PR Close #20855
This commit is contained in:
Marc Laval 2017-12-15 17:50:54 +01:00 committed by Igor Minar
parent bbdea96a66
commit 764fea1344
6 changed files with 133 additions and 7 deletions

View File

@ -15,6 +15,10 @@ ts_library(
"//packages:types", "//packages:types",
"//packages/core", "//packages/core",
"//packages/platform-browser", "//packages/platform-browser",
"//packages/platform-browser/animations",
"//packages/animations",
"//packages/animations/browser",
"//packages/animations/browser/testing",
], ],
) )

View File

@ -170,6 +170,6 @@ describe('encapsulation', () => {
renderComponent(WrapperComponentWith, getRendererFactory2(document)); renderComponent(WrapperComponentWith, getRendererFactory2(document));
expect(containerEl.outerHTML) expect(containerEl.outerHTML)
.toEqual( .toEqual(
'<div host="" _nghost-c1=""><leaf _ngcontent-c1="" _nghost-c2=""><span _ngcontent-c2="">bar</span></leaf></div>'); '<div host="" _nghost-c2=""><leaf _ngcontent-c2="" _nghost-c3=""><span _ngcontent-c3="">bar</span></leaf></div>');
}); });
}); });

View File

@ -6,8 +6,12 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ɵAnimationEngine, ɵNoopAnimationStyleNormalizer} from '@angular/animations/browser';
import {MockAnimationDriver} from '@angular/animations/browser/testing';
import {EventEmitter, NgZone, RendererFactory2} from '@angular/core'; import {EventEmitter, NgZone, RendererFactory2} from '@angular/core';
import {EventManager, ɵDomEventsPlugin, ɵDomRendererFactory2, ɵDomSharedStylesHost} from '@angular/platform-browser'; import {EventManager, ɵDomEventsPlugin, ɵDomRendererFactory2, ɵDomSharedStylesHost} from '@angular/platform-browser';
import {ɵAnimationRendererFactory} from '@angular/platform-browser/animations';
// Adapted renderer: it creates a Renderer2 instance and adapts it to Renderer3 // Adapted renderer: it creates a Renderer2 instance and adapts it to Renderer3
// TODO: remove once this code is in angular/angular // TODO: remove once this code is in angular/angular
@ -52,3 +56,11 @@ export function getRendererFactory2(document: any): RendererFactory2 {
new EventManager([new SimpleDomEventsPlugin(document, fakeNgZone)], fakeNgZone); new EventManager([new SimpleDomEventsPlugin(document, fakeNgZone)], fakeNgZone);
return new ɵDomRendererFactory2(eventManager, new ɵDomSharedStylesHost(document)); return new ɵDomRendererFactory2(eventManager, new ɵDomSharedStylesHost(document));
} }
export function getAnimationRendererFactory2(document: any): RendererFactory2 {
const fakeNgZone: NgZone = new NoopNgZone();
return new ɵAnimationRendererFactory(
getRendererFactory2(document),
new ɵAnimationEngine(new MockAnimationDriver(), new ɵNoopAnimationStyleNormalizer()),
fakeNgZone);
}

View File

@ -6,8 +6,12 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
// Needed to run animation tests
require('zone.js/dist/zone-node.js');
if (typeof window == 'undefined') { if (typeof window == 'undefined') {
const createWindow = require('domino').createWindow; const domino = require('domino');
const createWindow = domino.createWindow;
const window = createWindow('', 'http://localhost'); const window = createWindow('', 'http://localhost');
(global as any).document = window.document; (global as any).document = window.document;
@ -16,4 +20,8 @@ if (typeof window == 'undefined') {
// It fails with Domino with TypeError: Cannot assign to read only property // It fails with Domino with TypeError: Cannot assign to read only property
// 'stopImmediatePropagation' of object '#<Event>' // 'stopImmediatePropagation' of object '#<Event>'
(global as any).Event = null; (global as any).Event = null;
// For animation tests, see
// https://github.com/angular/angular/blob/master/packages/animations/browser/src/render/shared.ts#L140
(global as any).Element = domino.impl.Element;
} }

View File

@ -33,8 +33,12 @@ requestAnimationFrame.flush = function() {
export function resetDOM() { export function resetDOM() {
requestAnimationFrame.queue = []; requestAnimationFrame.queue = [];
if (containerEl) {
document.body.removeChild(containerEl);
}
containerEl = document.createElement('div'); containerEl = document.createElement('div');
containerEl.setAttribute('host', ''); containerEl.setAttribute('host', '');
document.body.appendChild(containerEl);
host = null; host = null;
// TODO: assert that the global state is clean (e.g. ngData, previousOrParentNode, etc) // TODO: assert that the global state is clean (e.g. ngData, previousOrParentNode, etc)
} }

View File

@ -6,13 +6,15 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {RendererType2} from '@angular/core'; import {AnimationEvent} from '@angular/animations';
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
import {D, E, e} from '../../src/render3'; import {RendererType2, ViewEncapsulation} from '../../src/core';
import {T, defineComponent, detectChanges} from '../../src/render3/index'; import {D, E, L, T, b, defineComponent, detectChanges, e, p} from '../../src/render3';
import {createRendererType2} from '../../src/view';
import {getRendererFactory2} from './imported_renderer2'; import {getAnimationRendererFactory2, getRendererFactory2} from './imported_renderer2';
import {document, renderComponent, renderToHtml, resetDOM} from './render_util'; import {containerEl, document, renderComponent, renderToHtml} from './render_util';
describe('renderer factory lifecycle', () => { describe('renderer factory lifecycle', () => {
let logs: string[] = []; let logs: string[] = [];
@ -104,3 +106,99 @@ describe('renderer factory lifecycle', () => {
}); });
}); });
describe('animation renderer factory', () => {
let eventLogs: string[] = [];
function getLog(): MockAnimationPlayer[] {
return MockAnimationDriver.log as MockAnimationPlayer[];
}
function resetLog() { MockAnimationDriver.log = []; }
beforeEach(() => {
eventLogs = [];
resetLog();
});
class SomeComponent {
static ngComponentDef = defineComponent({
type: SomeComponent,
tag: 'some-component',
template: function(ctx: SomeComponent, cm: boolean) {
if (cm) {
T(0, 'foo');
}
},
factory: () => new SomeComponent
});
}
class SomeComponentWithAnimation {
exp: string;
callback(event: AnimationEvent) {
eventLogs.push(`${event.fromState ? event.fromState : event.toState} - ${event.phaseName}`);
}
static ngComponentDef = defineComponent({
type: SomeComponentWithAnimation,
tag: 'some-component',
template: function(ctx: SomeComponentWithAnimation, cm: boolean) {
if (cm) {
E(0, 'div');
{
L('@myAnimation.start', ctx.callback.bind(ctx));
L('@myAnimation.done', ctx.callback.bind(ctx));
T(1, 'foo');
}
e();
}
p(0, '@myAnimation', b(ctx.exp));
},
factory: () => new SomeComponentWithAnimation,
rendererType: createRendererType2({
encapsulation: ViewEncapsulation.None,
styles: [],
data: {
animation: [{
type: 7,
name: 'myAnimation',
definitions: [{
type: 1,
expr: '* => on',
animation:
[{type: 4, styles: {type: 6, styles: {opacity: 1}, offset: null}, timings: 10}],
options: null
}],
options: {}
}]
}
}),
});
}
it('should work with components without animations', () => {
renderComponent(SomeComponent, getAnimationRendererFactory2(document));
expect(containerEl.innerHTML).toEqual('foo');
});
it('should work with animated components', (done) => {
const factory = getAnimationRendererFactory2(document);
const component = renderComponent(SomeComponentWithAnimation, factory);
expect(containerEl.innerHTML)
.toEqual('<div class="ng-tns-c1-0 ng-trigger ng-trigger-myAnimation">foo</div>');
component.exp = 'on';
detectChanges(component);
const [player] = getLog();
expect(player.keyframes).toEqual([
{opacity: '*', offset: 0},
{opacity: 1, offset: 1},
]);
player.finish();
factory.whenRenderingDone !().then(() => {
expect(eventLogs).toEqual(['void - start', 'void - done', 'on - start', 'on - done']);
done();
});
});
});