/**
* @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 {ApplicationRef, Compiler, Component, ComponentFactory, ComponentRef, Injector, NgModule, Testability, TestabilityRegistry} from '@angular/core';
import {TestBed, getTestBed, inject} from '@angular/core/testing';
import * as angular from '@angular/upgrade/src/common/angular1';
import {DowngradeComponentAdapter, groupNodesBySelector} from '@angular/upgrade/src/common/downgrade_component_adapter';
import {nodes, withEachNg1Version} from './test_helpers';
withEachNg1Version(() => {
describe('DowngradeComponentAdapter', () => {
describe('groupNodesBySelector', () => {
it('should return an array of node collections for each selector', () => {
const contentNodes = nodes(
'
div-1 content
' +
' ' +
' ' +
'span content ' +
'div-2 content
');
const selectors = ['input[type=date]', 'span', '.x'];
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
expect(projectableNodes[0]).toEqual(nodes(' '));
expect(projectableNodes[1]).toEqual(nodes('span content '));
expect(projectableNodes[2])
.toEqual(nodes(
'div-1 content
' +
'div-2 content
'));
});
it('should collect up unmatched nodes for the wildcard selector', () => {
const contentNodes = nodes(
'div-1 content
' +
' ' +
' ' +
'span content ' +
'div-2 content
');
const selectors = ['.x', '*', 'input[type=date]'];
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
expect(projectableNodes[0])
.toEqual(nodes(
'div-1 content
' +
'div-2 content
'));
expect(projectableNodes[1])
.toEqual(nodes(
' ' +
'span content '));
expect(projectableNodes[2]).toEqual(nodes(' '));
});
it('should return an array of empty arrays if there are no nodes passed in', () => {
const selectors = ['.x', '*', 'input[type=date]'];
const projectableNodes = groupNodesBySelector(selectors, []);
expect(projectableNodes).toEqual([[], [], []]);
});
it('should return an empty array for each selector that does not match', () => {
const contentNodes = nodes(
'div-1 content
' +
' ' +
' ' +
'span content ' +
'div-2 content
');
const projectableNodes = groupNodesBySelector([], contentNodes);
expect(projectableNodes).toEqual([]);
const noMatchSelectorNodes = groupNodesBySelector(['.not-there'], contentNodes);
expect(noMatchSelectorNodes).toEqual([[]]);
});
});
describe('testability', () => {
let adapter: DowngradeComponentAdapter;
let content: string;
let compiler: Compiler;
let element: angular.IAugmentedJQuery;
class mockScope implements angular.IScope {
private destroyListeners: (() => void)[] = [];
$new() { return this; }
$watch(exp: angular.Ng1Expression, fn?: (a1?: any, a2?: any) => void) {
return () => {};
}
$on(event: string, fn?: (event?: any, ...args: any[]) => void) {
if (event === '$destroy' && fn) {
this.destroyListeners.push(fn);
}
return () => {};
}
$destroy() {
let listener: (() => void)|undefined;
while ((listener = this.destroyListeners.shift())) listener();
}
$apply(exp?: angular.Ng1Expression) {
return () => {};
}
$digest() {
return () => {};
}
$evalAsync(exp: angular.Ng1Expression, locals?: any) {
return () => {};
}
$$childTail: angular.IScope;
$$childHead: angular.IScope;
$$nextSibling: angular.IScope;
[key: string]: any;
$id = 'mockScope';
$parent: angular.IScope;
$root: angular.IScope;
}
function getAdaptor(): DowngradeComponentAdapter {
let attrs = undefined as any;
let scope: angular.IScope; // mock
let ngModel = undefined as any;
let parentInjector: Injector; // testbed
let $injector = undefined as any;
let $compile = undefined as any;
let $parse = undefined as any;
let componentFactory: ComponentFactory; // testbed
let wrapCallback = (cb: any) => cb;
content = `
new component
a great component
`;
element = angular.element(content);
scope = new mockScope();
@Component({
selector: 'comp',
template: '',
})
class NewComponent {
}
@NgModule({
providers: [{provide: 'hello', useValue: 'component'}],
declarations: [NewComponent],
entryComponents: [NewComponent],
})
class NewModule {
}
const modFactory = compiler.compileModuleSync(NewModule);
const module = modFactory.create(TestBed);
componentFactory = module.componentFactoryResolver.resolveComponentFactory(NewComponent) !;
parentInjector = TestBed;
return new DowngradeComponentAdapter(
element, attrs, scope, ngModel, parentInjector, $injector, $compile, $parse,
componentFactory, wrapCallback);
}
beforeEach((inject([Compiler], (inject_compiler: Compiler) => {
compiler = inject_compiler;
adapter = getAdaptor();
})));
afterEach(() => {
let registry = TestBed.get(TestabilityRegistry);
registry.unregisterAllApplications();
});
it('should add testabilities hook when creating components', () => {
let registry = TestBed.get(TestabilityRegistry);
adapter.createComponent([]);
expect(registry.getAllTestabilities().length).toEqual(1);
adapter = getAdaptor(); // get a new adaptor to creat a new component
adapter.createComponent([]);
expect(registry.getAllTestabilities().length).toEqual(2);
});
it('should remove the testability hook when destroy a component', () => {
const registry = TestBed.get(TestabilityRegistry);
expect(registry.getAllTestabilities().length).toEqual(0);
adapter.createComponent([]);
expect(registry.getAllTestabilities().length).toEqual(1);
adapter.registerCleanup();
element.remove !();
expect(registry.getAllTestabilities().length).toEqual(0);
});
});
});
});