Home > Back-end >  React TDD - How do I get inner text?
React TDD - How do I get inner text?

Time:11-16

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/or aria-* 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 the role and aria-* attributes in a manner that conflicts with the semantics described. For example, a button element can't have the role attribute of heading, because the button element has default characteristics that conflict with the heading 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
  • Related