@ -6,8 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {T, b, defineComponent, markDirty, t} from '../../src/render3/index';
|
||||
import {ViewEncapsulation} from '../../src/core';
|
||||
import {D, E, T, b, defineComponent, e, markDirty, t} from '../../src/render3/index';
|
||||
import {createRendererType2} from '../../src/view';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
import {containerEl, renderComponent, requestAnimationFrame} from './render_util';
|
||||
|
||||
describe('component', () => {
|
||||
@ -60,3 +63,113 @@ describe('component', () => {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// TODO: add tests with Native once tests are run in real browser (domino doesn't support shadow
|
||||
// root)
|
||||
describe('encapsulation', () => {
|
||||
class WrapperComponent {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: WrapperComponent,
|
||||
tag: 'wrapper',
|
||||
template: function(ctx: WrapperComponent, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, EncapsulatedComponent.ngComponentDef);
|
||||
{ D(1, EncapsulatedComponent.ngComponentDef.n(), EncapsulatedComponent.ngComponentDef); }
|
||||
e();
|
||||
}
|
||||
EncapsulatedComponent.ngComponentDef.r(1, 0);
|
||||
},
|
||||
factory: () => new WrapperComponent,
|
||||
});
|
||||
}
|
||||
|
||||
class EncapsulatedComponent {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: EncapsulatedComponent,
|
||||
tag: 'encapsulated',
|
||||
template: function(ctx: EncapsulatedComponent, cm: boolean) {
|
||||
if (cm) {
|
||||
T(0, 'foo');
|
||||
E(1, LeafComponent.ngComponentDef);
|
||||
{ D(2, LeafComponent.ngComponentDef.n(), LeafComponent.ngComponentDef); }
|
||||
e();
|
||||
}
|
||||
LeafComponent.ngComponentDef.r(2, 1);
|
||||
},
|
||||
factory: () => new EncapsulatedComponent,
|
||||
rendererType:
|
||||
createRendererType2({encapsulation: ViewEncapsulation.Emulated, styles: [], data: {}}),
|
||||
});
|
||||
}
|
||||
|
||||
class LeafComponent {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: LeafComponent,
|
||||
tag: 'leaf',
|
||||
template: function(ctx: LeafComponent, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, 'span');
|
||||
{ T(1, 'bar'); }
|
||||
e();
|
||||
}
|
||||
},
|
||||
factory: () => new LeafComponent,
|
||||
});
|
||||
}
|
||||
|
||||
it('should encapsulate children, but not host nor grand children', () => {
|
||||
renderComponent(WrapperComponent, getRendererFactory2(document));
|
||||
expect(containerEl.outerHTML)
|
||||
.toEqual(
|
||||
'<div host=""><encapsulated _nghost-c0="">foo<leaf _ngcontent-c0=""><span>bar</span></leaf></encapsulated></div>');
|
||||
});
|
||||
|
||||
it('should encapsulate host', () => {
|
||||
renderComponent(EncapsulatedComponent, getRendererFactory2(document));
|
||||
expect(containerEl.outerHTML)
|
||||
.toEqual(
|
||||
'<div host="" _nghost-c0="">foo<leaf _ngcontent-c0=""><span>bar</span></leaf></div>');
|
||||
});
|
||||
|
||||
it('should encapsulate host and children with different attributes', () => {
|
||||
class WrapperComponentWith {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: WrapperComponent,
|
||||
tag: 'wrapper',
|
||||
template: function(ctx: WrapperComponentWith, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, LeafComponentwith.ngComponentDef);
|
||||
{ D(1, LeafComponentwith.ngComponentDef.n(), LeafComponentwith.ngComponentDef); }
|
||||
e();
|
||||
}
|
||||
LeafComponentwith.ngComponentDef.r(1, 0);
|
||||
},
|
||||
factory: () => new WrapperComponentWith,
|
||||
rendererType:
|
||||
createRendererType2({encapsulation: ViewEncapsulation.Emulated, styles: [], data: {}}),
|
||||
});
|
||||
}
|
||||
|
||||
class LeafComponentwith {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: LeafComponentwith,
|
||||
tag: 'leaf',
|
||||
template: function(ctx: LeafComponentwith, cm: boolean) {
|
||||
if (cm) {
|
||||
E(0, 'span');
|
||||
{ T(1, 'bar'); }
|
||||
e();
|
||||
}
|
||||
},
|
||||
factory: () => new LeafComponentwith,
|
||||
rendererType:
|
||||
createRendererType2({encapsulation: ViewEncapsulation.Emulated, styles: [], data: {}}),
|
||||
});
|
||||
}
|
||||
|
||||
renderComponent(WrapperComponentWith, getRendererFactory2(document));
|
||||
expect(containerEl.outerHTML)
|
||||
.toEqual(
|
||||
'<div host="" _nghost-c1=""><leaf _ngcontent-c1="" _nghost-c2=""><span _ngcontent-c2="">bar</span></leaf></div>');
|
||||
});
|
||||
});
|
||||
|
@ -6,10 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {EventEmitter, NgZone, Renderer2} from '@angular/core';
|
||||
import {EventEmitter, NgZone, RendererFactory2} from '@angular/core';
|
||||
import {EventManager, ɵDomEventsPlugin, ɵDomRendererFactory2, ɵDomSharedStylesHost} from '@angular/platform-browser';
|
||||
|
||||
|
||||
// Adapted renderer: it creates a Renderer2 instance and adapts it to Renderer3
|
||||
// TODO: remove once this code is in angular/angular
|
||||
export class NoopNgZone implements NgZone {
|
||||
@ -47,11 +46,9 @@ export class SimpleDomEventsPlugin extends ɵDomEventsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
export function getRenderer2(document: any): Renderer2 {
|
||||
export function getRendererFactory2(document: any): RendererFactory2 {
|
||||
const fakeNgZone: NgZone = new NoopNgZone();
|
||||
const eventManager =
|
||||
new EventManager([new SimpleDomEventsPlugin(document, fakeNgZone)], fakeNgZone);
|
||||
const rendererFactory2 =
|
||||
new ɵDomRendererFactory2(eventManager, new ɵDomSharedStylesHost(document));
|
||||
return rendererFactory2.createRenderer(null, null);
|
||||
return new ɵDomRendererFactory2(eventManager, new ɵDomSharedStylesHost(document));
|
||||
}
|
||||
|
@ -9,19 +9,17 @@
|
||||
import {ComponentTemplate, ComponentType, PublicFeature, defineComponent, renderComponent as _renderComponent} from '../../src/render3/index';
|
||||
import {NG_HOST_SYMBOL, createLNode, createViewState, renderTemplate} from '../../src/render3/instructions';
|
||||
import {LElement, LNodeFlags} from '../../src/render3/l_node';
|
||||
import {RElement, RText, Renderer3} from '../../src/render3/renderer';
|
||||
import {getRenderer2} from './imported_renderer2';
|
||||
import {RElement, RText, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/renderer';
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
|
||||
export const document = ((global || window) as any).document;
|
||||
export let containerEl: HTMLElement = null !;
|
||||
let host: LElement;
|
||||
let activeRenderer: Renderer3 =
|
||||
(typeof process !== 'undefined' && process.argv[3] && process.argv[3] === '--r=renderer2') ?
|
||||
getRenderer2(document) :
|
||||
document;
|
||||
let host: LElement|null;
|
||||
const isRenderer2 = process.argv[3] && process.argv[3] === '--r=renderer2';
|
||||
// tslint:disable-next-line:no-console
|
||||
console.log(
|
||||
`Running tests with ${activeRenderer === document ? 'document' : 'Renderer2'} renderer...`);
|
||||
console.log(`Running tests with ${!isRenderer2 ? 'document' : 'Renderer2'} renderer...`);
|
||||
const testRendererFactory: RendererFactory3 =
|
||||
isRenderer2 ? getRendererFactory2(document) : domRendererFactory3;
|
||||
|
||||
export const requestAnimationFrame:
|
||||
{(fn: () => void): void; flush(): void; queue: (() => void)[];} = function(fn: () => void) {
|
||||
@ -37,20 +35,22 @@ export function resetDOM() {
|
||||
requestAnimationFrame.queue = [];
|
||||
containerEl = document.createElement('div');
|
||||
containerEl.setAttribute('host', '');
|
||||
host = createLNode(
|
||||
null, LNodeFlags.Element, containerEl, createViewState(-1, activeRenderer, null !));
|
||||
host = null;
|
||||
// TODO: assert that the global state is clean (e.g. ngData, previousOrParentNode, etc)
|
||||
}
|
||||
|
||||
export function renderToHtml(template: ComponentTemplate<any>, ctx: any) {
|
||||
renderTemplate(host, template, ctx);
|
||||
return toHtml(host.native);
|
||||
export function renderToHtml(
|
||||
template: ComponentTemplate<any>, ctx: any, providedRendererFactory?: RendererFactory3) {
|
||||
host = renderTemplate(
|
||||
containerEl, template, ctx, providedRendererFactory || testRendererFactory, host);
|
||||
return toHtml(containerEl);
|
||||
}
|
||||
|
||||
beforeEach(resetDOM);
|
||||
|
||||
export function renderComponent<T>(type: ComponentType<T>): T {
|
||||
return _renderComponent(type, {renderer: activeRenderer, host: containerEl});
|
||||
export function renderComponent<T>(type: ComponentType<T>, rendererFactory?: RendererFactory3): T {
|
||||
return _renderComponent(
|
||||
type, {rendererFactory: rendererFactory || testRendererFactory, host: containerEl});
|
||||
}
|
||||
|
||||
export function toHtml<T>(componentOrElement: T | RElement): string {
|
||||
|
106
packages/core/test/render3/renderer_factory_spec.ts
Normal file
106
packages/core/test/render3/renderer_factory_spec.ts
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @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 {RendererType2} from '@angular/core';
|
||||
|
||||
import {D, E, e} from '../../src/render3';
|
||||
import {T, defineComponent, detectChanges} from '../../src/render3/index';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
import {document, renderComponent, renderToHtml, resetDOM} from './render_util';
|
||||
|
||||
describe('renderer factory lifecycle', () => {
|
||||
let logs: string[] = [];
|
||||
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');
|
||||
|
||||
class SomeComponent {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: SomeComponent,
|
||||
tag: 'some-component',
|
||||
template: function(ctx: SomeComponent, cm: boolean) {
|
||||
logs.push('component');
|
||||
if (cm) {
|
||||
T(0, 'foo');
|
||||
}
|
||||
},
|
||||
factory: () => new SomeComponent
|
||||
});
|
||||
}
|
||||
|
||||
class SomeComponentWhichThrows {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: SomeComponentWhichThrows,
|
||||
tag: 'some-component-with-Error',
|
||||
template: function(ctx: SomeComponentWhichThrows, cm: boolean) {
|
||||
throw(new Error('SomeComponentWhichThrows threw'));
|
||||
},
|
||||
factory: () => new SomeComponentWhichThrows
|
||||
});
|
||||
}
|
||||
|
||||
function Template(ctx: any, cm: boolean) {
|
||||
logs.push('function');
|
||||
if (cm) {
|
||||
T(0, 'bar');
|
||||
}
|
||||
}
|
||||
|
||||
function TemplateWithComponent(ctx: any, cm: boolean) {
|
||||
logs.push('function_with_component');
|
||||
if (cm) {
|
||||
T(0, 'bar');
|
||||
E(1, SomeComponent.ngComponentDef);
|
||||
{ D(2, SomeComponent.ngComponentDef.n(), SomeComponent.ngComponentDef); }
|
||||
e();
|
||||
}
|
||||
SomeComponent.ngComponentDef.r(2, 1);
|
||||
}
|
||||
|
||||
beforeEach(() => { logs = []; });
|
||||
|
||||
it('should work with a component', () => {
|
||||
const component = renderComponent(SomeComponent, rendererFactory);
|
||||
expect(logs).toEqual(['create', 'create', 'begin', 'component', 'end']);
|
||||
|
||||
logs = [];
|
||||
detectChanges(component);
|
||||
expect(logs).toEqual(['begin', 'component', '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, {}, rendererFactory);
|
||||
expect(logs).toEqual(['create', 'begin', 'function', 'end']);
|
||||
|
||||
logs = [];
|
||||
renderToHtml(Template, {});
|
||||
expect(logs).toEqual(['begin', 'function', 'end']);
|
||||
});
|
||||
|
||||
it('should work with a template which contains a component', () => {
|
||||
renderToHtml(TemplateWithComponent, {}, rendererFactory);
|
||||
expect(logs).toEqual(
|
||||
['create', 'begin', 'function_with_component', 'create', 'component', 'end']);
|
||||
|
||||
logs = [];
|
||||
renderToHtml(TemplateWithComponent, {});
|
||||
expect(logs).toEqual(['begin', 'function_with_component', 'component', 'end']);
|
||||
});
|
||||
|
||||
});
|
Reference in New Issue
Block a user