2016-10-04 23:39:20 -04:00
|
|
|
/**
|
|
|
|
* @license
|
2020-05-19 15:08:49 -04:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2016-10-04 23:39:20 -04:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2015-05-23 12:51:40 -04:00
|
|
|
// Tun on full stack traces in errors to help debugging
|
2016-10-04 23:39:20 -04:00
|
|
|
Error.stackTraceLimit = Infinity;
|
2015-05-23 12:51:40 -04:00
|
|
|
|
2015-04-15 01:14:03 -04:00
|
|
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100;
|
2014-10-06 20:35:00 -04:00
|
|
|
|
|
|
|
// Cancel Karma's synchronous start,
|
|
|
|
// we will call `__karma__.start()` later, once all the specs are loaded.
|
|
|
|
__karma__.loaded = function() {};
|
|
|
|
|
2017-12-17 18:10:54 -05:00
|
|
|
window.isNode = false;
|
|
|
|
window.isBrowser = true;
|
|
|
|
|
2015-08-14 18:05:56 -04:00
|
|
|
System.config({
|
2016-04-28 20:50:03 -04:00
|
|
|
baseURL: '/base',
|
2015-08-14 18:05:56 -04:00
|
|
|
defaultJSExtensions: true,
|
2016-04-28 20:50:03 -04:00
|
|
|
map: {
|
2015-08-14 18:05:56 -04:00
|
|
|
'benchpress/*': 'dist/js/dev/es5/benchpress/*.js',
|
2016-04-28 20:50:03 -04:00
|
|
|
'@angular': 'dist/all/@angular',
|
2017-08-08 05:17:40 -04:00
|
|
|
'domino': 'dist/all/@angular/empty.js',
|
2017-03-15 16:40:24 -04:00
|
|
|
'url': 'dist/all/@angular/empty.js',
|
|
|
|
'xhr2': 'dist/all/@angular/empty.js',
|
feat(platform-server): allow shimming the global env sooner (#40559)
`@angular/platform-server` provides the foundation for rendering an
Angular app on the server. In order to achieve that, it uses a
server-side DOM implementation (currently [domino][1]).
For rendering on the server to work as closely as possible to running
the app on the browser, we need to make DOM globals (such as `Element`,
`HTMLElement`, etc.), which are normally provided by the browser,
available as globals on the server as well.
Currently, `@angular/platform-server` achieves this by extending the
`global` object with the DOM implementation provided by `domino`. This
assignment happens in the [setDomTypes()][2] function, which is
[called in a `PLATFORM_INITIALIZER`][3]. While this works in most cases,
there are some scenarios where the DOM globals are needed sooner (i.e.
before initializing the platform). See, for example, #24551 and #39950
for more details on such issues.
This commit provides a way to solve this problem by exposing a
side-effect-ful entry-point (`@angular/platform-server/init`), that
shims the `global` object with DOM globals. People will be able to
import this entry-point in their server-rendered apps before
bootstrapping the app (for example, in their `main.server.ts` file).
(See also [#39950 (comment)][4].)
In a future update, the [`universal` schematics][5] will include such an
import by default in newly generated projects.
[1]: https://www.npmjs.com/package/domino
[2]: https://github.com/angular/angular/blob/0fc8466f1be392917e0c/packages/platform-server/src/domino_adapter.ts#L17-L21
[3]: https://github.com/angular/angular/blob/0fc8466f1be392917e0c/packages/platform-server/src/server.ts#L33
[4]: https://github.com/angular/angular/issues/39950#issuecomment-747598403
[5]: https://github.com/angular/angular-cli/blob/cc51432661eb4ab4b6a3/packages/schematics/angular/universal
PR Close #40559
2021-02-11 12:24:52 -05:00
|
|
|
'@angular/platform-server/src/domino_adapter': 'dist/all/@angular/empty.js',
|
2020-06-12 12:25:08 -04:00
|
|
|
'angular-in-memory-web-api': 'dist/all/@angular/misc/angular-in-memory-web-api',
|
2018-02-27 17:06:06 -05:00
|
|
|
'rxjs': 'node_modules/rxjs',
|
2016-04-28 20:50:03 -04:00
|
|
|
},
|
|
|
|
packages: {
|
2019-04-02 18:21:41 -04:00
|
|
|
'@angular/core/src/render3': {main: 'index.js', defaultExtension: 'js'},
|
2016-10-04 23:39:20 -04:00
|
|
|
'@angular/core/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/core': {main: 'index.js', defaultExtension: 'js'},
|
2017-02-28 20:49:37 -05:00
|
|
|
'@angular/animations/browser/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/animations/browser': {main: 'index.js', defaultExtension: 'js'},
|
2017-02-22 18:14:49 -05:00
|
|
|
'@angular/animations/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/animations': {main: 'index.js', defaultExtension: 'js'},
|
2016-10-04 23:39:20 -04:00
|
|
|
'@angular/compiler/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/compiler': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/common/testing': {main: 'index.js', defaultExtension: 'js'},
|
2017-03-22 20:13:24 -04:00
|
|
|
'@angular/common/http/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/common/http': {main: 'index.js', defaultExtension: 'js'},
|
2016-10-04 23:39:20 -04:00
|
|
|
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/forms': {main: 'index.js', defaultExtension: 'js'},
|
2020-06-12 12:25:08 -04:00
|
|
|
'@angular/misc/angular-in-memory-web-api': {main: 'index.js', defaultExtension: 'js'},
|
2016-04-28 20:50:03 -04:00
|
|
|
// remove after all tests imports are fixed
|
2016-10-04 23:39:20 -04:00
|
|
|
'@angular/facade': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/router/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
2019-10-08 09:46:28 -04:00
|
|
|
'@angular/localize/src/utils': {main: 'index.js', defaultExtension: 'js'},
|
2019-08-10 07:51:30 -04:00
|
|
|
'@angular/localize/src/localize': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/localize/init': {main: 'index.js', defaultExtension: 'js'},
|
2019-07-30 13:02:17 -04:00
|
|
|
'@angular/localize': {main: 'index.js', defaultExtension: 'js'},
|
2019-03-22 05:42:52 -04:00
|
|
|
'@angular/upgrade/static/testing': {main: 'index.js', defaultExtension: 'js'},
|
2017-03-07 14:04:30 -05:00
|
|
|
'@angular/upgrade/static': {main: 'index.js', defaultExtension: 'js'},
|
2016-10-04 23:39:20 -04:00
|
|
|
'@angular/upgrade': {main: 'index.js', defaultExtension: 'js'},
|
2017-02-22 18:14:49 -05:00
|
|
|
'@angular/platform-browser/animations/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/platform-browser/animations': {main: 'index.js', defaultExtension: 'js'},
|
2016-10-04 23:39:20 -04:00
|
|
|
'@angular/platform-browser/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/platform-browser-dynamic/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
|
feat(platform-server): allow shimming the global env sooner (#40559)
`@angular/platform-server` provides the foundation for rendering an
Angular app on the server. In order to achieve that, it uses a
server-side DOM implementation (currently [domino][1]).
For rendering on the server to work as closely as possible to running
the app on the browser, we need to make DOM globals (such as `Element`,
`HTMLElement`, etc.), which are normally provided by the browser,
available as globals on the server as well.
Currently, `@angular/platform-server` achieves this by extending the
`global` object with the DOM implementation provided by `domino`. This
assignment happens in the [setDomTypes()][2] function, which is
[called in a `PLATFORM_INITIALIZER`][3]. While this works in most cases,
there are some scenarios where the DOM globals are needed sooner (i.e.
before initializing the platform). See, for example, #24551 and #39950
for more details on such issues.
This commit provides a way to solve this problem by exposing a
side-effect-ful entry-point (`@angular/platform-server/init`), that
shims the `global` object with DOM globals. People will be able to
import this entry-point in their server-rendered apps before
bootstrapping the app (for example, in their `main.server.ts` file).
(See also [#39950 (comment)][4].)
In a future update, the [`universal` schematics][5] will include such an
import by default in newly generated projects.
[1]: https://www.npmjs.com/package/domino
[2]: https://github.com/angular/angular/blob/0fc8466f1be392917e0c/packages/platform-server/src/domino_adapter.ts#L17-L21
[3]: https://github.com/angular/angular/blob/0fc8466f1be392917e0c/packages/platform-server/src/server.ts#L33
[4]: https://github.com/angular/angular/issues/39950#issuecomment-747598403
[5]: https://github.com/angular/angular-cli/blob/cc51432661eb4ab4b6a3/packages/schematics/angular/universal
PR Close #40559
2021-02-11 12:24:52 -05:00
|
|
|
'@angular/platform-server/init': {main: 'index.js', defaultExtension: 'js'},
|
2016-10-04 23:39:20 -04:00
|
|
|
'@angular/platform-server/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'@angular/platform-server': {main: 'index.js', defaultExtension: 'js'},
|
2018-07-27 16:49:22 -04:00
|
|
|
'@angular/private/testing': {main: 'index.js', defaultExtension: 'js'},
|
2018-02-28 12:45:11 -05:00
|
|
|
'@angular/elements': {main: 'index.js', defaultExtension: 'js'},
|
2018-02-27 17:06:06 -05:00
|
|
|
'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'rxjs/operators': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'rxjs/testing': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'},
|
|
|
|
'rxjs': {main: 'index.js', defaultExtension: 'js'},
|
2015-08-14 18:05:56 -04:00
|
|
|
}
|
|
|
|
});
|
2014-10-06 20:35:00 -04:00
|
|
|
|
2016-04-28 20:50:03 -04:00
|
|
|
|
2018-02-28 12:45:11 -05:00
|
|
|
// Load browser-specific CustomElement polyfills, set up the test injector, import all the specs,
|
|
|
|
// execute their `main()` method and kick off Karma (Jasmine).
|
|
|
|
Promise
|
|
|
|
.resolve()
|
|
|
|
|
|
|
|
// Load browser-specific polyfills for custom elements.
|
2020-04-13 19:40:21 -04:00
|
|
|
.then(function() {
|
|
|
|
return loadCustomElementsPolyfills();
|
|
|
|
})
|
2018-02-28 12:45:11 -05:00
|
|
|
|
|
|
|
// Load necessary testing packages.
|
|
|
|
.then(function() {
|
|
|
|
return Promise.all([
|
|
|
|
System.import('@angular/core/testing'),
|
|
|
|
System.import('@angular/platform-browser-dynamic/testing'),
|
|
|
|
System.import('@angular/platform-browser/animations')
|
|
|
|
]);
|
|
|
|
})
|
|
|
|
|
|
|
|
// Set up the test injector.
|
|
|
|
.then(function(mods) {
|
|
|
|
var coreTesting = mods[0];
|
|
|
|
var pbdTesting = mods[1];
|
|
|
|
var pbAnimations = mods[2];
|
|
|
|
|
|
|
|
coreTesting.TestBed.initTestEnvironment(
|
|
|
|
[pbdTesting.BrowserDynamicTestingModule, pbAnimations.NoopAnimationsModule],
|
|
|
|
pbdTesting.platformBrowserDynamicTesting());
|
2016-10-04 23:39:20 -04:00
|
|
|
})
|
2018-02-28 12:45:11 -05:00
|
|
|
|
|
|
|
// Import all the specs and execute their `main()` method.
|
2016-10-04 23:39:20 -04:00
|
|
|
.then(function() {
|
|
|
|
return Promise.all(Object
|
|
|
|
.keys(window.__karma__.files) // All files served by Karma.
|
|
|
|
.filter(onlySpecFiles)
|
|
|
|
.map(window.file2moduleName) // Normalize paths to module names.
|
|
|
|
.map(function(path) {
|
|
|
|
return System.import(path).then(function(module) {
|
|
|
|
if (module.hasOwnProperty('main')) {
|
2017-12-16 17:42:55 -05:00
|
|
|
throw new Error('main() in specs are no longer supported');
|
2016-10-04 23:39:20 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
})
|
2018-02-28 12:45:11 -05:00
|
|
|
|
|
|
|
// Kick off karma (Jasmine).
|
2020-04-13 19:40:21 -04:00
|
|
|
.then(
|
|
|
|
function() {
|
|
|
|
__karma__.start();
|
|
|
|
},
|
|
|
|
function(error) {
|
|
|
|
console.error(error);
|
|
|
|
});
|
2014-10-06 20:35:00 -04:00
|
|
|
|
|
|
|
|
2018-02-28 12:45:11 -05:00
|
|
|
function loadCustomElementsPolyfills() {
|
|
|
|
var loadedPromise = Promise.resolve();
|
|
|
|
|
|
|
|
// The custom elements polyfill relies on `MutationObserver`.
|
|
|
|
if (!window.MutationObserver) {
|
2020-04-13 19:40:21 -04:00
|
|
|
loadedPromise = loadedPromise
|
|
|
|
.then(function() {
|
|
|
|
return System.import('node_modules/mutation-observer/index.js');
|
|
|
|
})
|
|
|
|
.then(function(MutationObserver) {
|
|
|
|
window.MutationObserver = MutationObserver;
|
|
|
|
});
|
2018-02-28 12:45:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// The custom elements polyfill relies on `Object.setPrototypeOf()`.
|
|
|
|
if (!Object.setPrototypeOf) {
|
|
|
|
var getDescriptor = function getDescriptor(obj, prop) {
|
|
|
|
var descriptor;
|
|
|
|
while (obj && !descriptor) {
|
|
|
|
descriptor = Object.getOwnPropertyDescriptor(obj, prop);
|
|
|
|
obj = Object.getPrototypeOf(obj);
|
|
|
|
}
|
|
|
|
return descriptor || {};
|
|
|
|
};
|
|
|
|
var setPrototypeOf = function setPrototypeOf(obj, proto) {
|
|
|
|
for (var prop in proto) {
|
|
|
|
if (!obj.hasOwnProperty(prop)) {
|
|
|
|
Object.defineProperty(obj, prop, getDescriptor(proto, prop));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
};
|
|
|
|
|
|
|
|
Object.defineProperty(setPrototypeOf, '$$shimmed', {value: true});
|
|
|
|
Object.setPrototypeOf = setPrototypeOf;
|
|
|
|
}
|
|
|
|
|
2018-03-06 17:02:25 -05:00
|
|
|
// The custom elements polyfill will patch properties and methods on `(HTML)Element` and `Node`
|
|
|
|
// (among others), including `(HTML)Element#innerHTML` and `Node#removeChild()`:
|
|
|
|
// https://github.com/webcomponents/custom-elements/blob/4f7072c0dbda4beb505d16967acfffd33337b325/src/Patch/Element.js#L28-L73
|
|
|
|
// https://github.com/webcomponents/custom-elements/blob/4f7072c0dbda4beb505d16967acfffd33337b325/src/Patch/Node.js#L105-L120
|
|
|
|
// The patched `innerHTML` setter and `removeChild()` method will try to traverse the DOM (via
|
|
|
|
// `nextSibling` and `parentNode` respectively), which leads to infinite loops when testing
|
|
|
|
// `HtmlSanitizer` with cloberred elements on browsers that do not support the `<template>`
|
|
|
|
// element:
|
2018-02-28 12:45:11 -05:00
|
|
|
// https://github.com/angular/angular/blob/213baa37b0b71e72d00ad7b606ebfc2ade06b934/packages/platform-browser/src/security/html_sanitizer.ts#L29-L38
|
2018-03-06 17:02:25 -05:00
|
|
|
// To avoid that, we "unpatch" these properties/methods and apply the patch only for the relevant
|
2018-02-28 12:45:11 -05:00
|
|
|
// `@angular/elements` tests.
|
2018-03-06 17:02:25 -05:00
|
|
|
var patchConfig = {'innerHTML': ['Element', 'HTMLElement'], 'removeChild': ['Node']};
|
|
|
|
var patchTargets = {};
|
|
|
|
var originalDescriptors = {};
|
2018-02-28 12:45:11 -05:00
|
|
|
if (!window.customElements) {
|
2018-03-06 17:02:25 -05:00
|
|
|
Object.keys(patchConfig).forEach(function(prop) {
|
|
|
|
patchConfig[prop]
|
2020-04-13 19:40:21 -04:00
|
|
|
.map(function(name) {
|
|
|
|
return window[name].prototype;
|
|
|
|
})
|
2018-03-06 17:02:25 -05:00
|
|
|
.some(function(candidatePatchTarget) {
|
|
|
|
var candidateOriginalDescriptor =
|
|
|
|
Object.getOwnPropertyDescriptor(candidatePatchTarget, prop);
|
|
|
|
|
|
|
|
if (candidateOriginalDescriptor) {
|
|
|
|
patchTargets[prop] = candidatePatchTarget;
|
|
|
|
originalDescriptors[prop] = candidateOriginalDescriptor;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2018-02-28 12:45:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
var polyfillPath = !window.customElements ?
|
|
|
|
// Load custom elements polyfill.
|
|
|
|
'node_modules/@webcomponents/custom-elements/custom-elements.min.js' :
|
|
|
|
// Allow ES5 functions as custom element constructors.
|
|
|
|
'node_modules/@webcomponents/custom-elements/src/native-shim.js';
|
|
|
|
|
2020-04-13 19:40:21 -04:00
|
|
|
loadedPromise = loadedPromise
|
|
|
|
.then(function() {
|
|
|
|
return System.import(polyfillPath);
|
|
|
|
})
|
|
|
|
.then(function() {
|
|
|
|
// `packages/compiler/test/schema/schema_extractor.ts` relies on
|
|
|
|
// `HTMLElement.name`, but custom element polyfills will replace
|
|
|
|
// `HTMLElement` with an anonymous function.
|
|
|
|
Object.defineProperty(HTMLElement, 'name', {value: 'HTMLElement'});
|
|
|
|
|
|
|
|
// Create helper functions on `window` for patching/restoring
|
|
|
|
// properties/methods.
|
|
|
|
Object.keys(patchConfig).forEach(function(prop) {
|
|
|
|
var patchMethod = '$$patch_' + prop;
|
|
|
|
var restoreMethod = '$$restore_' + prop;
|
|
|
|
|
|
|
|
if (!patchTargets[prop]) {
|
|
|
|
// No patching detected. Create no-op functions.
|
|
|
|
window[patchMethod] = window[restoreMethod] = function() {};
|
|
|
|
} else {
|
|
|
|
var patchTarget = patchTargets[prop];
|
|
|
|
var originalDescriptor = originalDescriptors[prop];
|
|
|
|
var patchedDescriptor =
|
|
|
|
Object.getOwnPropertyDescriptor(patchTarget, prop);
|
|
|
|
|
|
|
|
window[patchMethod] = function() {
|
|
|
|
Object.defineProperty(patchTarget, prop, patchedDescriptor);
|
|
|
|
};
|
|
|
|
window[restoreMethod] = function() {
|
|
|
|
Object.defineProperty(patchTarget, prop, originalDescriptor);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Restore `prop`. The patch will be manually applied only during the
|
|
|
|
// `@angular/elements` tests that need it.
|
|
|
|
window[restoreMethod]();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2018-02-28 12:45:11 -05:00
|
|
|
|
|
|
|
return loadedPromise;
|
|
|
|
}
|
|
|
|
|
2014-10-06 20:35:00 -04:00
|
|
|
function onlySpecFiles(path) {
|
|
|
|
return /_spec\.js$/.test(path);
|
|
|
|
}
|