fix: make all tests green with new view engine and JIT

Note that this does not yet include enabling the view engine
by default.

Included refactoring:
- view engine: split namespace of elements / attributes already
  when creating the `NodeDef`
- view engine: when injecting the old `Renderer`, use an implementation
  that is based on `RendererV2`
- view engine: store view queries in the component view, not
  on the host element
This commit is contained in:
Tobias Bosch
2017-02-17 08:56:36 -08:00
committed by Igor Minar
parent 74ce121dba
commit b9f17a9cb2
37 changed files with 527 additions and 300 deletions

View File

@ -10,6 +10,7 @@ import {APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, CompilerFactory, Component, NgM
import {ApplicationRef, ApplicationRef_} from '@angular/core/src/application_ref';
import {ErrorHandler} from '@angular/core/src/error_handler';
import {ComponentRef} from '@angular/core/src/linker/component_factory';
import {TestComponentRenderer} from '@angular/core/testing';
import {BrowserModule} from '@angular/platform-browser';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens';
@ -19,21 +20,26 @@ import {ServerModule} from '@angular/platform-server';
import {ComponentFixture, ComponentFixtureNoNgZone, TestBed, async, inject, withModule} from '../testing';
@Component({selector: 'comp', template: 'hello'})
@Component({selector: 'bootstrap-app', template: 'hello'})
class SomeComponent {
}
export function main() {
describe('bootstrap', () => {
let mockConsole: MockConsole;
let fakeDoc: Document;
beforeEach(() => {
fakeDoc = getDOM().createHtmlDocument();
const el = getDOM().createElement('comp', fakeDoc);
getDOM().appendChild(fakeDoc.body, el);
mockConsole = new MockConsole();
});
beforeEach(() => { mockConsole = new MockConsole(); });
function createRootEl() {
const doc = TestBed.get(DOCUMENT);
const rootEl = <HTMLElement>getDOM().firstChild(
getDOM().content(getDOM().createTemplate(`<bootstrap-app></bootstrap-app>`)));
const oldRoots = getDOM().querySelectorAll(doc, 'bootstrap-app');
for (let i = 0; i < oldRoots.length; i++) {
getDOM().remove(oldRoots[i]);
}
getDOM().appendChild(doc.body, rootEl);
}
type CreateModuleOptions = {providers?: any[], ngDoBootstrap?: any, bootstrap?: any[]};
@ -52,10 +58,7 @@ export function main() {
const platformModule = getDOM().supportsDOMEvents() ? BrowserModule : ServerModule;
@NgModule({
providers: [
{provide: ErrorHandler, useValue: errorHandler}, {provide: DOCUMENT, useValue: fakeDoc},
options.providers || []
],
providers: [{provide: ErrorHandler, useValue: errorHandler}, options.providers || []],
imports: [platformModule],
declarations: [SomeComponent],
entryComponents: [SomeComponent],
@ -74,7 +77,8 @@ export function main() {
it('should throw when reentering tick', inject([ApplicationRef], (ref: ApplicationRef_) => {
const view = jasmine.createSpyObj('view', ['detach', 'attachToAppRef']);
const viewRef = jasmine.createSpyObj('viewRef', ['detectChanges']);
const viewRef = jasmine.createSpyObj(
'viewRef', ['detectChanges', 'detachFromContainer', 'attachToAppRef']);
viewRef.internalView = view;
view.ref = viewRef;
try {
@ -101,16 +105,13 @@ export function main() {
it('should be called when a component is bootstrapped',
inject([ApplicationRef], (ref: ApplicationRef_) => {
createRootEl();
const compRef = ref.bootstrap(SomeComponent);
expect(capturedCompRefs).toEqual([compRef]);
}));
});
describe('bootstrap', () => {
beforeEach(
() => {
});
it('should throw if an APP_INITIIALIZER is not yet resolved',
withModule(
{
@ -119,6 +120,7 @@ export function main() {
]
},
inject([ApplicationRef], (ref: ApplicationRef_) => {
createRootEl();
expect(() => ref.bootstrap(SomeComponent))
.toThrowError(
'Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
@ -128,8 +130,10 @@ export function main() {
describe('bootstrapModule', () => {
let defaultPlatform: PlatformRef;
beforeEach(
inject([PlatformRef], (_platform: PlatformRef) => { defaultPlatform = _platform; }));
beforeEach(inject([PlatformRef], (_platform: PlatformRef) => {
createRootEl();
defaultPlatform = _platform;
}));
it('should wait for asynchronous app initializers', async(() => {
let resolve: (result: any) => void;
@ -221,8 +225,10 @@ export function main() {
describe('bootstrapModuleFactory', () => {
let defaultPlatform: PlatformRef;
beforeEach(
inject([PlatformRef], (_platform: PlatformRef) => { defaultPlatform = _platform; }));
beforeEach(inject([PlatformRef], (_platform: PlatformRef) => {
createRootEl();
defaultPlatform = _platform;
}));
it('should wait for asynchronous app initializers', async(() => {
let resolve: (result: any) => void;
const promise: Promise<any> = new Promise((res) => { resolve = res; });
@ -346,7 +352,7 @@ export function main() {
it('should not allow to attach a view to both, a view container and the ApplicationRef',
() => {
const comp = TestBed.createComponent(MyComp);
const hostView = comp.componentRef.hostView;
let hostView = comp.componentRef.hostView;
const containerComp = TestBed.createComponent(ContainerComp);
containerComp.detectChanges();
const vc = containerComp.componentInstance.vc;
@ -355,7 +361,7 @@ export function main() {
vc.insert(hostView);
expect(() => appRef.attachView(hostView))
.toThrowError('This view is already attached to a ViewContainer!');
vc.detach(0);
hostView = vc.detach(0);
appRef.attachView(hostView);
expect(() => vc.insert(hostView))

View File

@ -9,7 +9,6 @@
import {AfterContentInit, AfterViewInit, Component, ContentChildren, Directive, Input, QueryList, ViewChildren} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {beforeEach, describe, it} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/matchers';

View File

@ -8,7 +8,6 @@
import {Component, Directive, HostBinding, Input, NO_ERRORS_SCHEMA} from '@angular/core';
import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing';
import {afterEach, beforeEach, describe, expect, iit, it} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service';

View File

@ -82,7 +82,7 @@ export function main() {
it('should set attributes on the root node', () => {
const view = createRootView(
compViewDef([
elementDef(NodeFlags.None, null, null, 0, 'div', {'a': 'b'}),
elementDef(NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
]),
{}, [], rootNode);
expect(rootNode.getAttribute('a')).toBe('b');
@ -92,7 +92,7 @@ export function main() {
rootNode.appendChild(document.createElement('div'));
const view = createRootView(
compViewDef([
elementDef(NodeFlags.None, null, null, 0, 'div', {'a': 'b'}),
elementDef(NodeFlags.None, null, null, 0, 'div', [['a', 'b']]),
]),
{}, [], rootNode);
expect(rootNode.childNodes.length).toBe(0);

View File

@ -57,7 +57,7 @@ export function main() {
it('should set fixed attributes', () => {
const rootNodes = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 0, 'div', {'title': 'a'}),
elementDef(NodeFlags.None, null, null, 0, 'div', [['title', 'a']]),
])).rootNodes;
expect(rootNodes.length).toBe(1);
expect(getDOM().getAttribute(rootNodes[0], 'title')).toBe('a');

View File

@ -55,10 +55,10 @@ export function main() {
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 2, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child0'})
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child1'})
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
]))
]));
const viewContainerData = asElementData(parentView, 1);
@ -85,10 +85,10 @@ export function main() {
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 2, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child0'})
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child1'})
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
]))
]));
const viewContainerData = asElementData(parentView, 1);
@ -112,9 +112,9 @@ export function main() {
it('should include embedded views in root nodes', () => {
const {view: parentView} = createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'child0'})
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
elementDef(NodeFlags.None, null, null, 0, 'span', {'name': 'after'})
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'after']])
]));
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[0]);

View File

@ -50,12 +50,16 @@ export function main() {
];
}
function viewQueryProviders(compView: ViewDefinition) {
function viewQueryProviders(nodes: NodeDef[]) {
return [
directiveDef(NodeFlags.None, null, 1, QueryService, [], null, null, () => compView),
queryDef(
NodeFlags.HasViewQuery | NodeFlags.HasDynamicQuery, someQueryId,
{'a': QueryBindingType.All})
directiveDef(
NodeFlags.None, null, 0, QueryService, [], null, null,
() => compViewDef([
queryDef(
NodeFlags.HasViewQuery | NodeFlags.HasDynamicQuery, someQueryId,
{'a': QueryBindingType.All}),
...nodes
])),
];
}
@ -106,11 +110,11 @@ export function main() {
describe('view queries', () => {
it('should query providers in the view', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 2, 'div'),
...viewQueryProviders(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
...viewQueryProviders([
elementDef(NodeFlags.None, null, null, 1, 'span'),
aServiceProvider(),
])),
]),
]));
Services.checkAndUpdateView(view);
@ -118,15 +122,15 @@ export function main() {
const comp: QueryService = asProviderData(view, 1).instance;
const compView = asProviderData(view, 1).componentView;
expect(comp.a.length).toBe(1);
expect(comp.a.first).toBe(asProviderData(compView, 1).instance);
expect(comp.a.first).toBe(asProviderData(compView, 2).instance);
});
it('should not query providers on the host element', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 3, 'div'),
...viewQueryProviders(compViewDef([
elementDef(NodeFlags.None, null, null, 2, 'div'),
...viewQueryProviders([
elementDef(NodeFlags.None, null, null, 0, 'span'),
])),
]),
aServiceProvider(),
]));
@ -221,13 +225,13 @@ export function main() {
it('should update view queries if embedded views are added or removed', () => {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 2, 'div'),
...viewQueryProviders(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
...viewQueryProviders([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(),
])),
])),
]),
]));
Services.checkAndUpdateView(view);
@ -236,13 +240,13 @@ export function main() {
expect(comp.a.length).toBe(0);
const compView = asProviderData(view, 1).componentView;
const childView = Services.createEmbeddedView(compView, compView.def.nodes[0]);
attachEmbeddedView(asElementData(compView, 0), 0, childView);
const childView = Services.createEmbeddedView(compView, compView.def.nodes[1]);
attachEmbeddedView(asElementData(compView, 1), 0, childView);
Services.checkAndUpdateView(view);
expect(comp.a.length).toBe(1);
detachEmbeddedView(asElementData(compView, 0), 0);
detachEmbeddedView(asElementData(compView, 1), 0);
Services.checkAndUpdateView(view);
expect(comp.a.length).toBe(0);