| (function (global, factory) { |
| typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/cdk/testing'), require('@angular/core/testing'), require('rxjs/operators'), require('rxjs'), require('@angular/cdk/keycodes')) : |
| typeof define === 'function' && define.amd ? define('@angular/cdk/testing/testbed', ['exports', '@angular/cdk/testing', '@angular/core/testing', 'rxjs/operators', 'rxjs', '@angular/cdk/keycodes'], factory) : |
| (global = global || self, factory((global.ng = global.ng || {}, global.ng.cdk = global.ng.cdk || {}, global.ng.cdk.testing = global.ng.cdk.testing || {}, global.ng.cdk.testing.testbed = {}), global.ng.cdk.testing, global.ng.core.testing, global.rxjs.operators, global.rxjs, global.ng.cdk.keycodes)); |
| }(this, (function (exports, testing, testing$1, operators, rxjs, keyCodes) { 'use strict'; |
| |
| /*! ***************************************************************************** |
| Copyright (c) Microsoft Corporation. |
| |
| Permission to use, copy, modify, and/or distribute this software for any |
| purpose with or without fee is hereby granted. |
| |
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH |
| REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
| AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, |
| INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
| LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR |
| OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| PERFORMANCE OF THIS SOFTWARE. |
| ***************************************************************************** */ |
| /* global Reflect, Promise */ |
| var extendStatics = function (d, b) { |
| extendStatics = Object.setPrototypeOf || |
| ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || |
| function (d, b) { for (var p in b) |
| if (Object.prototype.hasOwnProperty.call(b, p)) |
| d[p] = b[p]; }; |
| return extendStatics(d, b); |
| }; |
| function __extends(d, b) { |
| if (typeof b !== "function" && b !== null) |
| throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); |
| extendStatics(d, b); |
| function __() { this.constructor = d; } |
| d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); |
| } |
| var __assign = function () { |
| __assign = Object.assign || function __assign(t) { |
| for (var s, i = 1, n = arguments.length; i < n; i++) { |
| s = arguments[i]; |
| for (var p in s) |
| if (Object.prototype.hasOwnProperty.call(s, p)) |
| t[p] = s[p]; |
| } |
| return t; |
| }; |
| return __assign.apply(this, arguments); |
| }; |
| function __rest(s, e) { |
| var t = {}; |
| for (var p in s) |
| if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) |
| t[p] = s[p]; |
| if (s != null && typeof Object.getOwnPropertySymbols === "function") |
| for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { |
| if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) |
| t[p[i]] = s[p[i]]; |
| } |
| return t; |
| } |
| function __decorate(decorators, target, key, desc) { |
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; |
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") |
| r = Reflect.decorate(decorators, target, key, desc); |
| else |
| for (var i = decorators.length - 1; i >= 0; i--) |
| if (d = decorators[i]) |
| r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; |
| return c > 3 && r && Object.defineProperty(target, key, r), r; |
| } |
| function __param(paramIndex, decorator) { |
| return function (target, key) { decorator(target, key, paramIndex); }; |
| } |
| function __metadata(metadataKey, metadataValue) { |
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") |
| return Reflect.metadata(metadataKey, metadataValue); |
| } |
| function __awaiter(thisArg, _arguments, P, generator) { |
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } |
| return new (P || (P = Promise))(function (resolve, reject) { |
| function fulfilled(value) { try { |
| step(generator.next(value)); |
| } |
| catch (e) { |
| reject(e); |
| } } |
| function rejected(value) { try { |
| step(generator["throw"](value)); |
| } |
| catch (e) { |
| reject(e); |
| } } |
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } |
| step((generator = generator.apply(thisArg, _arguments || [])).next()); |
| }); |
| } |
| function __generator(thisArg, body) { |
| var _ = { label: 0, sent: function () { if (t[0] & 1) |
| throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; |
| return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g; |
| function verb(n) { return function (v) { return step([n, v]); }; } |
| function step(op) { |
| if (f) |
| throw new TypeError("Generator is already executing."); |
| while (_) |
| try { |
| if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) |
| return t; |
| if (y = 0, t) |
| op = [op[0] & 2, t.value]; |
| switch (op[0]) { |
| case 0: |
| case 1: |
| t = op; |
| break; |
| case 4: |
| _.label++; |
| return { value: op[1], done: false }; |
| case 5: |
| _.label++; |
| y = op[1]; |
| op = [0]; |
| continue; |
| case 7: |
| op = _.ops.pop(); |
| _.trys.pop(); |
| continue; |
| default: |
| if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { |
| _ = 0; |
| continue; |
| } |
| if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { |
| _.label = op[1]; |
| break; |
| } |
| if (op[0] === 6 && _.label < t[1]) { |
| _.label = t[1]; |
| t = op; |
| break; |
| } |
| if (t && _.label < t[2]) { |
| _.label = t[2]; |
| _.ops.push(op); |
| break; |
| } |
| if (t[2]) |
| _.ops.pop(); |
| _.trys.pop(); |
| continue; |
| } |
| op = body.call(thisArg, _); |
| } |
| catch (e) { |
| op = [6, e]; |
| y = 0; |
| } |
| finally { |
| f = t = 0; |
| } |
| if (op[0] & 5) |
| throw op[1]; |
| return { value: op[0] ? op[1] : void 0, done: true }; |
| } |
| } |
| var __createBinding = Object.create ? (function (o, m, k, k2) { |
| if (k2 === undefined) |
| k2 = k; |
| Object.defineProperty(o, k2, { enumerable: true, get: function () { return m[k]; } }); |
| }) : (function (o, m, k, k2) { |
| if (k2 === undefined) |
| k2 = k; |
| o[k2] = m[k]; |
| }); |
| function __exportStar(m, o) { |
| for (var p in m) |
| if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) |
| __createBinding(o, m, p); |
| } |
| function __values(o) { |
| var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; |
| if (m) |
| return m.call(o); |
| if (o && typeof o.length === "number") |
| return { |
| next: function () { |
| if (o && i >= o.length) |
| o = void 0; |
| return { value: o && o[i++], done: !o }; |
| } |
| }; |
| throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); |
| } |
| function __read(o, n) { |
| var m = typeof Symbol === "function" && o[Symbol.iterator]; |
| if (!m) |
| return o; |
| var i = m.call(o), r, ar = [], e; |
| try { |
| while ((n === void 0 || n-- > 0) && !(r = i.next()).done) |
| ar.push(r.value); |
| } |
| catch (error) { |
| e = { error: error }; |
| } |
| finally { |
| try { |
| if (r && !r.done && (m = i["return"])) |
| m.call(i); |
| } |
| finally { |
| if (e) |
| throw e.error; |
| } |
| } |
| return ar; |
| } |
| /** @deprecated */ |
| function __spread() { |
| for (var ar = [], i = 0; i < arguments.length; i++) |
| ar = ar.concat(__read(arguments[i])); |
| return ar; |
| } |
| /** @deprecated */ |
| function __spreadArrays() { |
| for (var s = 0, i = 0, il = arguments.length; i < il; i++) |
| s += arguments[i].length; |
| for (var r = Array(s), k = 0, i = 0; i < il; i++) |
| for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) |
| r[k] = a[j]; |
| return r; |
| } |
| function __spreadArray(to, from) { |
| for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) |
| to[j] = from[i]; |
| return to; |
| } |
| function __await(v) { |
| return this instanceof __await ? (this.v = v, this) : new __await(v); |
| } |
| function __asyncGenerator(thisArg, _arguments, generator) { |
| if (!Symbol.asyncIterator) |
| throw new TypeError("Symbol.asyncIterator is not defined."); |
| var g = generator.apply(thisArg, _arguments || []), i, q = []; |
| return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; |
| function verb(n) { if (g[n]) |
| i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } |
| function resume(n, v) { try { |
| step(g[n](v)); |
| } |
| catch (e) { |
| settle(q[0][3], e); |
| } } |
| function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } |
| function fulfill(value) { resume("next", value); } |
| function reject(value) { resume("throw", value); } |
| function settle(f, v) { if (f(v), q.shift(), q.length) |
| resume(q[0][0], q[0][1]); } |
| } |
| function __asyncDelegator(o) { |
| var i, p; |
| return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; |
| function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } |
| } |
| function __asyncValues(o) { |
| if (!Symbol.asyncIterator) |
| throw new TypeError("Symbol.asyncIterator is not defined."); |
| var m = o[Symbol.asyncIterator], i; |
| return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); |
| function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } |
| function settle(resolve, reject, d, v) { Promise.resolve(v).then(function (v) { resolve({ value: v, done: d }); }, reject); } |
| } |
| function __makeTemplateObject(cooked, raw) { |
| if (Object.defineProperty) { |
| Object.defineProperty(cooked, "raw", { value: raw }); |
| } |
| else { |
| cooked.raw = raw; |
| } |
| return cooked; |
| } |
| ; |
| var __setModuleDefault = Object.create ? (function (o, v) { |
| Object.defineProperty(o, "default", { enumerable: true, value: v }); |
| }) : function (o, v) { |
| o["default"] = v; |
| }; |
| function __importStar(mod) { |
| if (mod && mod.__esModule) |
| return mod; |
| var result = {}; |
| if (mod != null) |
| for (var k in mod) |
| if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) |
| __createBinding(result, mod, k); |
| __setModuleDefault(result, mod); |
| return result; |
| } |
| function __importDefault(mod) { |
| return (mod && mod.__esModule) ? mod : { default: mod }; |
| } |
| function __classPrivateFieldGet(receiver, privateMap) { |
| if (!privateMap.has(receiver)) { |
| throw new TypeError("attempted to get private field on non-instance"); |
| } |
| return privateMap.get(receiver); |
| } |
| function __classPrivateFieldSet(receiver, privateMap, value) { |
| if (!privateMap.has(receiver)) { |
| throw new TypeError("attempted to set private field on non-instance"); |
| } |
| privateMap.set(receiver, value); |
| return value; |
| } |
| |
| /** Unique symbol that is used to patch a property to a proxy zone. */ |
| var stateObservableSymbol = Symbol('ProxyZone_PATCHED#stateObservable'); |
| /** |
| * Interceptor that can be set up in a `ProxyZone` instance. The interceptor |
| * will keep track of the task state and emit whenever the state changes. |
| * |
| * This serves as a workaround for https://github.com/angular/angular/issues/32896. |
| */ |
| var TaskStateZoneInterceptor = /** @class */ (function () { |
| function TaskStateZoneInterceptor(_lastState) { |
| this._lastState = _lastState; |
| /** Subject that can be used to emit a new state change. */ |
| this._stateSubject = new rxjs.BehaviorSubject(this._lastState ? this._getTaskStateFromInternalZoneState(this._lastState) : { stable: true }); |
| /** Public observable that emits whenever the task state changes. */ |
| this.state = this._stateSubject; |
| } |
| /** This will be called whenever the task state changes in the intercepted zone. */ |
| TaskStateZoneInterceptor.prototype.onHasTask = function (delegate, current, target, hasTaskState) { |
| if (current === target) { |
| this._stateSubject.next(this._getTaskStateFromInternalZoneState(hasTaskState)); |
| } |
| }; |
| /** Gets the task state from the internal ZoneJS task state. */ |
| TaskStateZoneInterceptor.prototype._getTaskStateFromInternalZoneState = function (state) { |
| return { stable: !state.macroTask && !state.microTask }; |
| }; |
| /** |
| * Sets up the custom task state Zone interceptor in the `ProxyZone`. Throws if |
| * no `ProxyZone` could be found. |
| * @returns an observable that emits whenever the task state changes. |
| */ |
| TaskStateZoneInterceptor.setup = function () { |
| if (Zone === undefined) { |
| throw Error('Could not find ZoneJS. For test harnesses running in TestBed, ' + |
| 'ZoneJS needs to be installed.'); |
| } |
| // tslint:disable-next-line:variable-name |
| var ProxyZoneSpec = Zone['ProxyZoneSpec']; |
| // If there is no "ProxyZoneSpec" installed, we throw an error and recommend |
| // setting up the proxy zone by pulling in the testing bundle. |
| if (!ProxyZoneSpec) { |
| throw Error('ProxyZoneSpec is needed for the test harnesses but could not be found. ' + |
| 'Please make sure that your environment includes zone.js/dist/zone-testing.js'); |
| } |
| // Ensure that there is a proxy zone instance set up, and get |
| // a reference to the instance if present. |
| var zoneSpec = ProxyZoneSpec.assertPresent(); |
| // If there already is a delegate registered in the proxy zone, and it |
| // is type of the custom task state interceptor, we just use that state |
| // observable. This allows us to only intercept Zone once per test |
| // (similar to how `fakeAsync` or `async` work). |
| if (zoneSpec[stateObservableSymbol]) { |
| return zoneSpec[stateObservableSymbol]; |
| } |
| // Since we intercept on environment creation and the fixture has been |
| // created before, we might have missed tasks scheduled before. Fortunately |
| // the proxy zone keeps track of the previous task state, so we can just pass |
| // this as initial state to the task zone interceptor. |
| var interceptor = new TaskStateZoneInterceptor(zoneSpec.lastTaskState); |
| var zoneSpecOnHasTask = zoneSpec.onHasTask.bind(zoneSpec); |
| // We setup the task state interceptor in the `ProxyZone`. Note that we cannot register |
| // the interceptor as a new proxy zone delegate because it would mean that other zone |
| // delegates (e.g. `FakeAsyncTestZone` or `AsyncTestZone`) can accidentally overwrite/disable |
| // our interceptor. Since we just intend to monitor the task state of the proxy zone, it is |
| // sufficient to just patch the proxy zone. This also avoids that we interfere with the task |
| // queue scheduling logic. |
| zoneSpec.onHasTask = function () { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| zoneSpecOnHasTask.apply(void 0, __spread(args)); |
| interceptor.onHasTask.apply(interceptor, __spread(args)); |
| }; |
| return zoneSpec[stateObservableSymbol] = interceptor.state; |
| }; |
| return TaskStateZoneInterceptor; |
| }()); |
| |
| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| /** |
| * Creates a browser MouseEvent with the specified options. |
| * @docs-private |
| */ |
| function createMouseEvent(type, clientX, clientY, button, modifiers) { |
| if (clientX === void 0) { clientX = 0; } |
| if (clientY === void 0) { clientY = 0; } |
| if (button === void 0) { button = 0; } |
| if (modifiers === void 0) { modifiers = {}; } |
| var event = document.createEvent('MouseEvent'); |
| var originalPreventDefault = event.preventDefault.bind(event); |
| // Note: We cannot determine the position of the mouse event based on the screen |
| // because the dimensions and position of the browser window are not available |
| // To provide reasonable `screenX` and `screenY` coordinates, we simply use the |
| // client coordinates as if the browser is opened in fullscreen. |
| var screenX = clientX; |
| var screenY = clientY; |
| event.initMouseEvent(type, |
| /* canBubble */ true, |
| /* cancelable */ true, |
| /* view */ window, |
| /* detail */ 0, |
| /* screenX */ screenX, |
| /* screenY */ screenY, |
| /* clientX */ clientX, |
| /* clientY */ clientY, |
| /* ctrlKey */ !!modifiers.control, |
| /* altKey */ !!modifiers.alt, |
| /* shiftKey */ !!modifiers.shift, |
| /* metaKey */ !!modifiers.meta, |
| /* button */ button, |
| /* relatedTarget */ null); |
| // `initMouseEvent` doesn't allow us to pass the `buttons` and |
| // defaults it to 0 which looks like a fake event. |
| defineReadonlyEventProperty(event, 'buttons', 1); |
| // IE won't set `defaultPrevented` on synthetic events so we need to do it manually. |
| event.preventDefault = function () { |
| defineReadonlyEventProperty(event, 'defaultPrevented', true); |
| return originalPreventDefault(); |
| }; |
| return event; |
| } |
| /** |
| * Creates a browser `PointerEvent` with the specified options. Pointer events |
| * by default will appear as if they are the primary pointer of their type. |
| * https://www.w3.org/TR/pointerevents2/#dom-pointerevent-isprimary. |
| * |
| * For example, if pointer events for a multi-touch interaction are created, the non-primary |
| * pointer touches would need to be represented by non-primary pointer events. |
| * |
| * @docs-private |
| */ |
| function createPointerEvent(type, clientX, clientY, options) { |
| if (clientX === void 0) { clientX = 0; } |
| if (clientY === void 0) { clientY = 0; } |
| if (options === void 0) { options = { isPrimary: true }; } |
| return new PointerEvent(type, Object.assign({ bubbles: true, cancelable: true, view: window, clientX: clientX, |
| clientY: clientY }, options)); |
| } |
| /** |
| * Creates a browser TouchEvent with the specified pointer coordinates. |
| * @docs-private |
| */ |
| function createTouchEvent(type, pageX, pageY) { |
| if (pageX === void 0) { pageX = 0; } |
| if (pageY === void 0) { pageY = 0; } |
| // In favor of creating events that work for most of the browsers, the event is created |
| // as a basic UI Event. The necessary details for the event will be set manually. |
| var event = document.createEvent('UIEvent'); |
| var touchDetails = { pageX: pageX, pageY: pageY }; |
| // TS3.6 removes the initUIEvent method and suggests porting to "new UIEvent()". |
| event.initUIEvent(type, true, true, window, 0); |
| // Most of the browsers don't have a "initTouchEvent" method that can be used to define |
| // the touch details. |
| defineReadonlyEventProperty(event, 'touches', [touchDetails]); |
| defineReadonlyEventProperty(event, 'targetTouches', [touchDetails]); |
| defineReadonlyEventProperty(event, 'changedTouches', [touchDetails]); |
| return event; |
| } |
| /** |
| * Creates a keyboard event with the specified key and modifiers. |
| * @docs-private |
| */ |
| function createKeyboardEvent(type, keyCode, key, modifiers) { |
| if (keyCode === void 0) { keyCode = 0; } |
| if (key === void 0) { key = ''; } |
| if (modifiers === void 0) { modifiers = {}; } |
| var event = document.createEvent('KeyboardEvent'); |
| var originalPreventDefault = event.preventDefault.bind(event); |
| // Firefox does not support `initKeyboardEvent`, but supports `initKeyEvent`. |
| // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/initKeyEvent. |
| if (event.initKeyEvent !== undefined) { |
| event.initKeyEvent(type, true, true, window, modifiers.control, modifiers.alt, modifiers.shift, modifiers.meta, keyCode); |
| } |
| else { |
| // `initKeyboardEvent` expects to receive modifiers as a whitespace-delimited string |
| // See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/initKeyboardEvent |
| var modifiersList = ''; |
| if (modifiers.control) { |
| modifiersList += 'Control '; |
| } |
| if (modifiers.alt) { |
| modifiersList += 'Alt '; |
| } |
| if (modifiers.shift) { |
| modifiersList += 'Shift '; |
| } |
| if (modifiers.meta) { |
| modifiersList += 'Meta '; |
| } |
| // TS3.6 removed the `initKeyboardEvent` method and suggested porting to |
| // `new KeyboardEvent()` constructor. We cannot use that as we support IE11. |
| // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/initKeyboardEvent. |
| event.initKeyboardEvent(type, true, /* canBubble */ true, /* cancelable */ window, /* view */ 0, /* char */ key, /* key */ 0, /* location */ modifiersList.trim(), /* modifiersList */ false /* repeat */); |
| } |
| // Webkit Browsers don't set the keyCode when calling the init function. |
| // See related bug https://bugs.webkit.org/show_bug.cgi?id=16735 |
| defineReadonlyEventProperty(event, 'keyCode', keyCode); |
| defineReadonlyEventProperty(event, 'key', key); |
| defineReadonlyEventProperty(event, 'ctrlKey', !!modifiers.control); |
| defineReadonlyEventProperty(event, 'altKey', !!modifiers.alt); |
| defineReadonlyEventProperty(event, 'shiftKey', !!modifiers.shift); |
| defineReadonlyEventProperty(event, 'metaKey', !!modifiers.meta); |
| // IE won't set `defaultPrevented` on synthetic events so we need to do it manually. |
| event.preventDefault = function () { |
| defineReadonlyEventProperty(event, 'defaultPrevented', true); |
| return originalPreventDefault(); |
| }; |
| return event; |
| } |
| /** |
| * Creates a fake event object with any desired event type. |
| * @docs-private |
| */ |
| function createFakeEvent(type, canBubble, cancelable) { |
| if (canBubble === void 0) { canBubble = false; } |
| if (cancelable === void 0) { cancelable = true; } |
| var event = document.createEvent('Event'); |
| event.initEvent(type, canBubble, cancelable); |
| return event; |
| } |
| /** |
| * Defines a readonly property on the given event object. Readonly properties on an event object |
| * are always set as configurable as that matches default readonly properties for DOM event objects. |
| */ |
| function defineReadonlyEventProperty(event, propertyName, value) { |
| Object.defineProperty(event, propertyName, { get: function () { return value; }, configurable: true }); |
| } |
| |
| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| /** |
| * Utility to dispatch any event on a Node. |
| * @docs-private |
| */ |
| function dispatchEvent(node, event) { |
| node.dispatchEvent(event); |
| return event; |
| } |
| /** |
| * Shorthand to dispatch a fake event on a specified node. |
| * @docs-private |
| */ |
| function dispatchFakeEvent(node, type, canBubble) { |
| return dispatchEvent(node, createFakeEvent(type, canBubble)); |
| } |
| /** |
| * Shorthand to dispatch a keyboard event with a specified key code and |
| * optional modifiers. |
| * @docs-private |
| */ |
| function dispatchKeyboardEvent(node, type, keyCode, key, modifiers) { |
| return dispatchEvent(node, createKeyboardEvent(type, keyCode, key, modifiers)); |
| } |
| /** |
| * Shorthand to dispatch a mouse event on the specified coordinates. |
| * @docs-private |
| */ |
| function dispatchMouseEvent(node, type, clientX, clientY, button, modifiers) { |
| if (clientX === void 0) { clientX = 0; } |
| if (clientY === void 0) { clientY = 0; } |
| return dispatchEvent(node, createMouseEvent(type, clientX, clientY, button, modifiers)); |
| } |
| /** |
| * Shorthand to dispatch a pointer event on the specified coordinates. |
| * @docs-private |
| */ |
| function dispatchPointerEvent(node, type, clientX, clientY, options) { |
| if (clientX === void 0) { clientX = 0; } |
| if (clientY === void 0) { clientY = 0; } |
| return dispatchEvent(node, createPointerEvent(type, clientX, clientY, options)); |
| } |
| /** |
| * Shorthand to dispatch a touch event on the specified coordinates. |
| * @docs-private |
| */ |
| function dispatchTouchEvent(node, type, x, y) { |
| if (x === void 0) { x = 0; } |
| if (y === void 0) { y = 0; } |
| return dispatchEvent(node, createTouchEvent(type, x, y)); |
| } |
| |
| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| function triggerFocusChange(element, event) { |
| var eventFired = false; |
| var handler = function () { return eventFired = true; }; |
| element.addEventListener(event, handler); |
| element[event](); |
| element.removeEventListener(event, handler); |
| if (!eventFired) { |
| dispatchFakeEvent(element, event); |
| } |
| } |
| /** |
| * Patches an elements focus and blur methods to emit events consistently and predictably. |
| * This is necessary, because some browsers, like IE11, will call the focus handlers asynchronously, |
| * while others won't fire them at all if the browser window is not focused. |
| * @docs-private |
| */ |
| function patchElementFocus(element) { |
| element.focus = function () { return dispatchFakeEvent(element, 'focus'); }; |
| element.blur = function () { return dispatchFakeEvent(element, 'blur'); }; |
| } |
| /** @docs-private */ |
| function triggerFocus(element) { |
| triggerFocusChange(element, 'focus'); |
| } |
| /** @docs-private */ |
| function triggerBlur(element) { |
| triggerFocusChange(element, 'blur'); |
| } |
| |
| /** Input types for which the value can be entered incrementally. */ |
| var incrementalInputTypes = new Set(['text', 'email', 'hidden', 'password', 'search', 'tel', 'url']); |
| /** |
| * Checks whether the given Element is a text input element. |
| * @docs-private |
| */ |
| function isTextInput(element) { |
| var nodeName = element.nodeName.toLowerCase(); |
| return nodeName === 'input' || nodeName === 'textarea'; |
| } |
| function typeInElement(element) { |
| var e_1, _a; |
| var modifiersAndKeys = []; |
| for (var _i = 1; _i < arguments.length; _i++) { |
| modifiersAndKeys[_i - 1] = arguments[_i]; |
| } |
| var first = modifiersAndKeys[0]; |
| var modifiers; |
| var rest; |
| if (typeof first !== 'string' && first.keyCode === undefined && first.key === undefined) { |
| modifiers = first; |
| rest = modifiersAndKeys.slice(1); |
| } |
| else { |
| modifiers = {}; |
| rest = modifiersAndKeys; |
| } |
| var isInput = isTextInput(element); |
| var inputType = element.getAttribute('type') || 'text'; |
| var keys = rest |
| .map(function (k) { return typeof k === 'string' ? |
| k.split('').map(function (c) { return ({ keyCode: c.toUpperCase().charCodeAt(0), key: c }); }) : [k]; }) |
| .reduce(function (arr, k) { return arr.concat(k); }, []); |
| // We simulate the user typing in a value by incrementally assigning the value below. The problem |
| // is that for some input types, the browser won't allow for an invalid value to be set via the |
| // `value` property which will always be the case when going character-by-character. If we detect |
| // such an input, we have to set the value all at once or listeners to the `input` event (e.g. |
| // the `ReactiveFormsModule` uses such an approach) won't receive the correct value. |
| var enterValueIncrementally = inputType === 'number' && keys.length > 0 ? |
| // The value can be set character by character in number inputs if it doesn't have any decimals. |
| keys.every(function (key) { return key.key !== '.' && key.keyCode !== keyCodes.PERIOD; }) : |
| incrementalInputTypes.has(inputType); |
| triggerFocus(element); |
| // When we aren't entering the value incrementally, assign it all at once ahead |
| // of time so that any listeners to the key events below will have access to it. |
| if (!enterValueIncrementally) { |
| element.value = keys.reduce(function (value, key) { return value + (key.key || ''); }, ''); |
| } |
| try { |
| for (var keys_1 = __values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) { |
| var key = keys_1_1.value; |
| dispatchKeyboardEvent(element, 'keydown', key.keyCode, key.key, modifiers); |
| dispatchKeyboardEvent(element, 'keypress', key.keyCode, key.key, modifiers); |
| if (isInput && key.key && key.key.length === 1) { |
| if (enterValueIncrementally) { |
| element.value += key.key; |
| dispatchFakeEvent(element, 'input'); |
| } |
| } |
| dispatchKeyboardEvent(element, 'keyup', key.keyCode, key.key, modifiers); |
| } |
| } |
| catch (e_1_1) { e_1 = { error: e_1_1 }; } |
| finally { |
| try { |
| if (keys_1_1 && !keys_1_1.done && (_a = keys_1.return)) _a.call(keys_1); |
| } |
| finally { if (e_1) throw e_1.error; } |
| } |
| // Since we weren't dispatching `input` events while sending the keys, we have to do it now. |
| if (!enterValueIncrementally) { |
| dispatchFakeEvent(element, 'input'); |
| } |
| } |
| /** |
| * Clears the text in an input or textarea element. |
| * @docs-private |
| */ |
| function clearElement(element) { |
| triggerFocus(element); |
| element.value = ''; |
| dispatchFakeEvent(element, 'input'); |
| } |
| |
| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| |
| var _a; |
| /** Maps `TestKey` constants to the `keyCode` and `key` values used by native browser events. */ |
| var keyMap = (_a = {}, |
| _a[testing.TestKey.BACKSPACE] = { keyCode: keyCodes.BACKSPACE, key: 'Backspace' }, |
| _a[testing.TestKey.TAB] = { keyCode: keyCodes.TAB, key: 'Tab' }, |
| _a[testing.TestKey.ENTER] = { keyCode: keyCodes.ENTER, key: 'Enter' }, |
| _a[testing.TestKey.SHIFT] = { keyCode: keyCodes.SHIFT, key: 'Shift' }, |
| _a[testing.TestKey.CONTROL] = { keyCode: keyCodes.CONTROL, key: 'Control' }, |
| _a[testing.TestKey.ALT] = { keyCode: keyCodes.ALT, key: 'Alt' }, |
| _a[testing.TestKey.ESCAPE] = { keyCode: keyCodes.ESCAPE, key: 'Escape' }, |
| _a[testing.TestKey.PAGE_UP] = { keyCode: keyCodes.PAGE_UP, key: 'PageUp' }, |
| _a[testing.TestKey.PAGE_DOWN] = { keyCode: keyCodes.PAGE_DOWN, key: 'PageDown' }, |
| _a[testing.TestKey.END] = { keyCode: keyCodes.END, key: 'End' }, |
| _a[testing.TestKey.HOME] = { keyCode: keyCodes.HOME, key: 'Home' }, |
| _a[testing.TestKey.LEFT_ARROW] = { keyCode: keyCodes.LEFT_ARROW, key: 'ArrowLeft' }, |
| _a[testing.TestKey.UP_ARROW] = { keyCode: keyCodes.UP_ARROW, key: 'ArrowUp' }, |
| _a[testing.TestKey.RIGHT_ARROW] = { keyCode: keyCodes.RIGHT_ARROW, key: 'ArrowRight' }, |
| _a[testing.TestKey.DOWN_ARROW] = { keyCode: keyCodes.DOWN_ARROW, key: 'ArrowDown' }, |
| _a[testing.TestKey.INSERT] = { keyCode: keyCodes.INSERT, key: 'Insert' }, |
| _a[testing.TestKey.DELETE] = { keyCode: keyCodes.DELETE, key: 'Delete' }, |
| _a[testing.TestKey.F1] = { keyCode: keyCodes.F1, key: 'F1' }, |
| _a[testing.TestKey.F2] = { keyCode: keyCodes.F2, key: 'F2' }, |
| _a[testing.TestKey.F3] = { keyCode: keyCodes.F3, key: 'F3' }, |
| _a[testing.TestKey.F4] = { keyCode: keyCodes.F4, key: 'F4' }, |
| _a[testing.TestKey.F5] = { keyCode: keyCodes.F5, key: 'F5' }, |
| _a[testing.TestKey.F6] = { keyCode: keyCodes.F6, key: 'F6' }, |
| _a[testing.TestKey.F7] = { keyCode: keyCodes.F7, key: 'F7' }, |
| _a[testing.TestKey.F8] = { keyCode: keyCodes.F8, key: 'F8' }, |
| _a[testing.TestKey.F9] = { keyCode: keyCodes.F9, key: 'F9' }, |
| _a[testing.TestKey.F10] = { keyCode: keyCodes.F10, key: 'F10' }, |
| _a[testing.TestKey.F11] = { keyCode: keyCodes.F11, key: 'F11' }, |
| _a[testing.TestKey.F12] = { keyCode: keyCodes.F12, key: 'F12' }, |
| _a[testing.TestKey.META] = { keyCode: keyCodes.META, key: 'Meta' }, |
| _a); |
| /** A `TestElement` implementation for unit tests. */ |
| var UnitTestElement = /** @class */ (function () { |
| function UnitTestElement(element, _stabilize) { |
| this.element = element; |
| this._stabilize = _stabilize; |
| } |
| UnitTestElement.prototype.blur = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| triggerBlur(this.element); |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.clear = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| if (!isTextInput(this.element)) { |
| throw Error('Attempting to clear an invalid element'); |
| } |
| clearElement(this.element); |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.click = function () { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._dispatchMouseEventSequence('click', args, 0)]; |
| case 1: |
| _a.sent(); |
| return [4 /*yield*/, this._stabilize()]; |
| case 2: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.rightClick = function () { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i] = arguments[_i]; |
| } |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._dispatchMouseEventSequence('contextmenu', args, 2)]; |
| case 1: |
| _a.sent(); |
| return [4 /*yield*/, this._stabilize()]; |
| case 2: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.focus = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| triggerFocus(this.element); |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.getCssValue = function (property) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| // TODO(mmalerba): Consider adding value normalization if we run into common cases where its |
| // needed. |
| return [2 /*return*/, getComputedStyle(this.element).getPropertyValue(property)]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.hover = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| this._dispatchPointerEventIfSupported('pointerenter'); |
| dispatchMouseEvent(this.element, 'mouseenter'); |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.mouseAway = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| this._dispatchPointerEventIfSupported('pointerleave'); |
| dispatchMouseEvent(this.element, 'mouseleave'); |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.sendKeys = function () { |
| var modifiersAndKeys = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| modifiersAndKeys[_i] = arguments[_i]; |
| } |
| return __awaiter(this, void 0, void 0, function () { |
| var args; |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| args = modifiersAndKeys.map(function (k) { return typeof k === 'number' ? keyMap[k] : k; }); |
| typeInElement.apply(void 0, __spread([this.element], args)); |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.text = function (options) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| if (options === null || options === void 0 ? void 0 : options.exclude) { |
| return [2 /*return*/, testing._getTextWithExcludedElements(this.element, options.exclude)]; |
| } |
| return [2 /*return*/, (this.element.textContent || '').trim()]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.getAttribute = function (name) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/, this.element.getAttribute(name)]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.hasClass = function (name) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/, this.element.classList.contains(name)]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.getDimensions = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/, this.element.getBoundingClientRect()]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.getProperty = function (name) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/, this.element[name]]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.setInputValue = function (value) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| this.element.value = value; |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.selectOptions = function () { |
| var optionIndexes = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| optionIndexes[_i] = arguments[_i]; |
| } |
| return __awaiter(this, void 0, void 0, function () { |
| var hasChanged, options, indexes, i, option, wasSelected; |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| hasChanged = false; |
| options = this.element.querySelectorAll('option'); |
| indexes = new Set(optionIndexes); |
| for (i = 0; i < options.length; i++) { |
| option = options[i]; |
| wasSelected = option.selected; |
| // We have to go through `option.selected`, because `HTMLSelectElement.value` doesn't |
| // allow for multiple options to be selected, even in `multiple` mode. |
| option.selected = indexes.has(i); |
| if (option.selected !== wasSelected) { |
| hasChanged = true; |
| dispatchFakeEvent(this.element, 'change'); |
| } |
| } |
| if (!hasChanged) return [3 /*break*/, 2]; |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| _a.label = 2; |
| case 2: return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.matchesSelector = function (selector) { |
| return __awaiter(this, void 0, void 0, function () { |
| var elementPrototype; |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| elementPrototype = Element.prototype; |
| return [2 /*return*/, (elementPrototype['matches'] || elementPrototype['msMatchesSelector']) |
| .call(this.element, selector)]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.isFocused = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/, document.activeElement === this.element]; |
| } |
| }); |
| }); |
| }; |
| UnitTestElement.prototype.dispatchEvent = function (name, data) { |
| return __awaiter(this, void 0, void 0, function () { |
| var event; |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| event = createFakeEvent(name); |
| if (data) { |
| // tslint:disable-next-line:ban Have to use `Object.assign` to preserve the original object. |
| Object.assign(event, data); |
| } |
| dispatchEvent(this.element, event); |
| return [4 /*yield*/, this._stabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| /** |
| * Dispatches a pointer event on the current element if the browser supports it. |
| * @param name Name of the pointer event to be dispatched. |
| * @param clientX Coordinate of the user's pointer along the X axis. |
| * @param clientY Coordinate of the user's pointer along the Y axis. |
| * @param button Mouse button that should be pressed when dispatching the event. |
| */ |
| UnitTestElement.prototype._dispatchPointerEventIfSupported = function (name, clientX, clientY, button) { |
| // The latest versions of all browsers we support have the new `PointerEvent` API. |
| // Though since we capture the two most recent versions of these browsers, we also |
| // need to support Safari 12 at time of writing. Safari 12 does not have support for this, |
| // so we need to conditionally create and dispatch these events based on feature detection. |
| if (typeof PointerEvent !== 'undefined' && PointerEvent) { |
| dispatchPointerEvent(this.element, name, clientX, clientY, { isPrimary: true, button: button }); |
| } |
| }; |
| /** Dispatches all the events that are part of a mouse event sequence. */ |
| UnitTestElement.prototype._dispatchMouseEventSequence = function (name, args, button) { |
| return __awaiter(this, void 0, void 0, function () { |
| var clientX, clientY, modifiers, _a, left, top, width, height, relativeX, relativeY; |
| return __generator(this, function (_b) { |
| switch (_b.label) { |
| case 0: |
| clientX = undefined; |
| clientY = undefined; |
| modifiers = {}; |
| if (args.length && typeof args[args.length - 1] === 'object') { |
| modifiers = args.pop(); |
| } |
| if (!args.length) return [3 /*break*/, 2]; |
| return [4 /*yield*/, this.getDimensions()]; |
| case 1: |
| _a = _b.sent(), left = _a.left, top = _a.top, width = _a.width, height = _a.height; |
| relativeX = args[0] === 'center' ? width / 2 : args[0]; |
| relativeY = args[0] === 'center' ? height / 2 : args[1]; |
| // Round the computed click position as decimal pixels are not |
| // supported by mouse events and could lead to unexpected results. |
| clientX = Math.round(left + relativeX); |
| clientY = Math.round(top + relativeY); |
| _b.label = 2; |
| case 2: |
| this._dispatchPointerEventIfSupported('pointerdown', clientX, clientY, button); |
| dispatchMouseEvent(this.element, 'mousedown', clientX, clientY, button, modifiers); |
| this._dispatchPointerEventIfSupported('pointerup', clientX, clientY, button); |
| dispatchMouseEvent(this.element, 'mouseup', clientX, clientY, button, modifiers); |
| dispatchMouseEvent(this.element, name, clientX, clientY, button, modifiers); |
| // This call to _stabilize should not be needed since the callers will already do that them- |
| // selves. Nevertheless it breaks some tests in g3 without it. It needs to be investigated |
| // why removing breaks those tests. |
| return [4 /*yield*/, this._stabilize()]; |
| case 3: |
| // This call to _stabilize should not be needed since the callers will already do that them- |
| // selves. Nevertheless it breaks some tests in g3 without it. It needs to be investigated |
| // why removing breaks those tests. |
| _b.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| return UnitTestElement; |
| }()); |
| |
| /** The default environment options. */ |
| var defaultEnvironmentOptions = { |
| queryFn: function (selector, root) { return root.querySelectorAll(selector); } |
| }; |
| /** Whether auto change detection is currently disabled. */ |
| var disableAutoChangeDetection = false; |
| /** |
| * The set of non-destroyed fixtures currently being used by `TestbedHarnessEnvironment` instances. |
| */ |
| var activeFixtures = new Set(); |
| /** |
| * Installs a handler for change detection batching status changes for a specific fixture. |
| * @param fixture The fixture to handle change detection batching for. |
| */ |
| function installAutoChangeDetectionStatusHandler(fixture) { |
| if (!activeFixtures.size) { |
| testing.handleAutoChangeDetectionStatus(function (_a) { |
| var isDisabled = _a.isDisabled, onDetectChangesNow = _a.onDetectChangesNow; |
| disableAutoChangeDetection = isDisabled; |
| if (onDetectChangesNow) { |
| Promise.all(Array.from(activeFixtures).map(detectChanges)).then(onDetectChangesNow); |
| } |
| }); |
| } |
| activeFixtures.add(fixture); |
| } |
| /** |
| * Uninstalls a handler for change detection batching status changes for a specific fixture. |
| * @param fixture The fixture to stop handling change detection batching for. |
| */ |
| function uninstallAutoChangeDetectionStatusHandler(fixture) { |
| activeFixtures.delete(fixture); |
| if (!activeFixtures.size) { |
| testing.stopHandlingAutoChangeDetectionStatus(); |
| } |
| } |
| /** Whether we are currently in the fake async zone. */ |
| function isInFakeAsyncZone() { |
| return Zone.current.get('FakeAsyncTestZoneSpec') != null; |
| } |
| /** |
| * Triggers change detection for a specific fixture. |
| * @param fixture The fixture to trigger change detection for. |
| */ |
| function detectChanges(fixture) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| fixture.detectChanges(); |
| if (!isInFakeAsyncZone()) return [3 /*break*/, 1]; |
| testing$1.flush(); |
| return [3 /*break*/, 3]; |
| case 1: return [4 /*yield*/, fixture.whenStable()]; |
| case 2: |
| _a.sent(); |
| _a.label = 3; |
| case 3: return [2 /*return*/]; |
| } |
| }); |
| }); |
| } |
| /** A `HarnessEnvironment` implementation for Angular's Testbed. */ |
| var TestbedHarnessEnvironment = /** @class */ (function (_super) { |
| __extends(TestbedHarnessEnvironment, _super); |
| function TestbedHarnessEnvironment(rawRootElement, _fixture, options) { |
| var _this = _super.call(this, rawRootElement) || this; |
| _this._fixture = _fixture; |
| /** Whether the environment has been destroyed. */ |
| _this._destroyed = false; |
| _this._options = Object.assign(Object.assign({}, defaultEnvironmentOptions), options); |
| _this._taskState = TaskStateZoneInterceptor.setup(); |
| installAutoChangeDetectionStatusHandler(_fixture); |
| _fixture.componentRef.onDestroy(function () { |
| uninstallAutoChangeDetectionStatusHandler(_fixture); |
| _this._destroyed = true; |
| }); |
| return _this; |
| } |
| /** Creates a `HarnessLoader` rooted at the given fixture's root element. */ |
| TestbedHarnessEnvironment.loader = function (fixture, options) { |
| return new TestbedHarnessEnvironment(fixture.nativeElement, fixture, options); |
| }; |
| /** |
| * Creates a `HarnessLoader` at the document root. This can be used if harnesses are |
| * located outside of a fixture (e.g. overlays appended to the document body). |
| */ |
| TestbedHarnessEnvironment.documentRootLoader = function (fixture, options) { |
| return new TestbedHarnessEnvironment(document.body, fixture, options); |
| }; |
| /** Gets the native DOM element corresponding to the given TestElement. */ |
| TestbedHarnessEnvironment.getNativeElement = function (el) { |
| if (el instanceof UnitTestElement) { |
| return el.element; |
| } |
| throw Error('This TestElement was not created by the TestbedHarnessEnvironment'); |
| }; |
| /** |
| * Creates an instance of the given harness type, using the fixture's root element as the |
| * harness's host element. This method should be used when creating a harness for the root element |
| * of a fixture, as components do not have the correct selector when they are created as the root |
| * of the fixture. |
| */ |
| TestbedHarnessEnvironment.harnessForFixture = function (fixture, harnessType, options) { |
| return __awaiter(this, void 0, void 0, function () { |
| var environment; |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| environment = new TestbedHarnessEnvironment(fixture.nativeElement, fixture, options); |
| return [4 /*yield*/, environment.forceStabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/, environment.createComponentHarness(harnessType, fixture.nativeElement)]; |
| } |
| }); |
| }); |
| }; |
| TestbedHarnessEnvironment.prototype.forceStabilize = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| if (!!disableAutoChangeDetection) return [3 /*break*/, 2]; |
| if (this._destroyed) { |
| throw Error('Harness is attempting to use a fixture that has already been destroyed.'); |
| } |
| return [4 /*yield*/, detectChanges(this._fixture)]; |
| case 1: |
| _a.sent(); |
| _a.label = 2; |
| case 2: return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| TestbedHarnessEnvironment.prototype.waitForTasksOutsideAngular = function () { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: |
| // If we run in the fake async zone, we run "flush" to run any scheduled tasks. This |
| // ensures that the harnesses behave inside of the FakeAsyncTestZone similar to the |
| // "AsyncTestZone" and the root zone (i.e. neither fakeAsync or async). Note that we |
| // cannot just rely on the task state observable to become stable because the state will |
| // never change. This is because the task queue will be only drained if the fake async |
| // zone is being flushed. |
| if (isInFakeAsyncZone()) { |
| testing$1.flush(); |
| } |
| // Wait until the task queue has been drained and the zone is stable. Note that |
| // we cannot rely on "fixture.whenStable" since it does not catch tasks scheduled |
| // outside of the Angular zone. For test harnesses, we want to ensure that the |
| // app is fully stabilized and therefore need to use our own zone interceptor. |
| return [4 /*yield*/, this._taskState.pipe(operators.takeWhile(function (state) { return !state.stable; })).toPromise()]; |
| case 1: |
| // Wait until the task queue has been drained and the zone is stable. Note that |
| // we cannot rely on "fixture.whenStable" since it does not catch tasks scheduled |
| // outside of the Angular zone. For test harnesses, we want to ensure that the |
| // app is fully stabilized and therefore need to use our own zone interceptor. |
| _a.sent(); |
| return [2 /*return*/]; |
| } |
| }); |
| }); |
| }; |
| TestbedHarnessEnvironment.prototype.getDocumentRoot = function () { |
| return document.body; |
| }; |
| TestbedHarnessEnvironment.prototype.createTestElement = function (element) { |
| var _this = this; |
| return new UnitTestElement(element, function () { return _this.forceStabilize(); }); |
| }; |
| TestbedHarnessEnvironment.prototype.createEnvironment = function (element) { |
| return new TestbedHarnessEnvironment(element, this._fixture, this._options); |
| }; |
| TestbedHarnessEnvironment.prototype.getAllRawElements = function (selector) { |
| return __awaiter(this, void 0, void 0, function () { |
| return __generator(this, function (_a) { |
| switch (_a.label) { |
| case 0: return [4 /*yield*/, this.forceStabilize()]; |
| case 1: |
| _a.sent(); |
| return [2 /*return*/, Array.from(this._options.queryFn(selector, this.rawRootElement))]; |
| } |
| }); |
| }); |
| }; |
| return TestbedHarnessEnvironment; |
| }(testing.HarnessEnvironment)); |
| |
| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| |
| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| |
| exports.TestbedHarnessEnvironment = TestbedHarnessEnvironment; |
| exports.UnitTestElement = UnitTestElement; |
| |
| Object.defineProperty(exports, '__esModule', { value: true }); |
| |
| }))); |
| //# sourceMappingURL=cdk-testing-testbed.umd.js.map |