@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
JavaScript
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