Skip to content

Commit

Permalink
feat(#315): ngMocks.trigger and ngMocks.click
Browse files Browse the repository at this point in the history
  • Loading branch information
satanTime committed Mar 28, 2021
1 parent 93d5813 commit 50753bb
Show file tree
Hide file tree
Showing 13 changed files with 1,006 additions and 91 deletions.
152 changes: 77 additions & 75 deletions .github/workflows/ci.yaml

Large diffs are not rendered by default.

27 changes: 11 additions & 16 deletions libs/ng-mocks/src/lib/mock-helper/cva/mock-helper.change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,25 @@ import { DebugElement } from '@angular/core';

import coreForm from '../../common/core.form';
import { isMockControlValueAccessor } from '../../common/func.is-mock-control-value-accessor';
import mockHelperTrigger from '../events/mock-helper.trigger';
import mockHelperStubMember from '../mock-helper.stub-member';

import funcGetVca from './func.get-vca';

// default html behavior
const triggerInput = (el: DebugElement, value: any): void => {
const target = el.nativeElement;
el.triggerEventHandler('focus', {
target,
});

const descriptor = Object.getOwnPropertyDescriptor(target, 'value');
mockHelperStubMember(target, 'value', value);
el.triggerEventHandler('input', {
target,
});
mockHelperTrigger(el, 'focus');

const descriptor = Object.getOwnPropertyDescriptor(el.nativeElement, 'value');
mockHelperStubMember(el.nativeElement, 'value', value);
mockHelperTrigger(el, 'input');
mockHelperTrigger(el, 'change');
if (descriptor) {
Object.defineProperty(target, 'value', descriptor);
target.value = value;
Object.defineProperty(el.nativeElement, 'value', descriptor);
el.nativeElement.value = value;
}

el.triggerEventHandler('blur', {
target,
});
mockHelperTrigger(el, 'blur');
};

const handleKnown = (valueAccessor: any, value: any): boolean => {
Expand All @@ -51,7 +46,7 @@ const handleKnown = (valueAccessor: any, value: any): boolean => {
};

const hasListener = (el: DebugElement): boolean =>
el.listeners.filter(listener => listener.name === 'input').length > 0;
el.listeners.filter(listener => listener.name === 'input' || listener.name === 'change').length > 0;

const keys = ['onChange', '_onChange', 'changeFn', '_onChangeCallback', 'onModelChange'];

Expand Down
5 changes: 5 additions & 0 deletions libs/ng-mocks/src/lib/mock-helper/events/mock-helper.click.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import mockHelperTrigger from './mock-helper.trigger';

export default (selector: any, payload?: object) => {
mockHelperTrigger(selector, 'click', payload);
};
179 changes: 179 additions & 0 deletions libs/ng-mocks/src/lib/mock-helper/events/mock-helper.event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import mockHelperStub from '../mock-helper.stub';

/**
* @see https://developer.mozilla.org/de/docs/Web/Events
*/
const preventBubble = ['focus', 'blur', 'load', 'unload', 'change', 'reset', 'scroll'];

// istanbul ignore next
function customEvent(event: string, params?: EventInit) {
const initParams = {
bubbles: false,
cancelable: false,
...params,
};
const eventObj = document.createEvent('CustomEvent');
eventObj.initCustomEvent(event, initParams.bubbles, initParams.cancelable, null);

return eventObj;
}

const eventCtor =
typeof (Event as any) === 'function'
? (event: string, init?: EventInit): CustomEvent => new CustomEvent(event, init)
: /* istanbul ignore next */ customEvent;

const keyMap: Record<string, object> = {
alt: {
altKey: true,
code: 'AltLeft',
key: 'Alt',
location: 1,
which: 18,
},
arrowdown: {
code: 'ArrowDown',
key: 'ArrowDown',
location: 0,
which: 40,
},
arrowleft: {
code: 'ArrowLeft',
key: 'ArrowLeft',
location: 0,
which: 37,
},
arrowright: {
code: 'ArrowRight',
key: 'ArrowRight',
location: 0,
which: 39,
},
arrowup: {
code: 'ArrowUp',
key: 'ArrowUp',
location: 0,
which: 38,
},
backspace: {
code: 'Backspace',
key: 'Backspace',
location: 0,
which: 8,
},
control: {
code: 'ControlLeft',
ctrlKey: true,
key: 'Control',
location: 1,
which: 17,
},
enter: {
code: 'Enter',
key: 'Enter',
location: 0,
which: 13,
},
esc: {
code: 'Escape',
key: 'Escape',
location: 0,
which: 27,
},
meta: {
code: 'MetaLeft',
key: 'Meta',
location: 1,
metaKey: true,
which: 91,
},
shift: {
code: 'ShiftLeft',
key: 'Shift',
location: 1,
shiftKey: true,
which: 16,
},
space: {
code: 'Space',
key: ' ',
location: 0,
which: 32,
},
tab: {
code: 'Tab',
key: 'Tab',
location: 0,
which: 9,
},
};
for (let f = 1; f <= 12; f += 1) {
keyMap[`f${f}`] = {
code: `F${f}`,
key: `F${f}`,
location: 0,
which: f + 111,
};
}

const getCode = (char: string): string => {
const code = char.codePointAt(0);
// a-z
if (code && code >= 97 && code <= 122) {
return `Key${char.toUpperCase()}`;
}
// A-Z
if (code && code >= 65 && code <= 90) {
return `Key${char.toUpperCase()}`;
}
// A-Z
if (code && code >= 48 && code <= 57) {
return `Digit${char}`;
}

return 'Unknown';
};

const applyPayload = (event: Event, payload?: string): void => {
const keyData: object = {};
for (const key of payload ? payload.split('.') : []) {
let map = keyMap[key];
if (!map && key.length === 1) {
map = {
code: getCode(key),
key,
};
}

if (!map) {
throw new Error(`Unknown event part ${key}`);
}

mockHelperStub(keyData, map);
}

if (payload) {
mockHelperStub(event, keyData);
}
};

export default (
event: string,
init?: EventInit,
overrides?: Partial<UIEvent | KeyboardEvent | MouseEvent | TouchEvent | Event>,
): CustomEvent => {
const dot = event.indexOf('.');
const [eventName, eventPayload] = dot === -1 ? [event] : [event.substr(0, dot), event.substr(dot + 1)];
const eventObj = eventCtor(eventName, {
bubbles: preventBubble.indexOf(event) === -1,
cancelable: true,
...init,
});
applyPayload(eventObj, eventPayload);

if (overrides) {
mockHelperStub(eventObj, overrides);
}

return eventObj;
};
47 changes: 47 additions & 0 deletions libs/ng-mocks/src/lib/mock-helper/events/mock-helper.trigger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { DebugElement } from '@angular/core';

import mockHelperStub from '../mock-helper.stub';

import mockHelperEvent from './mock-helper.event';

/**
* @see https://developer.mozilla.org/de/docs/Web/Events
*/
const preventBubble = ['focus', 'blur', 'load', 'unload', 'change', 'reset', 'scroll'];

const toEventObj = (event: string | UIEvent | KeyboardEvent | MouseEvent | TouchEvent | Event): Event => {
return typeof event === 'string'
? mockHelperEvent(event, {
bubbles: preventBubble.indexOf(event) === -1,
cancelable: true,
})
: event;
};

export default (
debugElement: DebugElement | undefined | null,
eventName: string | UIEvent | KeyboardEvent | MouseEvent | TouchEvent | Event,
payload?: Partial<UIEvent | KeyboardEvent | MouseEvent | TouchEvent | Event>,
) => {
if (!debugElement) {
throw new Error(
`Cannot trigger ${typeof eventName === 'string' ? eventName : eventName.type} event undefined element`,
);
}

// nothing to emit on disabled elements
if (debugElement.nativeElement.disabled) {
return;
}

const event = toEventObj(eventName);
if (!event.target && debugElement) {
mockHelperStub(event, {
target: debugElement.nativeElement,
});
}
if (payload) {
mockHelperStub(event, payload);
}
debugElement.nativeElement.dispatchEvent(event);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const normalizeValue = (html: string | undefined): string =>
? html
.replace(new RegExp('\\s+', 'mg'), ' ')
.replace(new RegExp('<!--.*?-->', 'mg'), '')
.replace(new RegExp('<!--.*?', 'mg'), '')
.replace(new RegExp('\\s+', 'mg'), ' ')
.replace(new RegExp('>\\s+<', 'mg'), '><')
: '';
Expand Down
6 changes: 6 additions & 0 deletions libs/ng-mocks/src/lib/mock-helper/mock-helper.object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import mockHelperReveal from './crawl/mock-helper.reveal';
import mockHelperRevealAll from './crawl/mock-helper.reveal-all';
import mockHelperChange from './cva/mock-helper.change';
import mockHelperTouch from './cva/mock-helper.touch';
import mockHelperClick from './events/mock-helper.click';
import mockHelperEvent from './events/mock-helper.event';
import mockHelperTrigger from './events/mock-helper.trigger';
import mockHelperFormatHtml from './format/mock-helper.format-html';
import mockHelperFormatText from './format/mock-helper.format-text';
import mockHelperAutoSpy from './mock-helper.auto-spy';
Expand Down Expand Up @@ -34,8 +37,10 @@ import mockHelperFindTemplateRefs from './template-ref/mock-helper.find-template
export default {
autoSpy: mockHelperAutoSpy,
change: mockHelperChange,
click: mockHelperClick,
crawl: mockHelperCrawl,
defaultMock: mockHelperDefaultMock,
event: mockHelperEvent,
faster: mockHelperFaster,
find: mockHelperFind,
findAll: mockHelperFindAll,
Expand Down Expand Up @@ -64,4 +69,5 @@ export default {
stubMember: mockHelperStubMember,
throwOnConsole: mockHelperThrowOnConsole,
touch: mockHelperTouch,
trigger: mockHelperTrigger,
};
28 changes: 28 additions & 0 deletions libs/ng-mocks/src/lib/mock-helper/mock-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export const ngMocks: {
*/
change(el: DebugNode, value: any): void;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/click
*/
click(debugElement: MockedDebugElement | undefined | null, payload?: Partial<MouseEvent>): void;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/crawl
*/
Expand Down Expand Up @@ -63,6 +68,15 @@ export const ngMocks: {
*/
defaultMock<T>(def: AnyType<T>, handler?: (value: T, injector: Injector) => void | Partial<T>): void;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/event
*/
event(
event: string,
init?: EventInit,
overrides?: Partial<UIEvent | KeyboardEvent | MouseEvent | TouchEvent | Event>,
): Event;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/faster
*/
Expand Down Expand Up @@ -492,4 +506,18 @@ export const ngMocks: {
* @see https://ng-mocks.sudo.eu/api/ngMocks/touch
*/
touch(el: DebugNode): void;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/trigger
*/
trigger(debugElement: MockedDebugElement | undefined | null, event: Event): void;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/trigger
*/
trigger(
debugElement: MockedDebugElement | undefined | null,
event: string,
payload?: Partial<UIEvent | KeyboardEvent | MouseEvent | TouchEvent>,
): void;
} = mockHelperObject;
Loading

0 comments on commit 50753bb

Please sign in to comment.