Skip to content

Commit 15520b7

Browse files
authored
feat(mock-doc): dispatch blur and focus events (#3449)
for mock-doc, `blur()` and `focus()` methods will now dispatch an event. created `MockFocusEvent` which extends a new `MockUIEvent`, which extends the existing `MockEvent`.
1 parent bd1b8c2 commit 15520b7

File tree

5 files changed

+92
-4
lines changed

5 files changed

+92
-4
lines changed

src/mock-doc/event.ts

+26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { MockDocument } from './document';
22
import { MockElement } from './node';
33
import { NODE_NAMES } from './constants';
4+
import { MockWindow } from './window';
45

56
export class MockEvent {
67
bubbles = false;
@@ -113,6 +114,31 @@ export class MockMouseEvent extends MockEvent {
113114
}
114115
}
115116

117+
export class MockUIEvent extends MockEvent {
118+
detail: number | null = null;
119+
view: MockWindow | null = null;
120+
121+
constructor(type: string, uiEventInitDic?: UIEventInit) {
122+
super(type);
123+
124+
if (uiEventInitDic != null) {
125+
Object.assign(this, uiEventInitDic);
126+
}
127+
}
128+
}
129+
130+
export class MockFocusEvent extends MockUIEvent {
131+
relatedTarget: EventTarget | null = null;
132+
133+
constructor(type: 'blur' | 'focus', focusEventInitDic?: FocusEventInit) {
134+
super(type);
135+
136+
if (focusEventInitDic != null) {
137+
Object.assign(this, focusEventInitDic);
138+
}
139+
}
140+
}
141+
116142
export class MockEventListener {
117143
type: string;
118144
handler: (ev?: any) => void;

src/mock-doc/global.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
MockTemplateElement,
1414
MockTitleElement,
1515
} from './element';
16-
import { MockCustomEvent, MockEvent, MockKeyboardEvent, MockMouseEvent } from './event';
16+
import { MockCustomEvent, MockEvent, MockFocusEvent, MockKeyboardEvent, MockMouseEvent } from './event';
1717
import { MockHeaders } from './headers';
1818
import { MockRequest, MockResponse } from './request-response';
1919
import { MockDOMParser } from './parser';
@@ -148,6 +148,7 @@ const WINDOW_PROPS = [
148148
'HTMLElement',
149149
'Node',
150150
'NodeList',
151+
'FocusEvent',
151152
'KeyboardEvent',
152153
'MouseEvent',
153154
];
@@ -156,6 +157,7 @@ const GLOBAL_CONSTRUCTORS: [string, any][] = [
156157
['CustomEvent', MockCustomEvent],
157158
['Event', MockEvent],
158159
['Headers', MockHeaders],
160+
['FocusEvent', MockFocusEvent],
159161
['KeyboardEvent', MockKeyboardEvent],
160162
['MouseEvent', MockMouseEvent],
161163
['Request', MockRequest],

src/mock-doc/node.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ import { matches, selectAll, selectOne } from './selector';
44
import { MockAttr, MockAttributeMap, createAttributeProxy } from './attribute';
55
import { MockClassList } from './class-list';
66
import { MockCSSStyleDeclaration, createCSSStyleDeclaration } from './css-style-declaration';
7-
import { MockEvent, addEventListener, dispatchEvent, removeEventListener, resetEventListeners } from './event';
7+
import {
8+
MockEvent,
9+
addEventListener,
10+
dispatchEvent,
11+
removeEventListener,
12+
resetEventListeners,
13+
MockFocusEvent,
14+
} from './event';
815
import { NODE_NAMES, NODE_TYPES } from './constants';
916
import { NON_ESCAPABLE_CONTENT, SerializeNodeToHtmlOptions, serializeNodeToHtml } from './serialize-node';
1017
import { parseFragmentUtil } from './parse-util';
@@ -236,7 +243,10 @@ export class MockElement extends MockNode {
236243
}
237244

238245
blur() {
239-
/**/
246+
dispatchEvent(
247+
this,
248+
new MockFocusEvent('blur', { relatedTarget: null, bubbles: true, cancelable: true, composed: true })
249+
);
240250
}
241251

242252
get shadowRoot() {
@@ -320,7 +330,12 @@ export class MockElement extends MockNode {
320330
return this.children[0] || null;
321331
}
322332

323-
focus(_options?: { preventScroll?: boolean }) {}
333+
focus(_options?: { preventScroll?: boolean }) {
334+
dispatchEvent(
335+
this,
336+
new MockFocusEvent('focus', { relatedTarget: null, bubbles: true, cancelable: true, composed: true })
337+
);
338+
}
324339

325340
getAttribute(attrName: string) {
326341
if (attrName === 'style') {

src/mock-doc/test/event.spec.ts

+43
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,49 @@ describe('event', () => {
9090
expect(ev.detail).toBe(88);
9191
});
9292

93+
it('FocusEvent() requires type', () => {
94+
expect(() => {
95+
// @ts-ignore checking that it throws when not supplied required arguments
96+
new win.FocusEvent();
97+
}).toThrow();
98+
});
99+
100+
const focusEventTypes: ('blur' | 'focus')[] = ['blur', 'focus'];
101+
it.each(focusEventTypes)('creates a %s-type MockFocusEvent', (focusType) => {
102+
const ev = new win.FocusEvent(focusType);
103+
expect(ev.bubbles).toBe(false);
104+
expect(ev.cancelBubble).toBe(false);
105+
expect(ev.cancelable).toBe(false);
106+
expect(ev.composed).toBe(false);
107+
expect(ev.currentTarget).toBe(null);
108+
expect(ev.defaultPrevented).toBe(false);
109+
expect(ev.srcElement).toBe(null);
110+
expect(ev.target).toBe(null);
111+
expect(typeof ev.timeStamp).toBe('number');
112+
expect(ev.type).toBe(focusType);
113+
expect(ev.relatedTarget).toBe(null);
114+
});
115+
116+
it('FocusEvent(type, focusEventInitDic)', () => {
117+
const focusEventInitDic = {
118+
bubbles: true,
119+
composed: true,
120+
relatedTarget: null as EventTarget | null,
121+
};
122+
const ev = new win.FocusEvent('blur', focusEventInitDic);
123+
expect(ev.bubbles).toBe(true);
124+
expect(ev.cancelBubble).toBe(false);
125+
expect(ev.cancelable).toBe(false);
126+
expect(ev.composed).toBe(true);
127+
expect(ev.currentTarget).toBe(null);
128+
expect(ev.defaultPrevented).toBe(false);
129+
expect(ev.srcElement).toBe(null);
130+
expect(ev.target).toBe(null);
131+
expect(typeof ev.timeStamp).toBe('number');
132+
expect(ev.type).toBe('blur');
133+
expect(ev.relatedTarget).toBe(null);
134+
});
135+
93136
it('KeyboardEvent() requires type', () => {
94137
expect(() => {
95138
// @ts-ignore checking that it throws when not supplied required arguments

src/mock-doc/window.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
MockMouseEvent,
1111
MockCustomEvent,
1212
MockKeyboardEvent,
13+
MockFocusEvent,
1314
} from './event';
1415
import { MockDocument, resetDocument } from './document';
1516
import { MockDocumentFragment } from './document-fragment';
@@ -74,6 +75,7 @@ export class MockWindow {
7475
CustomEvent: typeof MockCustomEvent;
7576
Event: typeof MockEvent;
7677
Headers: typeof MockHeaders;
78+
FocusEvent: typeof MockFocusEvent;
7779
KeyboardEvent: typeof MockKeyboardEvent;
7880
MouseEvent: typeof MockMouseEvent;
7981

0 commit comments

Comments
 (0)