Sage / carbon

Carbon by Sage | ReactJS UI Component Library
https://carbon.sage.com
Apache License 2.0
276 stars 86 forks source link

Select: React Testing Library doesn't render options on opening #6749

Closed damienrobson-sage closed 3 months ago

damienrobson-sage commented 4 months ago

Description

When running unit tests with React Testing Library, Select components no longer render their child Option values when clicking, either through fireEvent or through userEvent. The list container is rendered, but it has no option entries.

Reproduction

https://carbon.sage.com/?path=/docs/select--docs

Steps to reproduce

Create the following test file:

import React from 'react';
import {
  cleanup,
  render,
  screen,
} from '@os/react-testing';
import userEvent from '@testing-library/user-event';
import { Select, Option } from 'carbon-react/lib/components/select';

describe('Select', () => {
  const options = [
    { id: '1', text: 'England', value: 'ENG' },
    { id: '2', text: 'Scotland', value: 'SCO' },
    { id: '3', text: 'Ireland', value: 'IRE' },
    { id: '4', text: 'Wales', value: 'WAL' },
  ];

  beforeEach(cleanup);

  beforeAll(() => {
    HTMLElement.prototype.scrollTo = () => {};
  });

  it('allows selection changes to be made', async () => {
    const user = userEvent.setup();
    render(
      <Select>
        {options.map(
          ({ id: optionId, text: optionText, value: optionValue }) => (
            <Option
              id={optionId}
              text={optionText}
              value={optionValue}
              key={optionId || optionValue}
            />
          )
        )}
      </Select>
    );

    const dropdown = screen.getByText('Please Select...');

    user.click(dropdown);

    const walesValue = await screen.findByText('Wales');

    expect(walesValue).toBeDefined();

    screen.debug();
  });
});

Running it will produce HTML output, in amongst which is the following which demonstrates that there are no options rendered:

<ul
  class="sc-gPEVay fTyqzB"
  data-element="select-list"
  id="cb58afb8-6e3a-13fa-9b86-fa6ef6f63cbb"
  role="listbox"
  tabindex="-1"
/>

JIRA ticket numbers (Sage only)

No response

Suggested solution

No response

Carbon version

135.1.2

Design tokens version

No response

Relevant browsers

Chrome

Relevant OSs

MacOS

Additional context

No response

Confidentiality

edleeks87 commented 4 months ago

Investigated further and it looks like we need to mock the bounding rectangle in the test setup. See below for an example of how to test Select in RTL, we should use this ticket to update our docs and consider whether we should export some form of setup function for this.


import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Select, Option } from "carbon-react/lib/components/select";
import { setupMatchMediaMock } from "carbon-react/lib/__spec_helper__/mock-match-media";
import setupScrollToMock from "carbon-react/lib/__spec_helper__/mock-element-scrollto";

setupMatchMediaMock();
beforeAll(() => {
  global.window.ResizeObserver = jest.fn().mockImplementation(() => ({
    disconnect: jest.fn(),
    observe: jest.fn(),
    unobserve: jest.fn(),
  }));

  setupScrollToMock();
  Element.prototype.getBoundingClientRect = () => ({
    width: 100,
    height: 100,
    top: 100,
    left: 100,
    right: 100,
    bottom: 100,
    x: 100,
    y: 100,
    toJSON: jest.fn(),
  });
  Element.prototype.scrollIntoView = jest.fn();
});

test("renders a select component", async () => {
  const user = userEvent.setup();
  render(
    <Select onChange={jest.fn()} value="" label="foo" data-testid="select">
      <Option value="1" text="foo option" />
    </Select>
  );

  const select = screen.getByRole("combobox");
  await user.click(select);

  expect(screen.getByText("foo option")).toBeVisible();
});
edleeks87 commented 4 months ago

FE-6646

sianford commented 3 months ago

Fixed by https://github.com/Sage/carbon/pull/6769