I'm building a React application using TypeScript. I do my component tests using React Testing Library.
Let's say you have simple form like this:
import React from 'react'
function Login({onSubmit}) {
return (
<div>
<form
onSubmit={e => {
e.preventDefault()
const {username, password} = e.target.elements
onSubmit({
username: username.value,
password: password.value,
})
}}
>
<label htmlFor="username">Username</label>
<input id="username" />
<label htmlFor="password">Password</label>
<input id="password" type="password" />
<br />
<button type="submit">Submit</button>
</form>
</div>
)
}
export {Login}
In this video Kent (the creator of the library) shows how you would test the forms input inputs. The tests would look like this:
import React from 'react'
import {renderIntoDocument, cleanup} from 'react-testing-library'
import {Login} from '../login'
afterEach(cleanup)
test('calls onSubmit with username and password', () => {
const handleSubmit = jest.fn()
const {getByLabelText, getByText} = renderIntoDocument(
<Login onSubmit={handleSubmit} />,
)
getByLabelText(/username/i).value = 'chuck'
getByLabelText(/password/i).value = 'norris'
getByText(/submit/i).click()
expect(handleSubmit).toHaveBeenCalledTimes(1)
expect(handleSubmit).toHaveBeenCalledWith({
username: 'chuck',
password: 'norris',
})
})
The problem is that he did it with plain JavaScript. When doing this with
TypeScript the lines where he sets .value
throw the following errors
[ts] Property 'value' does not exist on type 'HTMLElement'.
How would one test this functionality with TypeScript using React Testing Library? How would you set the input's values?
The typings provided by that library type the return value of
getByLabelText
as type:HTMLElement
. Not all HTML elements havevalue
properties, only things likeHTMLInputElement
do.The
getByLabelText
also has no sort of generic type through which you might be able to affect the output type, so essentially you will need to either unsafely cast the result to typeHTMLInputElement
or you will need to build a helper function that tells TypeScript whether or not the object is the right type:Unsafe cast. All you really need to do is update any calls to
getByLabelText
where you expect it to be a type with avalue
property to:Type validation. This method is a bit safer as you can provide a type validation function that will cause TypeScript to update the type: