I'm migrating from using create-react-app to Vite along with RTL to create and unit testing React applications, so I'm re-testing my tests, which apparently failed at some point on the hasFocus() matcher. In the involved code below I tried to test whether the input fields (email, password) get focused whenever the related labels are clicked. The html tags seemed to match correctly but I got an issue with the inputs matchers (email, password) that actually target the entire document instead of the inputs elements. Below are the component, the unit test, the packages, and the error message installed code, if someone will come across this post and have a solution to fix my issue I'll be grateful:
Login component:
unction Login() {
return (
<div>
<p>Some text</p>
<div>
<label htmlFor="email">Email</label>
<input type="email" name="email" id="email" />
<label htmlFor="password">Password</label>
<input type="text" name="password" id="password" />
<button>OK</button>
</div>
</div>
)
}
unit test:
test('it should check that the email input element will be focused whenever the associated label is clicked', () => {
render(<Login />)
const emailLabel = screen.getByLabelText('Email');
const emailInput = screen.getByRole('textbox', {name: email});
logRoles(emailInput, emailLabel)
fireEvent.click(emailLabel);
expect(emailInput).toHaveFocus();
})
Packages:
{
"name": "my-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"test": "jest"
},
"dependencies": {
"@babel/preset-env": "^7.22.10",
"@babel/preset-react": "^7.22.5",
"identity-obj-proxy": "^3.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"styled-components": "^6.0.7"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react": "^4.0.3",
"eslint": "^8.45.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"jest": "^29.6.2",
"jest-environment-jsdom": "^29.6.2",
"vite": "^4.4.5"
},
"jest": {
"testEnvironment": "jsdom",
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/fileTransformer.js",
"^.+\\.(css|less|scss)$": "identity-obj-proxy"
},
"setupFilesAfterEnv": [
"<rootDir>/setupTests.js"
]
}
}
The error message:
expect(element).toHaveFocus()
Expected element with focus:
<input id="password" name="Password" type="text" />
Received element with focus:
<body><div><div class="App-body"><p>Login to access the full dashboard</p><div class="form"><label for="email">Email</label><input id="email" name="Email" type="email" /><label for="password">Password</label><input id="password" name="Password" type="text" /><button>OK</button></div></div></div></body>
38 | fireEvent.click(passwordLabel);
39 |
> 40 | expect(passwordInput).toHaveFocus();
| ^
41 | });
42 |
at Object.toHaveFocus (src/Login/Login.spec.js:40:25)
The test was failing because it was attempting to interact with and assert on an input element's focus behavior, but the interaction was not behaving as expected. Solution explanation:
test('it should check that the email input element will be focused whenever the associated label is clicked', async () => {
render(<Login />)
const emailInput = screen.getByLabelText('Email');
const emailLabel = screen.getByText('Email');
fireEvent.click(emailLabel);
await waitFor(() => {
expect(emailInput).toHaveFocus();
});
})
Hope this will anyone who comes across this post :)