I'm doing TDD in React (with Typescript, in case that matters) to build a really simple oauth login page. Because I want to be able to support multiple providers, my first test for parameterizing my element looks like this:
it("should have providers", () => {
const { getAllByRole } = render(<Login></Login>);
const providers: string[] = getAllByRole("provider").map((element) => {
return element.innerText;
});
expect(providers).toContain("GitHub");
});
My component is very simplistic at the moment and just has the element hard-coded for now:
const Login = () => {
return (
<div role="login">
<header>Login with SSO</header>
<ul>
<li role="provider">GitHub</li>
</ul>
</div>
);
};
export default Login;
I thought my test would convert all the elements to their text content (eg: string[]
), but instead I'm getting an array of undefined
● Login Component › should have providers
expect(received).toContain(expected) // indexOf
Expected value: "GitHub"
Received array: [undefined]
I think the problem is that innerText
isn't initialized and I am expected to call another field or method, but neither the immediate documentation for interface HTMLElement
or intellisense in VSCode are showing me anything obvious to use instead. Perhaps my approach to testing an item is in a collection could be done altogether differently?
CodePudding user response:
From the byrole/#api doc,
Please note that setting a
role
and/oraria-*
attribute that matches the implicit ARIA semantics is unnecessary and is not recommended as these properties are already set by the browser, and we must not use therole
andaria-*
attributes in a manner that conflicts with the semantics described. For example, abutton
element can't have therole
attribute ofheading
, because thebutton
element has default characteristics that conflict with theheading
role.
You can't set the provider
role for li
, the default and desired role for li
is listitem
set by browser.
Besides, jestjs use jsdom
as its test environment, HTMLELement.innerText
property is not implemented in jsdom
, see issue#1245. You can use Node.textContent instead.
Login.tsx
:
import React from 'react';
const Login = () => {
return (
<div role="login">
<header>Login with SSO</header>
<ul>
<li>GitHub</li>
<li>Google</li>
</ul>
</div>
);
};
export default Login;
Login.test.tsx
:
import { render, screen } from '@testing-library/react';
import React from 'react';
import Login from './Login';
describe('Login', () => {
it('should have providers', () => {
const { getAllByRole } = render(<Login />);
const providers: Array<string | null> = getAllByRole('listitem').map((element) => {
return element.textContent;
});
console.log(providers);
expect(providers).toContain('GitHub');
});
});
test result:
PASS examples/69970652/Login.test.tsx (10.053 s)
Login
✓ should have providers (124 ms)
console.log
[ 'GitHub', 'Google' ]
at Object.<anonymous> (examples/69970652/Login.test.tsx:11:13)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.6 s, estimated 11 s