2017-03-13 20:34:53 -04:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
2018-07-06 02:13:25 -04:00
|
|
|
import {Compiler, Component, ComponentFactory, Injector, NgModule, TestabilityRegistry} from '@angular/core';
|
|
|
|
import {TestBed} from '@angular/core/testing';
|
2017-03-13 20:34:53 -04:00
|
|
|
import * as angular from '@angular/upgrade/src/common/angular1';
|
2017-09-08 14:50:13 -04:00
|
|
|
import {DowngradeComponentAdapter, groupNodesBySelector} from '@angular/upgrade/src/common/downgrade_component_adapter';
|
2017-03-13 20:34:53 -04:00
|
|
|
|
2018-02-15 12:21:18 -05:00
|
|
|
import {nodes, withEachNg1Version} from './test_helpers';
|
2017-03-13 20:34:53 -04:00
|
|
|
|
2018-02-15 12:21:18 -05:00
|
|
|
withEachNg1Version(() => {
|
2017-03-13 20:34:53 -04:00
|
|
|
describe('DowngradeComponentAdapter', () => {
|
|
|
|
describe('groupNodesBySelector', () => {
|
|
|
|
it('should return an array of node collections for each selector', () => {
|
|
|
|
const contentNodes = nodes(
|
|
|
|
'<div class="x"><span>div-1 content</span></div>' +
|
|
|
|
'<input type="number" name="myNum">' +
|
|
|
|
'<input type="date" name="myDate">' +
|
|
|
|
'<span>span content</span>' +
|
|
|
|
'<div class="x"><span>div-2 content</span></div>');
|
|
|
|
|
|
|
|
const selectors = ['input[type=date]', 'span', '.x'];
|
2017-03-14 17:55:37 -04:00
|
|
|
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
2017-03-13 20:34:53 -04:00
|
|
|
expect(projectableNodes[0]).toEqual(nodes('<input type="date" name="myDate">'));
|
|
|
|
expect(projectableNodes[1]).toEqual(nodes('<span>span content</span>'));
|
|
|
|
expect(projectableNodes[2])
|
|
|
|
.toEqual(nodes(
|
|
|
|
'<div class="x"><span>div-1 content</span></div>' +
|
|
|
|
'<div class="x"><span>div-2 content</span></div>'));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should collect up unmatched nodes for the wildcard selector', () => {
|
|
|
|
const contentNodes = nodes(
|
|
|
|
'<div class="x"><span>div-1 content</span></div>' +
|
|
|
|
'<input type="number" name="myNum">' +
|
|
|
|
'<input type="date" name="myDate">' +
|
|
|
|
'<span>span content</span>' +
|
|
|
|
'<div class="x"><span>div-2 content</span></div>');
|
|
|
|
|
|
|
|
const selectors = ['.x', '*', 'input[type=date]'];
|
2017-03-14 17:55:37 -04:00
|
|
|
const projectableNodes = groupNodesBySelector(selectors, contentNodes);
|
2017-03-13 20:34:53 -04:00
|
|
|
|
|
|
|
expect(projectableNodes[0])
|
|
|
|
.toEqual(nodes(
|
|
|
|
'<div class="x"><span>div-1 content</span></div>' +
|
|
|
|
'<div class="x"><span>div-2 content</span></div>'));
|
|
|
|
expect(projectableNodes[1])
|
|
|
|
.toEqual(nodes(
|
|
|
|
'<input type="number" name="myNum">' +
|
|
|
|
'<span>span content</span>'));
|
|
|
|
expect(projectableNodes[2]).toEqual(nodes('<input type="date" name="myDate">'));
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should return an array of empty arrays if there are no nodes passed in', () => {
|
|
|
|
const selectors = ['.x', '*', 'input[type=date]'];
|
2017-03-14 17:55:37 -04:00
|
|
|
const projectableNodes = groupNodesBySelector(selectors, []);
|
2017-03-13 20:34:53 -04:00
|
|
|
expect(projectableNodes).toEqual([[], [], []]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should return an empty array for each selector that does not match', () => {
|
|
|
|
const contentNodes = nodes(
|
|
|
|
'<div class="x"><span>div-1 content</span></div>' +
|
|
|
|
'<input type="number" name="myNum">' +
|
|
|
|
'<input type="date" name="myDate">' +
|
|
|
|
'<span>span content</span>' +
|
|
|
|
'<div class="x"><span>div-2 content</span></div>');
|
|
|
|
|
2017-03-14 17:55:37 -04:00
|
|
|
const projectableNodes = groupNodesBySelector([], contentNodes);
|
2017-03-13 20:34:53 -04:00
|
|
|
expect(projectableNodes).toEqual([]);
|
|
|
|
|
2017-03-14 17:55:37 -04:00
|
|
|
const noMatchSelectorNodes = groupNodesBySelector(['.not-there'], contentNodes);
|
2017-03-13 20:34:53 -04:00
|
|
|
expect(noMatchSelectorNodes).toEqual([[]]);
|
|
|
|
});
|
|
|
|
});
|
2017-09-08 14:50:13 -04:00
|
|
|
|
|
|
|
describe('testability', () => {
|
|
|
|
|
|
|
|
let adapter: DowngradeComponentAdapter;
|
|
|
|
let content: string;
|
|
|
|
let compiler: Compiler;
|
2018-07-06 02:13:25 -04:00
|
|
|
let registry: TestabilityRegistry;
|
2017-09-08 14:50:13 -04:00
|
|
|
let element: angular.IAugmentedJQuery;
|
|
|
|
|
|
|
|
class mockScope implements angular.IScope {
|
2018-02-23 08:18:21 -05:00
|
|
|
private destroyListeners: (() => void)[] = [];
|
|
|
|
|
2017-09-22 13:51:03 -04:00
|
|
|
$new() { return this; }
|
2017-09-08 14:50:13 -04:00
|
|
|
$watch(exp: angular.Ng1Expression, fn?: (a1?: any, a2?: any) => void) {
|
|
|
|
return () => {};
|
2017-09-22 13:51:03 -04:00
|
|
|
}
|
2017-09-08 14:50:13 -04:00
|
|
|
$on(event: string, fn?: (event?: any, ...args: any[]) => void) {
|
2018-02-23 08:18:21 -05:00
|
|
|
if (event === '$destroy' && fn) {
|
|
|
|
this.destroyListeners.push(fn);
|
|
|
|
}
|
2017-09-08 14:50:13 -04:00
|
|
|
return () => {};
|
2017-09-22 13:51:03 -04:00
|
|
|
}
|
2017-09-08 14:50:13 -04:00
|
|
|
$destroy() {
|
2018-02-23 08:18:21 -05:00
|
|
|
let listener: (() => void)|undefined;
|
|
|
|
while ((listener = this.destroyListeners.shift())) listener();
|
2017-09-22 13:51:03 -04:00
|
|
|
}
|
2017-09-08 14:50:13 -04:00
|
|
|
$apply(exp?: angular.Ng1Expression) {
|
|
|
|
return () => {};
|
2017-09-22 13:51:03 -04:00
|
|
|
}
|
2017-09-08 14:50:13 -04:00
|
|
|
$digest() {
|
|
|
|
return () => {};
|
2017-09-22 13:51:03 -04:00
|
|
|
}
|
2017-09-08 14:50:13 -04:00
|
|
|
$evalAsync(exp: angular.Ng1Expression, locals?: any) {
|
|
|
|
return () => {};
|
2017-09-22 13:51:03 -04:00
|
|
|
}
|
2018-06-18 19:38:33 -04:00
|
|
|
// TODO(issue/24571): remove '!'.
|
|
|
|
$$childTail !: angular.IScope;
|
|
|
|
// TODO(issue/24571): remove '!'.
|
|
|
|
$$childHead !: angular.IScope;
|
|
|
|
// TODO(issue/24571): remove '!'.
|
|
|
|
$$nextSibling !: angular.IScope;
|
2017-09-08 14:50:13 -04:00
|
|
|
[key: string]: any;
|
|
|
|
$id = 'mockScope';
|
2018-06-18 19:38:33 -04:00
|
|
|
// TODO(issue/24571): remove '!'.
|
|
|
|
$parent !: angular.IScope;
|
|
|
|
// TODO(issue/24571): remove '!'.
|
|
|
|
$root !: angular.IScope;
|
2017-09-08 14:50:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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<any>; // testbed
|
2017-09-25 05:39:51 -04:00
|
|
|
let wrapCallback = (cb: any) => cb;
|
2017-09-08 14:50:13 -04:00
|
|
|
|
|
|
|
content = `
|
|
|
|
<h1> new component </h1>
|
|
|
|
<div> a great component </div>
|
|
|
|
<comp></comp>
|
|
|
|
`;
|
|
|
|
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);
|
2017-09-22 13:51:03 -04:00
|
|
|
}
|
2017-09-08 14:50:13 -04:00
|
|
|
|
2018-07-06 02:13:25 -04:00
|
|
|
beforeEach(() => {
|
|
|
|
compiler = TestBed.get(Compiler);
|
|
|
|
registry = TestBed.get(TestabilityRegistry);
|
2017-09-08 14:50:13 -04:00
|
|
|
adapter = getAdaptor();
|
|
|
|
});
|
2018-07-06 02:13:25 -04:00
|
|
|
beforeEach(() => registry.unregisterAllApplications());
|
|
|
|
afterEach(() => registry.unregisterAllApplications());
|
2017-09-08 14:50:13 -04:00
|
|
|
|
2018-11-27 17:11:10 -05:00
|
|
|
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);
|
|
|
|
});
|
2017-09-08 14:50:13 -04:00
|
|
|
});
|
|
|
|
|
2017-03-13 20:34:53 -04:00
|
|
|
});
|
2018-02-15 12:21:18 -05:00
|
|
|
});
|