Skip to content

Commit 00f9d85

Browse files
Joe MorganGpx
authored andcommitted
fix(190): Add blur events in correct order
Blur occurs after mouse down, but before click. I can't find any official documentation, but here's a nice code pen: https://codepen.io/mudassir0909/pen/eIHqB
1 parent 61398ad commit 00f9d85

File tree

3 files changed

+195
-25
lines changed

3 files changed

+195
-25
lines changed

__tests__/react/click.js

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,92 @@ describe("userEvent.click", () => {
198198
expect(b).toHaveFocus();
199199
});
200200

201+
it("should not blur when mousedown prevents default", () => {
202+
let events = [];
203+
const eventsHandler = jest.fn(evt => events.push(evt.type));
204+
const commonEvents = {
205+
onBlur: eventsHandler,
206+
onMouseOver: eventsHandler,
207+
onMouseMove: eventsHandler,
208+
onMouseDown: eventsHandler,
209+
onFocus: eventsHandler,
210+
onMouseUp: eventsHandler,
211+
onClick: eventsHandler,
212+
onChange: eventsHandler
213+
};
214+
215+
const { getByTestId } = render(
216+
<React.Fragment>
217+
<input data-testid="A" {...commonEvents} />
218+
<input
219+
data-testid="B"
220+
{...commonEvents}
221+
onMouseDown={e => {
222+
e.preventDefault();
223+
eventsHandler(e);
224+
}}
225+
/>
226+
<input data-testid="C" {...commonEvents} />
227+
</React.Fragment>
228+
);
229+
230+
const a = getByTestId("A");
231+
const b = getByTestId("B");
232+
const c = getByTestId("C");
233+
234+
expect(a).not.toHaveFocus();
235+
expect(b).not.toHaveFocus();
236+
expect(c).not.toHaveFocus();
237+
238+
userEvent.click(a);
239+
expect(a).toHaveFocus();
240+
expect(b).not.toHaveFocus();
241+
expect(c).not.toHaveFocus();
242+
243+
expect(events).toEqual([
244+
"mouseover",
245+
"mousemove",
246+
"mousedown",
247+
"focus",
248+
"mouseup",
249+
"click"
250+
]);
251+
252+
events = [];
253+
254+
userEvent.click(b);
255+
expect(a).toHaveFocus();
256+
expect(b).not.toHaveFocus();
257+
expect(c).not.toHaveFocus();
258+
259+
expect(events).toEqual([
260+
"mousemove",
261+
"mouseover",
262+
"mousemove",
263+
"mousedown",
264+
"mouseup",
265+
"click"
266+
]);
267+
268+
events = [];
269+
270+
userEvent.click(c);
271+
expect(a).not.toHaveFocus();
272+
expect(b).not.toHaveFocus();
273+
expect(c).toHaveFocus();
274+
275+
expect(events).toEqual([
276+
"mousemove",
277+
"mouseover",
278+
"mousemove",
279+
"mousedown",
280+
"blur",
281+
"focus",
282+
"mouseup",
283+
"click"
284+
]);
285+
});
286+
201287
it("does not lose focus when click updates focus", () => {
202288
const FocusComponent = () => {
203289
const inputRef = React.useRef();
@@ -328,9 +414,9 @@ describe("userEvent.click", () => {
328414
const { getByTestId } = render(
329415
React.createElement(type, {
330416
"data-testid": "element",
331-
onMouseDown: (evt) => {
417+
onMouseDown: evt => {
332418
evt.preventDefault();
333-
},
419+
}
334420
})
335421
);
336422

__tests__/react/dblclick.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,99 @@ describe("userEvent.dblClick", () => {
104104
"click"
105105
]);
106106
});
107+
108+
it("should not blur when mousedown prevents default", () => {
109+
let events = [];
110+
const eventsHandler = jest.fn(evt => events.push(evt.type));
111+
const commonEvents = {
112+
onBlur: eventsHandler,
113+
onMouseOver: eventsHandler,
114+
onMouseMove: eventsHandler,
115+
onMouseDown: eventsHandler,
116+
onFocus: eventsHandler,
117+
onMouseUp: eventsHandler,
118+
onClick: eventsHandler,
119+
onChange: eventsHandler
120+
};
121+
122+
const { getByTestId } = render(
123+
<React.Fragment>
124+
<input data-testid="A" {...commonEvents} />
125+
<input
126+
data-testid="B"
127+
{...commonEvents}
128+
onMouseDown={e => {
129+
e.preventDefault();
130+
eventsHandler(e);
131+
}}
132+
/>
133+
<input data-testid="C" {...commonEvents} />
134+
</React.Fragment>
135+
);
136+
137+
const a = getByTestId("A");
138+
const b = getByTestId("B");
139+
const c = getByTestId("C");
140+
141+
expect(a).not.toHaveFocus();
142+
expect(b).not.toHaveFocus();
143+
expect(c).not.toHaveFocus();
144+
145+
userEvent.dblClick(a);
146+
expect(a).toHaveFocus();
147+
expect(b).not.toHaveFocus();
148+
expect(c).not.toHaveFocus();
149+
150+
expect(events).toEqual([
151+
"mouseover",
152+
"mousemove",
153+
"mousedown",
154+
"focus",
155+
"mouseup",
156+
"click",
157+
"mousedown",
158+
"mouseup",
159+
"click"
160+
]);
161+
162+
events = [];
163+
164+
userEvent.dblClick(b);
165+
expect(a).toHaveFocus();
166+
expect(b).not.toHaveFocus();
167+
expect(c).not.toHaveFocus();
168+
169+
expect(events).toEqual([
170+
"mousemove",
171+
"mouseover",
172+
"mousemove",
173+
"mousedown",
174+
"mouseup",
175+
"click",
176+
"mousedown",
177+
"mouseup",
178+
"click"
179+
]);
180+
181+
events = [];
182+
183+
userEvent.dblClick(c);
184+
expect(a).not.toHaveFocus();
185+
expect(b).not.toHaveFocus();
186+
expect(c).toHaveFocus();
187+
188+
expect(events).toEqual([
189+
"mousemove",
190+
"mouseover",
191+
"mousemove",
192+
"mousedown",
193+
"blur",
194+
"focus",
195+
"mouseup",
196+
"click",
197+
"mousedown",
198+
"mouseup",
199+
"click"
200+
]);
201+
});
107202
});

src/index.js

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ function clickBooleanElement(element) {
4141
fireEvent.click(element);
4242
}
4343

44-
function clickElement(element) {
44+
function clickElement(element, previousElement) {
4545
fireEvent.mouseOver(element);
4646
fireEvent.mouseMove(element);
4747
const continueDefaultHandling = fireEvent.mouseDown(element);
4848
if (continueDefaultHandling) {
49+
previousElement && previousElement.blur();
4950
element.focus();
5051
}
5152
fireEvent.mouseUp(element);
@@ -55,11 +56,14 @@ function clickElement(element) {
5556
labelAncestor && clickLabel(labelAncestor);
5657
}
5758

58-
function dblClickElement(element) {
59+
function dblClickElement(element, previousElement) {
5960
fireEvent.mouseOver(element);
6061
fireEvent.mouseMove(element);
61-
fireEvent.mouseDown(element);
62-
element.focus();
62+
const continueDefaultHandling = fireEvent.mouseDown(element);
63+
if (continueDefaultHandling) {
64+
previousElement && previousElement.blur();
65+
element.focus();
66+
}
6367
fireEvent.mouseUp(element);
6468
fireEvent.click(element);
6569
fireEvent.mouseDown(element);
@@ -101,15 +105,6 @@ function fireChangeEvent(event) {
101105
event.target.removeEventListener("blur", fireChangeEvent);
102106
}
103107

104-
function blurFocusedElement(element, focusedElement, wasAnotherElementFocused) {
105-
if (
106-
wasAnotherElementFocused &&
107-
element.ownerDocument.activeElement === element
108-
) {
109-
focusedElement.blur();
110-
}
111-
}
112-
113108
const userEvent = {
114109
click(element) {
115110
const focusedElement = element.ownerDocument.activeElement;
@@ -131,10 +126,8 @@ const userEvent = {
131126
break;
132127
}
133128
default:
134-
clickElement(element);
129+
clickElement(element, wasAnotherElementFocused && focusedElement);
135130
}
136-
137-
blurFocusedElement(element, focusedElement, wasAnotherElementFocused);
138131
},
139132

140133
dblClick(element) {
@@ -149,14 +142,12 @@ const userEvent = {
149142
switch (element.tagName) {
150143
case "INPUT":
151144
if (element.type === "checkbox") {
152-
dblClickCheckbox(element);
145+
dblClickCheckbox(element, wasAnotherElementFocused && focusedElement);
153146
break;
154147
}
155148
default:
156-
dblClickElement(element);
149+
dblClickElement(element, wasAnotherElementFocused && focusedElement);
157150
}
158-
159-
blurFocusedElement(element, focusedElement, wasAnotherElementFocused);
160151
},
161152

162153
selectOptions(element, values) {
@@ -168,7 +159,7 @@ const userEvent = {
168159
fireEvent.mouseLeave(focusedElement);
169160
}
170161

171-
clickElement(element);
162+
clickElement(element, wasAnotherElementFocused && focusedElement);
172163

173164
const valArray = Array.isArray(values) ? values : [values];
174165
const selectedOptions = Array.from(
@@ -182,8 +173,6 @@ const userEvent = {
182173
selectOption(element, selectedOptions[0]);
183174
}
184175
}
185-
186-
blurFocusedElement(element, focusedElement, wasAnotherElementFocused);
187176
},
188177

189178
async type(element, text, userOpts = {}) {

0 commit comments

Comments
 (0)