diff --git a/packages/core/test/acceptance/BUILD.bazel b/packages/core/test/acceptance/BUILD.bazel
index 8f74f3f99a..c037d23381 100644
--- a/packages/core/test/acceptance/BUILD.bazel
+++ b/packages/core/test/acceptance/BUILD.bazel
@@ -1,6 +1,6 @@
package(default_visibility = ["//visibility:private"])
-load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
+load("//tools:defaults.bzl", "jasmine_node_test", "ts_library", "ts_web_test_suite")
ts_library(
name = "acceptance_lib",
@@ -9,6 +9,9 @@ ts_library(
["**/*.ts"],
),
deps = [
+ "//packages/animations",
+ "//packages/animations/browser",
+ "//packages/animations/browser/testing",
"//packages/common",
"//packages/compiler",
"//packages/compiler/testing",
@@ -17,7 +20,9 @@ ts_library(
"//packages/core/testing",
"//packages/platform-browser",
"//packages/platform-browser-dynamic",
+ "//packages/platform-browser/animations",
"//packages/platform-browser/testing",
+ "//packages/platform-server",
"//packages/private/testing",
"@npm//zone.js",
],
@@ -34,3 +39,10 @@ jasmine_node_test(
"@npm//zone.js",
],
)
+
+ts_web_test_suite(
+ name = "acceptance_web",
+ deps = [
+ ":acceptance_lib",
+ ],
+)
diff --git a/packages/core/test/acceptance/renderer_factory_spec.ts b/packages/core/test/acceptance/renderer_factory_spec.ts
new file mode 100644
index 0000000000..be26ca3543
--- /dev/null
+++ b/packages/core/test/acceptance/renderer_factory_spec.ts
@@ -0,0 +1,200 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {AnimationEvent} from '@angular/animations';
+import {ɵAnimationEngine, ɵNoopAnimationStyleNormalizer} from '@angular/animations/browser';
+import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
+import {DOCUMENT} from '@angular/common';
+import {Component, DoCheck, NgZone, RendererFactory2, RendererType2} from '@angular/core';
+import {NoopNgZone} from '@angular/core/src/zone/ng_zone';
+import {TestBed} from '@angular/core/testing';
+import {EventManager, ɵDomSharedStylesHost} from '@angular/platform-browser';
+import {ɵAnimationRendererFactory} from '@angular/platform-browser/animations';
+import {expect} from '@angular/platform-browser/testing/src/matchers';
+import {ServerRendererFactory2} from '@angular/platform-server/src/server_renderer';
+import {onlyInIvy} from '@angular/private/testing';
+
+describe('renderer factory lifecycle', () => {
+ let logs: string[] = [];
+
+ @Component({selector: 'some-component', template: `foo`})
+ class SomeComponent implements DoCheck {
+ ngOnInit() { logs.push('some_component create'); }
+ ngDoCheck() { logs.push('some_component update'); }
+ }
+
+ @Component({selector: 'some-component-with-error', template: `With error`})
+ class SomeComponentWhichThrows {
+ ngOnInit() { throw new Error('SomeComponentWhichThrows threw'); }
+ }
+
+ @Component({selector: 'lol', template: ``})
+ class TestComponent implements DoCheck {
+ ngOnInit() { logs.push('test_component create'); }
+ ngDoCheck() { logs.push('test_component update'); }
+ }
+
+ /** Creates a patched renderer factory that pushes entries to the test log */
+ function createPatchedRendererFactory(document: any) {
+ let rendererFactory = getRendererFactory2(document);
+ const createRender = rendererFactory.createRenderer;
+
+ rendererFactory.createRenderer = (hostElement: any, type: RendererType2 | null) => {
+ logs.push('create');
+ return createRender.apply(rendererFactory, [hostElement, type]);
+ };
+
+ rendererFactory.begin = () => logs.push('begin');
+ rendererFactory.end = () => logs.push('end');
+
+ return rendererFactory;
+ }
+
+ beforeEach(() => {
+ logs = [];
+
+ TestBed.configureTestingModule({
+ declarations: [SomeComponent, SomeComponentWhichThrows, TestComponent],
+ providers: [{
+ provide: RendererFactory2,
+ useFactory: (document: any) => createPatchedRendererFactory(document),
+ deps: [DOCUMENT]
+ }]
+ });
+ });
+
+ onlyInIvy('FW-1320: Ivy creates renderer twice.').it('should work with a component', () => {
+ const fixture = TestBed.createComponent(SomeComponent);
+ fixture.detectChanges();
+ expect(logs).toEqual(
+ ['create', 'create', 'begin', 'some_component create', 'some_component update', 'end']);
+
+ logs = [];
+ fixture.detectChanges();
+ expect(logs).toEqual(['begin', 'some_component update', 'end']);
+ });
+
+ onlyInIvy('FW-1320: Ivy creates renderer twice.')
+ .it('should work with a component which throws', () => {
+ expect(() => {
+ const fixture = TestBed.createComponent(SomeComponentWhichThrows);
+ fixture.detectChanges();
+ }).toThrow();
+ expect(logs).toEqual(['create', 'create', 'begin', 'end']);
+ });
+});
+
+describe('animation renderer factory', () => {
+ let eventLogs: string[] = [];
+ let rendererFactory: RendererFactory2|null = null;
+
+ function getAnimationLog(): MockAnimationPlayer[] {
+ return MockAnimationDriver.log as MockAnimationPlayer[];
+ }
+
+ beforeEach(() => {
+ eventLogs = [];
+ rendererFactory = null;
+ MockAnimationDriver.log = [];
+
+ TestBed.configureTestingModule({
+ declarations: [SomeComponentWithAnimation, SomeComponent],
+ providers: [{
+ provide: RendererFactory2,
+ useFactory: (d: any) => rendererFactory = getAnimationRendererFactory2(d),
+ deps: [DOCUMENT]
+ }]
+ });
+ });
+
+ @Component({
+ selector: 'some-component',
+ template: `
+
+ foo
+
+ `,
+ animations: [{
+ 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: {}
+ }]
+ })
+ class SomeComponentWithAnimation {
+ exp: string|undefined;
+
+ callback(event: AnimationEvent) {
+ eventLogs.push(`${event.fromState ? event.fromState : event.toState} - ${event.phaseName}`);
+ }
+ }
+
+ @Component({selector: 'some-component', template: 'foo'})
+ class SomeComponent {
+ }
+
+ it('should work with components without animations', () => {
+ const fixture = TestBed.createComponent(SomeComponent);
+ fixture.detectChanges();
+ expect(fixture.nativeElement.innerHTML).toEqual('foo');
+ });
+
+ isBrowser && it('should work with animated components', (done) => {
+ const fixture = TestBed.createComponent(SomeComponentWithAnimation);
+ fixture.detectChanges();
+
+ expect(rendererFactory).toBeTruthy();
+ expect(fixture.nativeElement.innerHTML)
+ .toMatch(/\s+foo\s+<\/div>/);
+
+ fixture.componentInstance.exp = 'on';
+ fixture.detectChanges();
+
+ const [player] = getAnimationLog();
+ expect(player.keyframes).toEqual([
+ {opacity: '*', offset: 0},
+ {opacity: 1, offset: 1},
+ ]);
+ player.finish();
+
+ rendererFactory !.whenRenderingDone !().then(() => {
+ expect(eventLogs).toEqual(['void - start', 'void - done', 'on - start', 'on - done']);
+ done();
+ });
+ });
+});
+
+function getRendererFactory2(document: any): RendererFactory2 {
+ const fakeNgZone: NgZone = new NoopNgZone();
+ const eventManager = new EventManager([], fakeNgZone);
+ const rendererFactory = new ServerRendererFactory2(
+ eventManager, fakeNgZone, document, new ɵDomSharedStylesHost(document));
+ const origCreateRenderer = rendererFactory.createRenderer;
+ rendererFactory.createRenderer = function() {
+ const renderer = origCreateRenderer.apply(this, arguments);
+ renderer.destroyNode = () => {};
+ return renderer;
+ };
+ return rendererFactory;
+}
+
+function getAnimationRendererFactory2(document: any): RendererFactory2 {
+ const fakeNgZone: NgZone = new NoopNgZone();
+ return new ɵAnimationRendererFactory(
+ getRendererFactory2(document),
+ new ɵAnimationEngine(
+ document.body, new MockAnimationDriver(), new ɵNoopAnimationStyleNormalizer()),
+ fakeNgZone);
+}
diff --git a/packages/core/test/render3/renderer_factory_spec.ts b/packages/core/test/render3/renderer_factory_spec.ts
index 4d3952b83c..1e7473bdbd 100644
--- a/packages/core/test/render3/renderer_factory_spec.ts
+++ b/packages/core/test/render3/renderer_factory_spec.ts
@@ -6,16 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {AnimationEvent} from '@angular/animations';
-import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
-
import {RendererType2, ViewEncapsulation} from '../../src/core';
import {ɵɵdefineComponent} from '../../src/render3/index';
-import {tick, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵlistener, ɵɵtext} from '../../src/render3/instructions/all';
+import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵtext} from '../../src/render3/instructions/all';
import {RenderFlags} from '../../src/render3/interfaces/definition';
-import {getAnimationRendererFactory2, getRendererFactory2} from './imported_renderer2';
-import {TemplateFixture, containerEl, document, renderComponent, renderToHtml, toHtml} from './render_util';
+import {getRendererFactory2} from './imported_renderer2';
+import {TemplateFixture, document, renderToHtml} from './render_util';
describe('renderer factory lifecycle', () => {
let logs: string[] = [];
@@ -87,21 +84,6 @@ describe('renderer factory lifecycle', () => {
beforeEach(() => { logs = []; });
- it('should work with a component', () => {
- const component = renderComponent(SomeComponent, {rendererFactory});
- expect(logs).toEqual(
- ['create', 'create', 'begin', 'component create', 'component update', 'end']);
-
- logs = [];
- tick(component);
- expect(logs).toEqual(['begin', 'component update', 'end']);
- });
-
- it('should work with a component which throws', () => {
- expect(() => renderComponent(SomeComponentWhichThrows, {rendererFactory})).toThrow();
- expect(logs).toEqual(['create', 'create', 'begin', 'end']);
- });
-
it('should work with a template', () => {
renderToHtml(Template, {}, 1, 0, null, null, rendererFactory);
expect(logs).toEqual(['create', 'function create', 'function update']);
@@ -125,108 +107,6 @@ 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,
- encapsulation: ViewEncapsulation.None,
- selectors: [['some-component']],
- consts: 1,
- vars: 0,
- template: function(rf: RenderFlags, ctx: SomeComponent) {
- if (rf & RenderFlags.Create) {
- ɵɵtext(0, 'foo');
- }
- },
- factory: () => new SomeComponent
- });
- }
-
- class SomeComponentWithAnimation {
- // TODO(issue/24571): remove '!'.
- exp !: string;
- callback(event: AnimationEvent) {
- eventLogs.push(`${event.fromState ? event.fromState : event.toState} - ${event.phaseName}`);
- }
- static ngComponentDef = ɵɵdefineComponent({
- type: SomeComponentWithAnimation,
- selectors: [['some-component']],
- consts: 2,
- vars: 1,
- template: function(rf: RenderFlags, ctx: SomeComponentWithAnimation) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- {
- ɵɵlistener('@myAnimation.start', ctx.callback.bind(ctx));
- ɵɵlistener('@myAnimation.done', ctx.callback.bind(ctx));
- ɵɵtext(1, 'foo');
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, '@myAnimation', ɵɵbind(ctx.exp));
- }
- },
- factory: () => new SomeComponentWithAnimation,
- 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, {rendererFactory: getAnimationRendererFactory2(document)});
- expect(toHtml(containerEl)).toEqual('foo');
- });
-
- isBrowser && it('should work with animated components', (done) => {
- const rendererFactory = getAnimationRendererFactory2(document);
- const component = renderComponent(SomeComponentWithAnimation, {rendererFactory});
- expect(toHtml(containerEl))
- .toMatch(/
foo<\/div>/);
-
- component.exp = 'on';
- tick(component);
-
- const [player] = getLog();
- expect(player.keyframes).toEqual([
- {opacity: '*', offset: 0},
- {opacity: 1, offset: 1},
- ]);
- player.finish();
-
- rendererFactory.whenRenderingDone !().then(() => {
- expect(eventLogs).toEqual(['void - start', 'void - done', 'on - start', 'on - done']);
- done();
- });
- });
-});
-
describe('Renderer2 destruction hooks', () => {
const rendererFactory = getRendererFactory2(document);