
committed by
Alex Rickabaugh

parent
f20d1a8af5
commit
0adb97bffb
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
|
||||
import {DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
||||
@ -34,8 +34,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
new RenderComponentType('1', 'someUrl', 0, ViewEncapsulation.None, [], {});
|
||||
}));
|
||||
|
||||
function compViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater, renderComponentType);
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], update?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update, handleEvent, renderComponentType);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, destroyView, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, destroyView, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
||||
@ -34,8 +34,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
new RenderComponentType('1', 'someUrl', 0, ViewEncapsulation.None, [], {});
|
||||
}));
|
||||
|
||||
function compViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater, renderComponentType);
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], update?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update, handleEvent, renderComponentType);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
|
||||
@ -45,56 +46,57 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
}
|
||||
|
||||
it('should create and attach component views', () => {
|
||||
class AComp {}
|
||||
let instance: AComp;
|
||||
class AComp {
|
||||
constructor() { instance = this; }
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
providerDef(NodeFlags.None, AComp, [], null, () => compViewDef([
|
||||
elementDef(NodeFlags.None, 0, 'span'),
|
||||
])),
|
||||
providerDef(NodeFlags.None, AComp, [], null, null, () => compViewDef([
|
||||
elementDef(NodeFlags.None, 0, 'span'),
|
||||
])),
|
||||
]));
|
||||
|
||||
const compView = view.nodes[1].componentView;
|
||||
|
||||
expect(compView.context).toBe(instance);
|
||||
expect(compView.component).toBe(instance);
|
||||
|
||||
const compRootEl = getDOM().childNodes(rootNodes[0])[0];
|
||||
expect(getDOM().nodeName(compRootEl).toLowerCase()).toBe('span');
|
||||
});
|
||||
|
||||
it('should dirty check component views', () => {
|
||||
let value = 'v1';
|
||||
let instance: AComp;
|
||||
class AComp {
|
||||
a: any;
|
||||
constructor() { instance = this; }
|
||||
}
|
||||
|
||||
const updater = jasmine.createSpy('updater').and.callFake(
|
||||
const update = jasmine.createSpy('updater').and.callFake(
|
||||
(updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, value));
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
providerDef(NodeFlags.None, AComp, [], null, () => compViewDef(
|
||||
providerDef(NodeFlags.None, AComp, [], null, null, () => compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 0, 'span', null, [[BindingType.ElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
], updater
|
||||
], update
|
||||
)),
|
||||
], jasmine.createSpy('parentUpdater')));
|
||||
const compView = view.nodes[1].componentView;
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
expect(updater).toHaveBeenCalled();
|
||||
// component
|
||||
expect(updater.calls.mostRecent().args[2]).toBe(instance);
|
||||
// view context
|
||||
expect(updater.calls.mostRecent().args[3]).toBe(instance);
|
||||
expect(update).toHaveBeenCalled();
|
||||
expect(update.calls.mostRecent().args[1]).toBe(compView);
|
||||
|
||||
updater.calls.reset();
|
||||
update.calls.reset();
|
||||
checkNoChangesView(view);
|
||||
|
||||
expect(updater).toHaveBeenCalled();
|
||||
// component
|
||||
expect(updater.calls.mostRecent().args[2]).toBe(instance);
|
||||
// view context
|
||||
expect(updater.calls.mostRecent().args[3]).toBe(instance);
|
||||
expect(update).toHaveBeenCalled();
|
||||
expect(update.calls.mostRecent().args[1]).toBe(compView);
|
||||
|
||||
value = 'v2';
|
||||
expect(() => checkNoChangesView(view))
|
||||
@ -114,10 +116,11 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, AComp, [], null, () => compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.OnDestroy, ChildProvider, [])
|
||||
])),
|
||||
NodeFlags.None, AComp, [], null, null,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.OnDestroy, ChildProvider, [])
|
||||
])),
|
||||
]));
|
||||
|
||||
destroyView(view);
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, destroyView, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
||||
@ -34,8 +34,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
new RenderComponentType('1', 'someUrl', 0, ViewEncapsulation.None, [], {});
|
||||
}));
|
||||
|
||||
function compViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater, renderComponentType);
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], update?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update, handleEvent, renderComponentType);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
|
||||
@ -101,12 +102,12 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
describe('change properties', () => {
|
||||
[{
|
||||
name: 'inline',
|
||||
updater: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 'v1', 'v2')
|
||||
update: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 'v1', 'v2')
|
||||
},
|
||||
{
|
||||
name: 'dynamic',
|
||||
updater: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, ['v1', 'v2'])
|
||||
update: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, ['v1', 'v2'])
|
||||
}].forEach((config) => {
|
||||
it(`should update ${config.name}`, () => {
|
||||
|
||||
@ -119,7 +120,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
[BindingType.ElementProperty, 'value', SecurityContext.NONE]
|
||||
]),
|
||||
],
|
||||
config.updater));
|
||||
config.update));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
@ -133,12 +134,12 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
describe('change attributes', () => {
|
||||
[{
|
||||
name: 'inline',
|
||||
updater: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 'v1', 'v2')
|
||||
update: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 'v1', 'v2')
|
||||
},
|
||||
{
|
||||
name: 'dynamic',
|
||||
updater: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, ['v1', 'v2'])
|
||||
update: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, ['v1', 'v2'])
|
||||
}].forEach((config) => {
|
||||
it(`should update ${config.name}`, () => {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
@ -150,7 +151,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
[BindingType.ElementAttribute, 'a2', SecurityContext.NONE]
|
||||
]),
|
||||
],
|
||||
config.updater));
|
||||
config.update));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
@ -192,12 +193,12 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
describe('change styles', () => {
|
||||
[{
|
||||
name: 'inline',
|
||||
updater: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 10, 'red')
|
||||
update: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 10, 'red')
|
||||
},
|
||||
{
|
||||
name: 'dynamic',
|
||||
updater: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, [10, 'red'])
|
||||
update: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, [10, 'red'])
|
||||
}].forEach((config) => {
|
||||
it(`should update ${config.name}`, () => {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
@ -209,7 +210,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
[BindingType.ElementStyle, 'color', null]
|
||||
]),
|
||||
],
|
||||
config.updater));
|
||||
config.update));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
@ -219,5 +220,131 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (getDOM().supportsDOMEvents()) {
|
||||
describe('listen to DOM events', () => {
|
||||
let removeNodes: Node[];
|
||||
beforeEach(() => { removeNodes = []; });
|
||||
afterEach(() => {
|
||||
removeNodes.forEach((node) => {
|
||||
if (node.parentNode) {
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function createAndAttachAndGetRootNodes(viewDef: ViewDefinition):
|
||||
{rootNodes: any[], view: ViewData} {
|
||||
const result = createAndGetRootNodes(viewDef);
|
||||
// Note: We need to append the node to the document.body, otherwise `click` events
|
||||
// won't work in IE.
|
||||
result.rootNodes.forEach((node) => {
|
||||
document.body.appendChild(node);
|
||||
removeNodes.push(node);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
it('should listen to DOM events', () => {
|
||||
const handleEventSpy = jasmine.createSpy('handleEvent');
|
||||
const removeListenerSpy =
|
||||
spyOn(HTMLElement.prototype, 'removeEventListener').and.callThrough();
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(NodeFlags.None, 0, 'button', null, null, ['click'])], null,
|
||||
handleEventSpy));
|
||||
|
||||
rootNodes[0].click();
|
||||
|
||||
expect(handleEventSpy).toHaveBeenCalled();
|
||||
let handleEventArgs = handleEventSpy.calls.mostRecent().args;
|
||||
expect(handleEventArgs[0]).toBe(view);
|
||||
expect(handleEventArgs[1]).toBe(0);
|
||||
expect(handleEventArgs[2]).toBe('click');
|
||||
expect(handleEventArgs[3]).toBeTruthy();
|
||||
|
||||
destroyView(view);
|
||||
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should listen to window events', () => {
|
||||
const handleEventSpy = jasmine.createSpy('handleEvent');
|
||||
const addListenerSpy = spyOn(window, 'addEventListener');
|
||||
const removeListenerSpy = spyOn(window, 'removeEventListener');
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(NodeFlags.None, 0, 'button', null, null, [['window', 'windowClick']])],
|
||||
null, handleEventSpy));
|
||||
|
||||
expect(addListenerSpy).toHaveBeenCalled();
|
||||
expect(addListenerSpy.calls.mostRecent().args[0]).toBe('windowClick');
|
||||
addListenerSpy.calls.mostRecent().args[1]({name: 'windowClick'});
|
||||
|
||||
expect(handleEventSpy).toHaveBeenCalled();
|
||||
const handleEventArgs = handleEventSpy.calls.mostRecent().args;
|
||||
expect(handleEventArgs[0]).toBe(view);
|
||||
expect(handleEventArgs[1]).toBe(0);
|
||||
expect(handleEventArgs[2]).toBe('windowClick');
|
||||
expect(handleEventArgs[3]).toBeTruthy();
|
||||
|
||||
destroyView(view);
|
||||
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should listen to document events', () => {
|
||||
const handleEventSpy = jasmine.createSpy('handleEvent');
|
||||
const addListenerSpy = spyOn(document, 'addEventListener');
|
||||
const removeListenerSpy = spyOn(document, 'removeEventListener');
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(
|
||||
NodeFlags.None, 0, 'button', null, null, [['document', 'documentClick']])],
|
||||
null, handleEventSpy));
|
||||
|
||||
expect(addListenerSpy).toHaveBeenCalled();
|
||||
expect(addListenerSpy.calls.mostRecent().args[0]).toBe('documentClick');
|
||||
addListenerSpy.calls.mostRecent().args[1]({name: 'documentClick'});
|
||||
|
||||
expect(handleEventSpy).toHaveBeenCalled();
|
||||
const handleEventArgs = handleEventSpy.calls.mostRecent().args;
|
||||
expect(handleEventArgs[0]).toBe(view);
|
||||
expect(handleEventArgs[1]).toBe(0);
|
||||
expect(handleEventArgs[2]).toBe('documentClick');
|
||||
expect(handleEventArgs[3]).toBeTruthy();
|
||||
|
||||
destroyView(view);
|
||||
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should preventDefault only if the handler returns false', () => {
|
||||
let eventHandlerResult: any;
|
||||
let preventDefaultSpy: jasmine.Spy;
|
||||
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(NodeFlags.None, 0, 'button', null, null, ['click'])], null,
|
||||
(view, index, eventName, event) => {
|
||||
preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();
|
||||
return eventHandlerResult;
|
||||
}));
|
||||
|
||||
eventHandlerResult = undefined;
|
||||
rootNodes[0].click();
|
||||
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
||||
|
||||
eventHandlerResult = true;
|
||||
rootNodes[0].click();
|
||||
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
||||
|
||||
eventHandlerResult = 'someString';
|
||||
rootNodes[0].click();
|
||||
expect(preventDefaultSpy).not.toHaveBeenCalled();
|
||||
|
||||
eventHandlerResult = false;
|
||||
rootNodes[0].click();
|
||||
expect(preventDefaultSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, anchorDef, attachEmbeddedView, checkAndUpdateView, checkNoChangesView, createEmbeddedView, createRootView, destroyView, detachEmbeddedView, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, attachEmbeddedView, checkAndUpdateView, checkNoChangesView, createEmbeddedView, createRootView, destroyView, detachEmbeddedView, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
||||
@ -34,12 +34,13 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
new RenderComponentType('1', 'someUrl', 0, ViewEncapsulation.None, [], {});
|
||||
}));
|
||||
|
||||
function compViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater, renderComponentType);
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], update?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update, handleEvent, renderComponentType);
|
||||
}
|
||||
|
||||
function embeddedViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater);
|
||||
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(
|
||||
@ -49,6 +50,23 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
return {rootNodes, view};
|
||||
}
|
||||
|
||||
it('should create embedded views with the right context', () => {
|
||||
const parentContext = new Object();
|
||||
const childContext = new Object();
|
||||
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, 2, 'div'),
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, 0, embeddedViewDef([elementDef(
|
||||
NodeFlags.None, 0, 'span')])),
|
||||
]),
|
||||
parentContext);
|
||||
|
||||
const childView = createEmbeddedView(parentView, parentView.def.nodes[1], childContext);
|
||||
expect(childView.component).toBe(parentContext);
|
||||
expect(childView.context).toBe(childContext);
|
||||
});
|
||||
|
||||
it('should attach and detach embedded views', () => {
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 2, 'div'),
|
||||
@ -97,45 +115,35 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should dirty check embedded views', () => {
|
||||
let childValue = 'v1';
|
||||
const parentContext = new Object();
|
||||
const childContext = new Object();
|
||||
const updater = jasmine.createSpy('updater').and.callFake(
|
||||
const update = jasmine.createSpy('updater').and.callFake(
|
||||
(updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, childValue));
|
||||
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, 0,
|
||||
embeddedViewDef(
|
||||
[elementDef(
|
||||
NodeFlags.None, 0, 'span', null,
|
||||
[[BindingType.ElementAttribute, 'name', SecurityContext.NONE]])],
|
||||
updater))
|
||||
]),
|
||||
parentContext);
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, 0,
|
||||
embeddedViewDef(
|
||||
[elementDef(
|
||||
NodeFlags.None, 0, 'span', null,
|
||||
[[BindingType.ElementAttribute, 'name', SecurityContext.NONE]])],
|
||||
update))
|
||||
]));
|
||||
|
||||
const childView0 = createEmbeddedView(parentView, parentView.def.nodes[1], childContext);
|
||||
const childView0 = createEmbeddedView(parentView, parentView.def.nodes[1]);
|
||||
|
||||
const rootEl = rootNodes[0];
|
||||
attachEmbeddedView(parentView.nodes[1], 0, childView0);
|
||||
|
||||
checkAndUpdateView(parentView);
|
||||
|
||||
expect(updater).toHaveBeenCalled();
|
||||
// component
|
||||
expect(updater.calls.mostRecent().args[2]).toBe(parentContext);
|
||||
// view context
|
||||
expect(updater.calls.mostRecent().args[3]).toBe(childContext);
|
||||
expect(update).toHaveBeenCalled();
|
||||
expect(update.calls.mostRecent().args[1]).toBe(childView0);
|
||||
|
||||
updater.calls.reset();
|
||||
update.calls.reset();
|
||||
checkNoChangesView(parentView);
|
||||
|
||||
expect(updater).toHaveBeenCalled();
|
||||
// component
|
||||
expect(updater.calls.mostRecent().args[2]).toBe(parentContext);
|
||||
// view context
|
||||
expect(updater.calls.mostRecent().args[3]).toBe(childContext);
|
||||
expect(update).toHaveBeenCalled();
|
||||
expect(update.calls.mostRecent().args[1]).toBe(childView0);
|
||||
|
||||
childValue = 'v2';
|
||||
expect(() => checkNoChangesView(parentView))
|
||||
|
@ -6,8 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, ElementRef, OnChanges, OnDestroy, OnInit, RenderComponentType, Renderer, RootRenderer, Sanitizer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, destroyView, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, ElementRef, EventEmitter, OnChanges, OnDestroy, OnInit, RenderComponentType, Renderer, RootRenderer, Sanitizer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, destroyView, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
||||
@ -34,12 +34,13 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
new RenderComponentType('1', 'someUrl', 0, ViewEncapsulation.None, [], {});
|
||||
}));
|
||||
|
||||
function compViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater, renderComponentType);
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], update?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update, handleEvent, renderComponentType);
|
||||
}
|
||||
|
||||
function embeddedViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater);
|
||||
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
|
||||
@ -110,10 +111,11 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, Dep, [], null, () => compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [Dep])
|
||||
])),
|
||||
NodeFlags.None, Dep, [], null, null,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [Dep])
|
||||
])),
|
||||
]));
|
||||
|
||||
expect(instance.dep instanceof Dep).toBeTruthy();
|
||||
@ -173,12 +175,12 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
describe('data binding', () => {
|
||||
[{
|
||||
name: 'inline',
|
||||
updater: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 1, 'v1', 'v2')
|
||||
update: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 1, 'v1', 'v2')
|
||||
},
|
||||
{
|
||||
name: 'dynamic',
|
||||
updater: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 1, ['v1', 'v2'])
|
||||
update: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 1, ['v1', 'v2'])
|
||||
}].forEach((config) => {
|
||||
it(`should update ${config.name}`, () => {
|
||||
let instance: SomeService;
|
||||
@ -194,7 +196,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [], {a: [0, 'a'], b: [1, 'b']})
|
||||
],
|
||||
config.updater));
|
||||
config.update));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
@ -226,6 +228,39 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
});
|
||||
});
|
||||
|
||||
describe('outputs', () => {
|
||||
it('should listen to provider events', () => {
|
||||
let emitter = new EventEmitter<any>();
|
||||
let unsubscribeSpy: any;
|
||||
|
||||
class SomeService {
|
||||
emitter = {
|
||||
subscribe: (callback: any) => {
|
||||
const subscription = emitter.subscribe(callback);
|
||||
unsubscribeSpy = spyOn(subscription, 'unsubscribe').and.callThrough();
|
||||
return subscription;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const handleEvent = jasmine.createSpy('handleEvent');
|
||||
const subscribe = spyOn(emitter, 'subscribe').and.callThrough();
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [], null, {emitter: 'someEventName'})
|
||||
],
|
||||
null, handleEvent));
|
||||
|
||||
emitter.emit('someEventInstance');
|
||||
expect(handleEvent).toHaveBeenCalledWith(view, 0, 'someEventName', 'someEventInstance');
|
||||
|
||||
destroyView(view);
|
||||
expect(unsubscribeSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('lifecycle hooks', () => {
|
||||
it('should call the lifecycle hooks in the right order', () => {
|
||||
let instanceCount = 0;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core';
|
||||
import {DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {DefaultServices, NodeDef, NodeFlags, NodeUpdater, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, checkAndUpdateView, checkNoChangesView, createRootView, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
||||
@ -34,8 +34,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
new RenderComponentType('1', 'someUrl', 0, ViewEncapsulation.None, [], {});
|
||||
}));
|
||||
|
||||
function compViewDef(nodes: NodeDef[], updater?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, updater, renderComponentType);
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], update?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
return viewDef(config.viewFlags, nodes, update, handleEvent, renderComponentType);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
|
||||
@ -88,19 +89,19 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
describe('change text', () => {
|
||||
[{
|
||||
name: 'inline',
|
||||
updater: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 'a', 'b')
|
||||
update: (updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, 'a', 'b')
|
||||
},
|
||||
{
|
||||
name: 'dynamic',
|
||||
updater: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, ['a', 'b'])
|
||||
update: (updater: NodeUpdater, view: ViewData) =>
|
||||
updater.checkDynamic(view, 0, ['a', 'b'])
|
||||
}].forEach((config) => {
|
||||
it(`should update ${config.name}`, () => {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
textDef(['0', '1', '2']),
|
||||
],
|
||||
config.updater));
|
||||
config.update));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
|
Reference in New Issue
Block a user