UNPKG

@terminus/ngx-tools

Version:

[![CircleCI][circle-badge]][circle-link] [![codecov][codecov-badge]][codecov-project] [![semantic-release][semantic-release-badge]][semantic-release] [![MIT License][license-image]][license-url] <br> [![NPM version][npm-version-image]][npm-url] [![Github

457 lines (433 loc) 13.8 kB
import { __decorate, __awaiter } from 'tslib'; import { Injectable } from '@angular/core'; import { noop } from '@terminus/ngx-tools/utilities'; import { TestBed, async } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; /** * A mock of the Angular ChangeDetectorRefMock class */ let ChangeDetectorRefMock = class ChangeDetectorRefMock { constructor() { this.markForCheck = noop; this.detach = noop; this.detectChanges = noop; this.checkNoChanges = noop; this.reattach = noop; } }; ChangeDetectorRefMock = __decorate([ Injectable() ], ChangeDetectorRefMock); /** * Default stubbed items for `nativeElement` */ const defaults = { innerText: 'foo', style: {}, classList: { add: noop, remove: noop, }, }; /** * A mock of the Angular ElementRef class */ class ElementRefMock { constructor(nativeElementAdditions) { this.nativeElement = Object.assign(Object.assign({}, defaults), nativeElementAdditions || {}); } } /** * A mock of the Angular Renderer */ const rendererMock = { setElementStyle: noop, setElementClass: noop, selectRootElement: noop, createElement: noop, createViewRoot: noop, createText: noop, setElementProperty: noop, setElementAttribute: noop, setText: noop, setBindingDebugInfo: noop, createTemplateAnchor: noop, projectNodes: noop, attachViewAfter: noop, detachView: noop, destroyView: noop, listen: noop, listenGlobal: noop, invokeElementMethod: noop, animate: noop, }; /** * A mock of the Angular Renderer2 */ class Renderer2Mock { addClass() { } appendChild() { } createComment() { } set data(v) { this._data = v; } get data() { return this._data; } destroy() { } destroyNode() { } insertBefore() { } nextSibling() { } parentNode() { } removeAttribute() { } removeChild() { } removeClass() { } removeStyle() { } setAttribute() { } setProperty() { } setStyle() { } setValue() { } animate() { } attachViewAfter() { } createElement() { } createTemplateAnchor() { } createText() { } createViewRoot() { } destroyView() { } detachView() { } invokeElementMethod() { } listen() { return noop; } listenGlobal() { return noop; } projectNodes() { } selectRootElement() { } setBindingDebugInfo() { } setElementAttribute() { } setElementClass() { } setElementProperty() { } setElementStyle() { } setText() { } } /** * Create an instance of the TestBed and compile components * * @param configureFn - The configuration function for the TestBed * @param compilerOptions * @returns A promise-wrapped TestBed instance */ function configureTestBedWhitespace(configureFn, compilerOptions = {}) { const compilerConfig = Object.assign({ preserveWhitespaces: false }, compilerOptions); const configuredTestBed = TestBed.configureCompiler(compilerConfig); configureFn(configuredTestBed); return configuredTestBed.compileComponents().then(() => configuredTestBed); } /** * Set up the TestBed without resetting the TestBed for every test * * https://github.com/angular/angular/issues/12409 * * @param moduleDef - The module definition */ function configureTestBedWithoutReset(moduleDef) { const resetTestingModule = TestBed.resetTestingModule; const preventAngularFromResetting = () => { TestBed.resetTestingModule = () => TestBed; return TestBed.resetTestingModule; }; const allowAngularToReset = () => { TestBed.resetTestingModule = resetTestingModule; return TestBed.resetTestingModule; }; // eslint-disable-next-line no-undef beforeAll(async(function () { return __awaiter(this, void 0, void 0, function* () { resetTestingModule(); preventAngularFromResetting(); TestBed.configureTestingModule(moduleDef); yield TestBed.compileComponents(); }); })); // eslint-disable-next-line no-undef afterAll(() => allowAngularToReset()); } /** * Create a TestBed fixture with a single component registered * * @param component - The test component * @param providers - Any providers to register to the test module * @param imports - Any items to import to the test module * @returns The test fixture * * @example * const myComponent = createComponent(MyComponent); * const myComponent = createComponent(MyComponent, MyProviders, MyImports); */ function createComponent(component, providers = [], // eslint-disable-next-line @typescript-eslint/no-explicit-any imports = []) { TestBed.configureTestingModule({ imports: [ ...imports, ], declarations: [component], providers: [ ...providers, ], }).compileComponents(); return TestBed.createComponent(component); } /** * Creates a fake event object with any desired event type. * * @param type - The event type * @param canBubble - Define if the event can bubble up the DOM * @param cancelable * @returns The event * * @example * createFakeEvent('focus'); * createFakeEvent('focus', false, false); */ function createFakeEvent(type, canBubble = true, cancelable = true) { const event = document.createEvent('Event'); event.initEvent(type, canBubble, cancelable); return event; } /** * Dispatches a keydown event from an element. * * @param type - The event type * @param key - The KeyCode type * @param target - The target element * @returns The event * * @example * createKeyboardEvent('keydown', ENTER, myInputNativeElement); */ function createKeyboardEvent(type, key, target) { // NOTE: Cannot 'type' the event here due to the note about FireFox below // eslint-disable-next-line @typescript-eslint/no-explicit-any const event = document.createEvent('KeyboardEvent'); event.initEvent(type, true, false); const originalPreventDefault = event.preventDefault; // NOTE: Webkit Browsers don't set the keyCode when calling the init function. // See related bug https://bugs.webkit.org/show_bug.cgi?id=16735 Object.defineProperties(event, { code: { get: () => key.code }, key: { get: () => key.code }, keyCode: { get: () => key.keyCode }, target: { get: () => target }, }); // NOTE: IE won't set `defaultPrevented` on synthetic events so we need to do it manually. event.preventDefault = function () { Object.defineProperty(event, 'defaultPrevented', { get: () => true }); // FIXME: Not sure why this `as any` is needed now // eslint-disable-next-line @typescript-eslint/no-explicit-any return originalPreventDefault.apply(this, arguments); }; return event; } /** * Create a browser MouseEvent with the specified options * * @param type - The event type * @param x - The location on the X axis * @param y - The location on the Y axis * @returns The event * * @example * createMouseEvent('click'); * createMouseEvent('click', 212, 433); */ function createMouseEvent(type, x = 0, y = 0) { const event = document.createEvent('MouseEvent'); /* eslint-disable line-comment-position */ event.initMouseEvent(type, false, // canBubble false, // cancelable window, // view 0, // detail x, // screenX y, // screenY x, // clientX y, // clientY false, // ctrlKey false, // altKey false, // shiftKey false, // metaKey 0, // button null); /* eslint-enable line-comment-position */ return event; } /** * Creates a browser TouchEvent with the specified pointer coordinates. * * @param type - The touch event type * @param pageX - The location on the X axis * @param pageY - The location on the Y axis * * @example * createTouchEvent('touchstart'); * createTouchEvent('touchstart', 212, 433); */ function createTouchEvent(type, pageX = 0, pageY = 0) { // NOTE: 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. const event = document.createEvent('UIEvent'); const touchDetails = { pageX, pageY, }; event.initEvent(type, true, true); // NOTE: Most of the browsers don't have a "initTouchEvent" method that can be used to define the touch details. Object.defineProperties(event, { touches: { value: [touchDetails] } }); return event; } /** * Utility to dispatch any event on a Node. * * @param node - The Node that should dispatch the event * @param event - The event to be dispatched * @returns The dispatched event * * @example * dispatchEvent(myNativeElement, 'blur'); */ function dispatchEvent(node, event) { node.dispatchEvent(event); return event; } /** * Shorthand to dispatch a fake event on a specified node. * * @param node - The Node that should dispatch the fake event * @param type - The event type * @param canBubble - Define if the event can bubble up the DOM * @returns The event * * @example * dispatchFakeEvent(myNativeElement, 'mousedown'); * dispatchFakeEvent(myNativeElement, 'mousedown', true); */ const dispatchFakeEvent = (node, type, canBubble) => dispatchEvent(node, createFakeEvent(type, canBubble)); /** * Shorthand to dispatch a keyboard event with a specified key code * * @param node - The Node that should dispatch the keyboard event * @param type - The event type * @param key - The KeycodesConst type (contains code and keyCode) * @param target - The target event element * @returns The keyboard event * * @example * dispatchKeyboardEvent(myNativeElement, 'keyup', ENTER); * dispatchKeyboardEvent(myNativeElement, 'keyup', ENTER, myTargetElement); */ const dispatchKeyboardEvent = (node, type, key, target) => dispatchEvent(node, createKeyboardEvent(type, key, target)); /** * Shorthand to dispatch a mouse event on the specified coordinates. * * @param node - The Node that should dispatch the mouse event * @param type - The event type * @param x - The location on the X axis * @param y - The location on the Y axis * @param event - The event * @returns The mouse event * * @example * dispatchMouseEvent(myNativeElement, 'mousedown'); * dispatchMouseEvent(myNativeElement, 'mousedown', 10, 10, myCustomEvent); */ const dispatchMouseEvent = (node, type, x = 0, y = 0, event = createMouseEvent(type, x, y)) => dispatchEvent(node, event); /** * Shorthand to dispatch a touch event on the specified coordinates. * * @param node - The Node that should dispatch the touch event * @param type - The event type * @param x - The location on the X axis * @param y - The location on the Y axis * @returns The touch event * * @example * dispatchTouchEvent(myNativeElement, 'touchstart'); * dispatchTouchEvent(myNativeElement, 'touchstart', 10, 10); */ const dispatchTouchEvent = (node, type, x = 0, y = 0) => dispatchEvent(node, createTouchEvent(type, x, y)); /** * Reusable expect statement to check for the nativeElement * * NOTE: This helper only accesses the 1st-level child within a component. * * @param fixture - The test fixture * @returns expect statement * * @example * test('My test', () => { * expectNativeEl(myEl); * }); */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function expectNativeEl(fixture) { fixture.detectChanges(); // eslint-disable-next-line no-undef return expect(fixture.debugElement.children[0].nativeElement); } /** * Return a component's instance from within a ComponentFixture * * @param fixture - The component fixture * @param component - The component to find * @returns The instance of the found component * * @example * const myItem = getChildComponentInstanceFromFixture(myFixture, MyComponent); */ function getChildComponentInstanceFromFixture(fixture, component) { const debugElForDumbComponent = fixture.debugElement.query(By.directive(component)); return debugElForDumbComponent.injector.get(component); } /** * Helper to query a fixture for a selector * * @param fixture - The test fixture * @param selector - The selector to query for * @returns The query result * * @example * const myItem = queryFor(myFixture, '.my-class'); */ const queryFor = (fixture, selector) => fixture.debugElement.query(By.css(selector)); /** * Focuses an input, sets it's value and dispatches the `input` event, simulating the user typing. * * @param value - Value to be set on the input. * @param element - Element onto which to set the value. * * @example * typeInElement('test@test.com', myEmailInputElement); */ function typeInElement(value, element) { element.focus(); element.value = value; dispatchFakeEvent(element, 'input'); } /** * Gets a RegExp used to detect an angular wrapped error message. * * See https://github.com/angular/angular/issues/8348 * * @param e - The error * @returns The regex */ function wrappedErrorMessage(e) { const escapedMessage = e.message.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); return new RegExp(escapedMessage); } /** * Generated bundle index. Do not edit. */ export { ChangeDetectorRefMock, ElementRefMock, Renderer2Mock, configureTestBedWhitespace, configureTestBedWithoutReset, createComponent, createFakeEvent, createKeyboardEvent, createMouseEvent, createTouchEvent, dispatchEvent, dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent, dispatchTouchEvent, expectNativeEl, getChildComponentInstanceFromFixture, queryFor, rendererMock, typeInElement, wrappedErrorMessage }; //# sourceMappingURL=terminus-ngx-tools-testing.js.map