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:
@ -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))
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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');
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user