I'm following a tutorial on React.js testing Library and trying to follow along in Typescript. Although after following along with the first test I'm already encountering a few issues and am wondering what should be different in a test written in Typescript.
App.ts
function App() {
return (
<div className="container my-5">
<form>
<div className="mb-3">
<label htmlFor="email" className="form-label">
Email Address
</label>
<input
type="email"
id="email"
name="email"
className="form-control"
/>
</div>
<div className="mb-3">
<label htmlFor="password" className="form-label">
Password
</label>
<input
type="password"
id="password"
name="password"
className="form-control"
/>
</div>
</form>
</div>
);
}
export default App;
App.test.tsx
import { render, screen } from "@testing-library/react";
import App from "./App";
test("inputs should be initially empty", () => {
render(<App />);
const emailInputElement = screen.getByRole("textbox");
const passwordInputElement = screen.getByLabelText(/password/);
expect(emailInputElement.value).toBe("");
expect(passwordInputElement.value).toBe("");
});
I'm receiving an error "Property 'value' does not exist on type 'HTMLElement" on:
expect(emailInputElement.value).toBe("");
expect(passwordInputElement.value).toBe("");
Do these need to be explained differently on Typescript?
CodePudding user response:
You are getting this error because screen.getByRole
and screen.getByLabelText
returns HTMLElement
object and it doesn´t have value
prop.
There are 2 ways to get it working:
- explicitly define the return type as
HTMLInputElement
(it has value prop).
import { render, screen } from "@testing-library/react";
import App from "./App";
test("inputs should be initially empty", () => {
render(<App />);
const emailInputElement = screen.getByRole<HTMLInputElement>("textbox");
const passwordInputElement = screen.getByLabelText<HTMLInputElement>(/password/i);
expect(emailInputElement.value).toBe("");
expect(passwordInputElement.value).toBe("");
});
- Use
@testing-library/jest-dom
library -> it provides a set of custom jest matchers that you can use to extend jest. You can check more here.
import "@testing-library/jest-dom/extend-expect";
import { render, screen } from "@testing-library/react";
import App from "./App";
test("inputs should be initially empty", () => {
render(<App />);
const emailInputElement = screen.getByRole("textbox");
const passwordInputElement = screen.getByLabelText(/password/i);
expect(emailInputElement).toHaveValue("");
expect(passwordInputElement).toHaveValue("");
});
CodePudding user response:
You can define type for both text box as HTMLInputElement
also where you are targeting password in your actual code it's case sensitive so always use regular expression to avoid tests failing ie (/password/i)
render(<App/>);
const emailInputElement: HTMLInputElement = screen.getByRole("textbox");
const passwordInputElement: HTMLInputElement =
screen.getByLabelText(/password/i);
expect(emailInputElement.value).toBe("");
expect(passwordInputElement.value).toBe("");
});