Skip to content

Commit 1177c46

Browse files
committed
fix: 🐛 don't type on disabled or readonly inputs
Closes #152 BREAKING CHANGE: disabled or readonly inputs won't be typeable anymore
1 parent 9477e30 commit 1177c46

File tree

3 files changed

+106
-9
lines changed

3 files changed

+106
-9
lines changed

__tests__/react/type.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,51 @@ describe("userEvent.type", () => {
3535
expect(getByTestId("input")).not.toHaveProperty("value", text);
3636
});
3737

38+
it.each(["input", "textarea"])(
39+
"should not type when <%s> is disabled",
40+
type => {
41+
const onChange = jest.fn();
42+
const { getByTestId } = render(
43+
React.createElement(type, {
44+
"data-testid": "input",
45+
onChange: onChange,
46+
disabled: true
47+
})
48+
);
49+
const text = "Hello, world!";
50+
userEvent.type(getByTestId("input"), text);
51+
expect(onChange).not.toHaveBeenCalled();
52+
expect(getByTestId("input")).toHaveProperty("value", "");
53+
}
54+
);
55+
56+
it.each(["input", "textarea"])(
57+
"should not type when <%s> is readOnly",
58+
type => {
59+
const onChange = jest.fn();
60+
const onKeyDown = jest.fn();
61+
const onKeyPress = jest.fn();
62+
const onKeyUp = jest.fn();
63+
const { getByTestId } = render(
64+
React.createElement(type, {
65+
"data-testid": "input",
66+
onChange,
67+
onKeyDown,
68+
onKeyPress,
69+
onKeyUp,
70+
readOnly: true
71+
})
72+
);
73+
const text = "Hello, world!";
74+
userEvent.type(getByTestId("input"), text);
75+
expect(onKeyDown).toHaveBeenCalledTimes(text.length);
76+
expect(onKeyPress).toHaveBeenCalledTimes(text.length);
77+
expect(onKeyUp).toHaveBeenCalledTimes(text.length);
78+
expect(onChange).not.toHaveBeenCalled();
79+
expect(getByTestId("input")).toHaveProperty("value", "");
80+
}
81+
);
82+
3883
it("should delay the typing when opts.delay is not 0", async () => {
3984
jest.useFakeTimers();
4085
const onChange = jest.fn();

__tests__/vue/type.js

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import userEvent from "../../src";
44

55
afterEach(cleanup);
66

7-
const renderComponent = (type, events = {}) =>
7+
const renderComponent = (type, events = {}, attrs = {}) =>
88
render({
99
render: function(h) {
1010
return h(type, {
11-
attrs: { "data-testid": "input" },
11+
attrs: { "data-testid": "input", ...attrs },
1212
on: events
1313
});
1414
}
@@ -48,6 +48,55 @@ describe("userEvent.type", () => {
4848
expect(getByTestId("input")).not.toHaveProperty("value", text);
4949
});
5050

51+
it.each(["input", "textarea"])(
52+
"should not type when <%s> is disabled",
53+
type => {
54+
const change = jest.fn();
55+
const { getByTestId } = renderComponent(
56+
type,
57+
{
58+
change
59+
},
60+
{
61+
disabled: true
62+
}
63+
);
64+
const text = "Hello, world!";
65+
userEvent.type(getByTestId("input"), text);
66+
expect(change).not.toHaveBeenCalled();
67+
expect(getByTestId("input")).toHaveProperty("value", "");
68+
}
69+
);
70+
71+
it.each(["input", "textarea"])(
72+
"should not type when <%s> is readOnly",
73+
type => {
74+
const change = jest.fn();
75+
const keydown = jest.fn();
76+
const keypress = jest.fn();
77+
const keyup = jest.fn();
78+
const { getByTestId } = renderComponent(
79+
type,
80+
{
81+
change,
82+
keydown,
83+
keypress,
84+
keyup
85+
},
86+
{
87+
readOnly: true
88+
}
89+
);
90+
const text = "Hello, world!";
91+
userEvent.type(getByTestId("input"), text);
92+
expect(keydown).toHaveBeenCalledTimes(text.length);
93+
expect(keypress).toHaveBeenCalledTimes(text.length);
94+
expect(keyup).toHaveBeenCalledTimes(text.length);
95+
expect(change).not.toHaveBeenCalled();
96+
expect(getByTestId("input")).toHaveProperty("value", "");
97+
}
98+
);
99+
51100
it("should delay the typing when opts.delay is not 0", async () => {
52101
jest.useFakeTimers();
53102
const change = jest.fn();

src/index.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,14 @@ const userEvent = {
174174
},
175175

176176
async type(element, text, userOpts = {}) {
177+
if (element.disabled) return;
177178
const defaultOpts = {
178179
allAtOnce: false,
179180
delay: 0
180181
};
181182
const opts = Object.assign(defaultOpts, userOpts);
182183
if (opts.allAtOnce) {
184+
if (element.readOnly) return;
183185
fireEvent.input(element, { target: { value: text } });
184186
} else {
185187
let actuallyTyped = "";
@@ -203,13 +205,14 @@ const userEvent = {
203205
});
204206
if (pressEvent) {
205207
actuallyTyped += key;
206-
fireEvent.input(element, {
207-
target: {
208-
value: actuallyTyped
209-
},
210-
bubbles: true,
211-
cancelable: true
212-
});
208+
if (!element.readOnly)
209+
fireEvent.input(element, {
210+
target: {
211+
value: actuallyTyped
212+
},
213+
bubbles: true,
214+
cancelable: true
215+
});
213216
}
214217
}
215218

0 commit comments

Comments
 (0)