Skip to content

Commit a746fe6

Browse files
authored
Merge pull request testing-library#28 from weyert/master
Importing branch
2 parents 7947860 + 03f1ffe commit a746fe6

File tree

3 files changed

+110
-18
lines changed

3 files changed

+110
-18
lines changed

.babelrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
22
"presets": ["env", "react"]
3-
}
3+
}

__tests__/type.js

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,70 @@
1-
import React from "react";
2-
import { render, cleanup } from "react-testing-library";
31
import "jest-dom/extend-expect";
2+
3+
import { cleanup, render } from "react-testing-library";
4+
5+
import React from "react";
46
import userEvent from "../src";
57

68
afterEach(cleanup);
79

810
describe("userEvent.type", () => {
9-
it.each(["input", "textarea"])("should type text in <%s>", type => {
11+
it.each(["input", "textarea"])("should type text in <%s>", async type => {
12+
const onChange = jest.fn();
13+
const { getByTestId } = render(
14+
React.createElement(type, {
15+
"data-testid": "input",
16+
onChange: onChange
17+
})
18+
);
19+
const text = "Hello, world!";
20+
await userEvent.type(getByTestId("input"), text);
21+
expect(onChange).toHaveBeenCalledTimes(text.length);
22+
expect(getByTestId("input")).toHaveProperty("value", text);
23+
});
24+
25+
it.each(["input", "textarea"])(
26+
"should not type <%s> when prevented",
27+
async type => {
28+
const onChange = jest.fn();
29+
const onKeydown = jest
30+
.fn()
31+
.mockImplementation(event => event.preventDefault());
32+
const { getByTestId } = render(
33+
React.createElement(type, {
34+
"data-testid": "input",
35+
onKeyDown: onKeydown,
36+
onChange: onChange
37+
})
38+
);
39+
const text = "Hello, world!";
40+
await userEvent.type(getByTestId("input"), text);
41+
expect(onKeydown).toHaveBeenCalledTimes(text.length);
42+
expect(onChange).toHaveBeenCalledTimes(0);
43+
expect(getByTestId("input")).not.toHaveProperty("value", text);
44+
}
45+
);
46+
47+
it("test delayed typing of text", async () => {
1048
const onChange = jest.fn();
1149
const { getByTestId } = render(
12-
React.createElement(type, { "data-testid": "input", onChange: onChange })
50+
React.createElement("input", {
51+
"data-testid": "input",
52+
onChange: onChange
53+
})
1354
);
1455
const text = "Hello, world!";
15-
userEvent.type(getByTestId("input"), text);
56+
await userEvent.type(getByTestId("input"), text, {
57+
allAtOnce: false,
58+
delay: 10
59+
});
1660

1761
expect(onChange).toHaveBeenCalledTimes(text.length);
1862
expect(getByTestId("input")).toHaveProperty("value", text);
1963
});
2064

2165
it.each(["input", "textarea"])(
2266
"should type text in <%s> all at once",
23-
type => {
67+
async type => {
2468
const onChange = jest.fn();
2569
const { getByTestId } = render(
2670
React.createElement(type, {
@@ -29,7 +73,9 @@ describe("userEvent.type", () => {
2973
})
3074
);
3175
const text = "Hello, world!";
32-
userEvent.type(getByTestId("input"), text, { allAtOnce: true });
76+
await userEvent.type(getByTestId("input"), text, {
77+
allAtOnce: true
78+
});
3379

3480
expect(onChange).toHaveBeenCalledTimes(1);
3581
expect(getByTestId("input")).toHaveProperty("value", text);

src/index.js

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { fireEvent } from "dom-testing-library";
22

3+
function delay(t, v) {
4+
return new Promise(function(resolve) {
5+
setTimeout(resolve.bind(null, v), t);
6+
});
7+
}
8+
39
function findTagInParents(element, tagName) {
410
if (element.parentNode == null) return undefined;
511
if (element.parentNode.tagName === tagName) return element.parentNode;
@@ -122,19 +128,59 @@ const userEvent = {
122128
wasAnotherElementFocused && focusedElement.blur();
123129
},
124130

125-
type(element, text, userOpts = {}) {
126-
const defaultOpts = { allAtOnce: false };
131+
async type(element, text, userOpts = {}) {
132+
const defaultOpts = {
133+
allAtOnce: false,
134+
delay: 0
135+
};
127136
const opts = Object.assign(defaultOpts, userOpts);
128-
129-
this.click(element);
130137
if (opts.allAtOnce) {
131-
fireEvent.change(element, { target: { value: text } });
138+
fireEvent.change(element, {
139+
target: {
140+
value: text
141+
}
142+
});
132143
} else {
133-
text
134-
.split("")
135-
.forEach((_, i) =>
136-
fireEvent.change(element, { target: { value: text.slice(0, i + 1) } })
137-
);
144+
const typedCharacters = text.split("");
145+
146+
let actuallyTyped = "";
147+
for (let index = 0; index < text.length; index++) {
148+
const char = text[index];
149+
const key = char; // TODO: check if this also valid for characters with diacritic markers e.g. úé etc
150+
const keyCode = char.charCodeAt(0);
151+
152+
if (opts.delay > 0) await delay(opts.delay);
153+
154+
const downEvent = fireEvent.keyDown(element, {
155+
key: key,
156+
keyCode: keyCode,
157+
which: keyCode
158+
});
159+
if (downEvent) {
160+
const pressEvent = fireEvent.keyPress(element, {
161+
key: key,
162+
keyCode,
163+
charCode: keyCode,
164+
keyCode: keyCode
165+
});
166+
if (pressEvent) {
167+
actuallyTyped += key;
168+
fireEvent.change(element, {
169+
target: {
170+
value: actuallyTyped
171+
},
172+
bubbles: true,
173+
cancelable: true
174+
});
175+
}
176+
}
177+
178+
fireEvent.keyUp(element, {
179+
key: key,
180+
keyCode: keyCode,
181+
which: keyCode
182+
});
183+
}
138184
}
139185
}
140186
};

0 commit comments

Comments
 (0)