feat(upgrade): return a function (instead of array) from `downgradeInjectable()` (#14037)
This makes it more consistent with the dynamic version of `upgrade` and makes it
possible to share code between the dynamic and static versions.
This commit also refactors the file layout, moving common and dynamic-specific
files to `common/` and `dynamic/` directories respectively and renaming `aot/`
to `static/`.
Some private keys, used as AngularJS DI tokens, have also been renamed, but this
should not affect apps, since these keys are undocumented and not supposed to
be used externally.
BREAKING CHANGE:
Previously, `upgrade/static/downgradeInjectable` returned an array of the form:
```js
['dep1', 'dep2', ..., function factory(dep1, dep2, ...) { ... }]
```
Now it returns a function with an `$inject` property:
```js
factory.$inject = ['dep1', 'dep2', ...];
function factory(dep1, dep2, ...) { ... }
```
It shouldn't affect the behavior of apps, since both forms are equally suitable
to be used for registering AngularJS injectable services, but it is possible
that type-checking might fail or that current code breaks if it relies on the
returned value being an array.
2017-01-13 09:20:28 -05: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-02-15 12:21:18 -05:00
|
|
|
import {setAngularJSGlobal} from '@angular/upgrade/src/common/angular1';
|
|
|
|
|
|
|
|
|
|
|
|
const ng1Versions = [
|
|
|
|
{
|
|
|
|
label: '1.5',
|
|
|
|
files: ['angular-1.5/angular.js', 'angular-mocks-1.5/angular-mocks.js'],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: '1.6',
|
|
|
|
files: ['angular/angular.js', 'angular-mocks/angular-mocks.js'],
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
export function createWithEachNg1VersionFn(setNg1: typeof setAngularJSGlobal) {
|
|
|
|
return (specSuite: () => void) => ng1Versions.forEach(({label, files}) => {
|
|
|
|
describe(`[AngularJS v${label}]`, () => {
|
2018-07-04 18:53:51 -04:00
|
|
|
// Problem:
|
|
|
|
// As soon as `angular-mocks.js` is loaded, it runs `beforeEach` and `afterEach` to register
|
|
|
|
// setup/tear down callbacks. Jasmine 2.9+ does not allow `beforeEach`/`afterEach` to be
|
|
|
|
// nested inside a `beforeAll` call (only inside `describe`).
|
|
|
|
// Hacky work-around:
|
|
|
|
// Patch the affected jasmine methods while loading `angular-mocks.js` (inside `beforeAll`) to
|
|
|
|
// capture the registered callbacks. Also, inside the `describe` call register a callback with
|
|
|
|
// each affected method that runs all captured callbacks.
|
|
|
|
// (Note: Currently, async callbacks are not supported, but that should be OK, since
|
|
|
|
// `angular-mocks.js` does not use them.)
|
|
|
|
const methodsToPatch = ['beforeAll', 'beforeEach', 'afterEach', 'afterAll'];
|
|
|
|
const methodCallbacks = methodsToPatch.reduce<{[name: string]: any[]}>(
|
|
|
|
(aggr, method) => ({...aggr, [method]: []}), {});
|
|
|
|
const win = window as any;
|
|
|
|
|
|
|
|
function patchJasmineMethods(): () => void {
|
|
|
|
const originalMethods: {[name: string]: any} = {};
|
|
|
|
|
|
|
|
methodsToPatch.forEach(method => {
|
|
|
|
originalMethods[method] = win[method];
|
|
|
|
win[method] = (cb: any) => methodCallbacks[method].push(cb);
|
|
|
|
});
|
|
|
|
|
|
|
|
return () => methodsToPatch.forEach(method => win[method] = originalMethods[method]);
|
|
|
|
}
|
|
|
|
|
2018-02-15 12:21:18 -05:00
|
|
|
beforeAll(done => {
|
|
|
|
// Load AngularJS before running tests.
|
|
|
|
files
|
|
|
|
.reduce(
|
|
|
|
(prev, file) => prev.then(() => new Promise<void>((resolve, reject) => {
|
2018-07-04 18:53:51 -04:00
|
|
|
const restoreMethods = patchJasmineMethods();
|
2018-02-15 12:21:18 -05:00
|
|
|
const script = document.createElement('script');
|
2018-05-31 02:49:37 -04:00
|
|
|
script.src = `base/angular/node_modules/${file}`;
|
2018-02-15 12:21:18 -05:00
|
|
|
script.onerror = reject;
|
|
|
|
script.onload = () => {
|
|
|
|
document.body.removeChild(script);
|
2018-07-04 18:53:51 -04:00
|
|
|
restoreMethods();
|
2018-02-15 12:21:18 -05:00
|
|
|
resolve();
|
|
|
|
};
|
|
|
|
document.body.appendChild(script);
|
|
|
|
})),
|
|
|
|
Promise.resolve())
|
2018-07-04 18:53:51 -04:00
|
|
|
.then(() => setNg1(win.angular))
|
2018-02-15 12:21:18 -05:00
|
|
|
.then(done, done.fail);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterAll(() => {
|
|
|
|
// In these tests we are loading different versions of AngularJS on the same window.
|
|
|
|
// AngularJS leaves an "expandoId" property on `document`, which can trick subsequent
|
|
|
|
// `window.angular` instances into believing an app is already bootstrapped.
|
2018-07-04 18:53:51 -04:00
|
|
|
win.angular.element(document).removeData();
|
2018-02-15 12:21:18 -05:00
|
|
|
|
|
|
|
// Remove AngularJS to leave a clean state for subsequent tests.
|
|
|
|
setNg1(undefined);
|
2018-07-04 18:53:51 -04:00
|
|
|
delete win.angular;
|
2018-02-15 12:21:18 -05:00
|
|
|
});
|
|
|
|
|
2018-07-04 18:53:51 -04:00
|
|
|
methodsToPatch.forEach(method => win[method](function() {
|
|
|
|
// Run the captured callbacks. (Async callbacks not supported.)
|
|
|
|
methodCallbacks[method].forEach(cb => cb.call(this));
|
|
|
|
}));
|
|
|
|
|
2018-02-15 12:21:18 -05:00
|
|
|
specSuite();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
feat(upgrade): return a function (instead of array) from `downgradeInjectable()` (#14037)
This makes it more consistent with the dynamic version of `upgrade` and makes it
possible to share code between the dynamic and static versions.
This commit also refactors the file layout, moving common and dynamic-specific
files to `common/` and `dynamic/` directories respectively and renaming `aot/`
to `static/`.
Some private keys, used as AngularJS DI tokens, have also been renamed, but this
should not affect apps, since these keys are undocumented and not supposed to
be used externally.
BREAKING CHANGE:
Previously, `upgrade/static/downgradeInjectable` returned an array of the form:
```js
['dep1', 'dep2', ..., function factory(dep1, dep2, ...) { ... }]
```
Now it returns a function with an `$inject` property:
```js
factory.$inject = ['dep1', 'dep2', ...];
function factory(dep1, dep2, ...) { ... }
```
It shouldn't affect the behavior of apps, since both forms are equally suitable
to be used for registering AngularJS injectable services, but it is possible
that type-checking might fail or that current code breaks if it relies on the
returned value being an array.
2017-01-13 09:20:28 -05:00
|
|
|
|
|
|
|
export function html(html: string): Element {
|
|
|
|
// Don't return `body` itself, because using it as a `$rootElement` for ng1
|
|
|
|
// will attach `$injector` to it and that will affect subsequent tests.
|
|
|
|
const body = document.body;
|
|
|
|
body.innerHTML = `<div>${html.trim()}</div>`;
|
|
|
|
const div = document.body.firstChild as Element;
|
|
|
|
|
|
|
|
if (div.childNodes.length === 1 && div.firstChild instanceof HTMLElement) {
|
|
|
|
return div.firstChild;
|
|
|
|
}
|
|
|
|
|
|
|
|
return div;
|
|
|
|
}
|
|
|
|
|
2017-07-05 06:58:27 -04:00
|
|
|
export function multiTrim(text: string | null | undefined, allSpace = false): string {
|
2017-03-29 12:34:45 -04:00
|
|
|
if (typeof text == 'string') {
|
2017-07-05 06:58:27 -04:00
|
|
|
const repl = allSpace ? '' : ' ';
|
|
|
|
return text.replace(/\n/g, '').replace(/\s+/g, repl).trim();
|
2017-03-29 12:34:45 -04:00
|
|
|
}
|
|
|
|
throw new Error('Argument can not be undefined.');
|
feat(upgrade): return a function (instead of array) from `downgradeInjectable()` (#14037)
This makes it more consistent with the dynamic version of `upgrade` and makes it
possible to share code between the dynamic and static versions.
This commit also refactors the file layout, moving common and dynamic-specific
files to `common/` and `dynamic/` directories respectively and renaming `aot/`
to `static/`.
Some private keys, used as AngularJS DI tokens, have also been renamed, but this
should not affect apps, since these keys are undocumented and not supposed to
be used externally.
BREAKING CHANGE:
Previously, `upgrade/static/downgradeInjectable` returned an array of the form:
```js
['dep1', 'dep2', ..., function factory(dep1, dep2, ...) { ... }]
```
Now it returns a function with an `$inject` property:
```js
factory.$inject = ['dep1', 'dep2', ...];
function factory(dep1, dep2, ...) { ... }
```
It shouldn't affect the behavior of apps, since both forms are equally suitable
to be used for registering AngularJS injectable services, but it is possible
that type-checking might fail or that current code breaks if it relies on the
returned value being an array.
2017-01-13 09:20:28 -05:00
|
|
|
}
|
2017-03-13 20:34:53 -04:00
|
|
|
|
|
|
|
export function nodes(html: string) {
|
|
|
|
const div = document.createElement('div');
|
|
|
|
div.innerHTML = html.trim();
|
|
|
|
return Array.prototype.slice.call(div.childNodes);
|
|
|
|
}
|
2018-02-15 12:21:18 -05:00
|
|
|
|
|
|
|
export const withEachNg1Version = createWithEachNg1VersionFn(setAngularJSGlobal);
|