Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Joe Morgan authored and Gpx committed Feb 17, 2020
1 parent 61398ad commit 00f9d85
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 25 deletions.
90 changes: 88 additions & 2 deletions __tests__/react/click.js
Expand Up @@ -198,6 +198,92 @@ describe("userEvent.click", () => {
expect(b).toHaveFocus();
});

it("should not blur when mousedown prevents default", () => {
let events = [];
const eventsHandler = jest.fn(evt => events.push(evt.type));
const commonEvents = {
onBlur: eventsHandler,
onMouseOver: eventsHandler,
onMouseMove: eventsHandler,
onMouseDown: eventsHandler,
onFocus: eventsHandler,
onMouseUp: eventsHandler,
onClick: eventsHandler,
onChange: eventsHandler
};

const { getByTestId } = render(
<React.Fragment>
<input data-testid="A" {...commonEvents} />
<input
data-testid="B"
{...commonEvents}
onMouseDown={e => {
e.preventDefault();
eventsHandler(e);
}}
/>
<input data-testid="C" {...commonEvents} />
</React.Fragment>
);

const a = getByTestId("A");
const b = getByTestId("B");
const c = getByTestId("C");

expect(a).not.toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).not.toHaveFocus();

userEvent.click(a);
expect(a).toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).not.toHaveFocus();

expect(events).toEqual([
"mouseover",
"mousemove",
"mousedown",
"focus",
"mouseup",
"click"
]);

events = [];

userEvent.click(b);
expect(a).toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).not.toHaveFocus();

expect(events).toEqual([
"mousemove",
"mouseover",
"mousemove",
"mousedown",
"mouseup",
"click"
]);

events = [];

userEvent.click(c);
expect(a).not.toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).toHaveFocus();

expect(events).toEqual([
"mousemove",
"mouseover",
"mousemove",
"mousedown",
"blur",
"focus",
"mouseup",
"click"
]);
});

it("does not lose focus when click updates focus", () => {
const FocusComponent = () => {
const inputRef = React.useRef();
Expand Down Expand Up @@ -328,9 +414,9 @@ describe("userEvent.click", () => {
const { getByTestId } = render(
React.createElement(type, {
"data-testid": "element",
onMouseDown: (evt) => {
onMouseDown: evt => {
evt.preventDefault();
},
}
})
);

Expand Down
95 changes: 95 additions & 0 deletions __tests__/react/dblclick.js
Expand Up @@ -104,4 +104,99 @@ describe("userEvent.dblClick", () => {
"click"
]);
});

it("should not blur when mousedown prevents default", () => {
let events = [];
const eventsHandler = jest.fn(evt => events.push(evt.type));
const commonEvents = {
onBlur: eventsHandler,
onMouseOver: eventsHandler,
onMouseMove: eventsHandler,
onMouseDown: eventsHandler,
onFocus: eventsHandler,
onMouseUp: eventsHandler,
onClick: eventsHandler,
onChange: eventsHandler
};

const { getByTestId } = render(
<React.Fragment>
<input data-testid="A" {...commonEvents} />
<input
data-testid="B"
{...commonEvents}
onMouseDown={e => {
e.preventDefault();
eventsHandler(e);
}}
/>
<input data-testid="C" {...commonEvents} />
</React.Fragment>
);

const a = getByTestId("A");
const b = getByTestId("B");
const c = getByTestId("C");

expect(a).not.toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).not.toHaveFocus();

userEvent.dblClick(a);
expect(a).toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).not.toHaveFocus();

expect(events).toEqual([
"mouseover",
"mousemove",
"mousedown",
"focus",
"mouseup",
"click",
"mousedown",
"mouseup",
"click"
]);

events = [];

userEvent.dblClick(b);
expect(a).toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).not.toHaveFocus();

expect(events).toEqual([
"mousemove",
"mouseover",
"mousemove",
"mousedown",
"mouseup",
"click",
"mousedown",
"mouseup",
"click"
]);

events = [];

userEvent.dblClick(c);
expect(a).not.toHaveFocus();
expect(b).not.toHaveFocus();
expect(c).toHaveFocus();

expect(events).toEqual([
"mousemove",
"mouseover",
"mousemove",
"mousedown",
"blur",
"focus",
"mouseup",
"click",
"mousedown",
"mouseup",
"click"
]);
});
});
35 changes: 12 additions & 23 deletions src/index.js
Expand Up @@ -41,11 +41,12 @@ function clickBooleanElement(element) {
fireEvent.click(element);
}

function clickElement(element) {
function clickElement(element, previousElement) {
fireEvent.mouseOver(element);
fireEvent.mouseMove(element);
const continueDefaultHandling = fireEvent.mouseDown(element);
if (continueDefaultHandling) {
previousElement && previousElement.blur();
element.focus();
}
fireEvent.mouseUp(element);
Expand All @@ -55,11 +56,14 @@ function clickElement(element) {
labelAncestor && clickLabel(labelAncestor);
}

function dblClickElement(element) {
function dblClickElement(element, previousElement) {
fireEvent.mouseOver(element);
fireEvent.mouseMove(element);
fireEvent.mouseDown(element);
element.focus();
const continueDefaultHandling = fireEvent.mouseDown(element);
if (continueDefaultHandling) {
previousElement && previousElement.blur();
element.focus();
}
fireEvent.mouseUp(element);
fireEvent.click(element);
fireEvent.mouseDown(element);
Expand Down Expand Up @@ -101,15 +105,6 @@ function fireChangeEvent(event) {
event.target.removeEventListener("blur", fireChangeEvent);
}

function blurFocusedElement(element, focusedElement, wasAnotherElementFocused) {
if (
wasAnotherElementFocused &&
element.ownerDocument.activeElement === element
) {
focusedElement.blur();
}
}

const userEvent = {
click(element) {
const focusedElement = element.ownerDocument.activeElement;
Expand All @@ -131,10 +126,8 @@ const userEvent = {
break;
}
default:
clickElement(element);
clickElement(element, wasAnotherElementFocused && focusedElement);
}

blurFocusedElement(element, focusedElement, wasAnotherElementFocused);
},

dblClick(element) {
Expand All @@ -149,14 +142,12 @@ const userEvent = {
switch (element.tagName) {
case "INPUT":
if (element.type === "checkbox") {
dblClickCheckbox(element);
dblClickCheckbox(element, wasAnotherElementFocused && focusedElement);
break;
}
default:
dblClickElement(element);
dblClickElement(element, wasAnotherElementFocused && focusedElement);
}

blurFocusedElement(element, focusedElement, wasAnotherElementFocused);
},

selectOptions(element, values) {
Expand All @@ -168,7 +159,7 @@ const userEvent = {
fireEvent.mouseLeave(focusedElement);
}

clickElement(element);
clickElement(element, wasAnotherElementFocused && focusedElement);

const valArray = Array.isArray(values) ? values : [values];
const selectedOptions = Array.from(
Expand All @@ -182,8 +173,6 @@ const userEvent = {
selectOption(element, selectedOptions[0]);
}
}

blurFocusedElement(element, focusedElement, wasAnotherElementFocused);
},

async type(element, text, userOpts = {}) {
Expand Down

0 comments on commit 00f9d85

Please sign in to comment.