it-source

반응 선택 테스트 방법(반응 선택)

criticalcode 2023. 3. 2. 22:19
반응형

반응 선택 테스트 방법(반응 선택)

App.js

import React, { Component } from "react";
import Select from "react-select";

const SELECT_OPTIONS = ["FOO", "BAR"].map(e => {
  return { value: e, label: e };
});

class App extends Component {
  state = {
    selected: SELECT_OPTIONS[0].value
  };

  handleSelectChange = e => {
    this.setState({ selected: e.value });
  };

  render() {
    const { selected } = this.state;
    const value = { value: selected, label: selected };
    return (
      <div className="App">
        <div data-testid="select">
          <Select
            multi={false}
            value={value}
            options={SELECT_OPTIONS}
            onChange={this.handleSelectChange}
          />
        </div>
        <p data-testid="select-output">{selected}</p>
      </div>
    );
  }
}

export default App;

App.test.js

import React from "react";
import {
  render,
  fireEvent,
  cleanup,
  waitForElement,
  getByText
} from "react-testing-library";
import App from "./App";

afterEach(cleanup);

const setup = () => {
  const utils = render(<App />);
  const selectOutput = utils.getByTestId("select-output");
  const selectInput = document.getElementById("react-select-2-input");
  return { selectOutput, selectInput };
};

test("it can change selected item", async () => {
  const { selectOutput, selectInput } = setup();
  getByText(selectOutput, "FOO");
  fireEvent.change(selectInput, { target: { value: "BAR" } });
  await waitForElement(() => getByText(selectOutput, "BAR"));
});

이 최소한의 예는 브라우저에서 예상대로 작동하지만 테스트는 실패합니다.의 onChange 핸들러가 호출되지 않은 것 같습니다.테스트에서 onChange 콜백을 트리거하려면 어떻게 해야 합니까?fireEvent를 실행할 요소를 찾는 권장 방법은 무엇입니까?감사해요.

제 프로젝트에서는 리액트 테스트(라이브러리)와 재스트돔을 사용하고 있습니다.같은 문제에 부딪혔습니다.조사한 결과, 스레드에 근거해 해결 방법을 찾았습니다.https://github.com/airbnb/enzyme/issues/400

렌더의 최상위 함수는 개별 단계뿐만 아니라 비동기여야 합니다.

이 경우 포커스이벤트를 사용할 필요가 없으며 여러 값을 선택할 수 있습니다.

또한 getSelectItem 내부에는 비동기 콜백이 있어야 합니다.

const DOWN_ARROW = { keyCode: 40 };

it('renders and values can be filled then submitted', async () => {
  const {
    asFragment,
    getByLabelText,
    getByText,
  } = render(<MyComponent />);

  ( ... )

  // the function
  const getSelectItem = (getByLabelText, getByText) => async (selectLabel, itemText) => {
    fireEvent.keyDown(getByLabelText(selectLabel), DOWN_ARROW);
    await waitForElement(() => getByText(itemText));
    fireEvent.click(getByText(itemText));
  }

  // usage
  const selectItem = getSelectItem(getByLabelText, getByText);

  await selectItem('Label', 'Option');

  ( ... )

}

이것은 RTL:D에 대해 가장 자주 묻는 질문입니다.

최선의 전략은 (또는 테스트 프레임워크에서는 동등한 것을) 사용하여 선택을 조롱하고 대신 HTML 선택을 렌더링하는 것입니다.

왜 이것이 최선의 방법인지에 대한 자세한 내용을 위해 이 사례에도 적용되는 내용을 작성했습니다.OP는 Material-UI의 선택에 대해 물었지만 생각은 같다.

원래 질문과 내 답변:

왜냐하면 당신은 그 UI를 제어할 수 없기 때문입니다.서드파티 모듈에 정의되어 있습니다.

두 가지 옵션이 있습니다.

재료 라이브러리가 작성하는 HTML을 파악하여 컨테이너를 사용할 수 있습니다.querySelector는 해당 요소를 찾아 상호 작용합니다.시간이 좀 걸리지만 가능할 거예요.이 모든 작업을 완료한 후에는 새로운 릴리스마다 DOM 구조가 크게 변경되지 않도록 해야 합니다.그렇지 않으면 모든 테스트를 갱신해야 할 수도 있습니다.

다른 옵션은 Material-UI가 작동하며 사용자가 사용할 수 있는 구성 요소를 만든다는 것을 신뢰하는 것입니다.이 신뢰성에 근거해, 테스트의 컴포넌트를 간단하게 교환할 수 있습니다.

예, 옵션 1은 사용자에게 표시되는 내용을 테스트하지만 옵션 2는 유지보수가 더 쉽습니다.

제 경험상 두 번째 옵션은 괜찮지만, 물론 사용 사례는 다를 수 있으며 실제 구성 요소를 테스트해야 할 수도 있습니다.

다음 예시는 선택 항목을 조롱하는 방법을 보여 줍니다.

jest.mock("react-select", () => ({ options, value, onChange }) => {
  function handleChange(event) {
    const option = options.find(
      option => option.value === event.currentTarget.value
    );
    onChange(option);
  }
  return (
    <select data-testid="select" value={value} onChange={handleChange}>
      {options.map(({ label, value }) => (
        <option key={value} value={value}>
          {label}
        </option>
      ))}
    </select>
  );
});

여기서 더 읽을 수 있습니다.

마지막으로, 이를 지원하는 라이브러리가 있습니다.https://testing-library.com/docs/ecosystem-react-select-event.싱글 셀렉트 또는 셀렉트 멀티 모두 완벽하게 동작합니다.

터에서@testing-library/react문서:

import React from 'react'
import Select from 'react-select'
import { render } from '@testing-library/react'
import selectEvent from 'react-select-event'

const { getByTestId, getByLabelText } = render(
  <form data-testid="form">
    <label htmlFor="food">Food</label>
    <Select options={OPTIONS} name="food" inputId="food" isMulti />
  </form>
)
expect(getByTestId('form')).toHaveFormValues({ food: '' }) // empty select

// select two values...
await selectEvent.select(getByLabelText('Food'), ['Strawberry', 'Mango'])
expect(getByTestId('form')).toHaveFormValues({ food: ['strawberry', 'mango'] })

// ...and add a third one
await selectEvent.select(getByLabelText('Food'), 'Chocolate')
expect(getByTestId('form')).toHaveFormValues({
  food: ['strawberry', 'mango', 'chocolate'],
})

https://github.com/romgain/react-select-event에서 멋진 패키지를 보내주셔서 감사합니다!

@ 모모모모모의 대답과 비슷하게, mom 변 찬 mom 니 습 선im다써 similar to서omo @'im from, helper @ a를도 answer미택하를react-select유형 스크립트에 있습니다.스크립트 습 니 type다script?

도우미 파일:

import { getByText, findByText, fireEvent } from '@testing-library/react';

const keyDownEvent = {
    key: 'ArrowDown',
};

export async function selectOption(container: HTMLElement, optionText: string) {
    const placeholder = getByText(container, 'Select...');
    fireEvent.keyDown(placeholder, keyDownEvent);
    await findByText(container, optionText);
    fireEvent.click(getByText(container, optionText));
}

사용방법:

export const MyComponent: React.FunctionComponent = () => {
    return (
        <div data-testid="day-selector">
            <Select {...reactSelectOptions} />
        </div>
    );
};
it('can select an option', async () => {
    const { getByTestId } = render(<MyComponent />);
    // Open the react-select options then click on "Monday".
    await selectOption(getByTestId('day-selector'), 'Monday');
});

간단한 테스트 방법은 사용자가 수행해야 할 작업을 수행하는 것입니다.

  • 선택 필드를 클릭합니다.
  • 드롭다운 목록에서 항목 중 하나를 클릭합니다.
function CustomSelect() {

  const colourOptions = [
    { value: 'orange', label: 'Orange', color: '#FF8B00' },
    { value: 'yellow', label: 'Yellow', color: '#FFC400' }
  ]

  return <Select 
    aria-label="my custom select" 
    options={colourOptions}
    //... props  
  />
}
import { act, render, screen } from '@testing-library/react'; 
import userEvent from '@testing-library/user-event';
// another imports

test('show selected item...', async () => {
  const { getByText, getByLabelText } = render(<CustomSelect />);

  expect(getByText('Orange')).not.toBeInTheDocument();
  
  const myCustomSelect = getByLabelText(/my custom select/i);
  await act(async () => userEvent.click(myCustomSelect));

  const selectedItem = getByText('Orange');
  await act(async () => userEvent.click(selectedItem));

  expect(getByText('Orange')).toBeInTheDocument();
});

이 솔루션은 나에게 효과가 있었다.

fireEvent.change(getByTestId("select-test-id"), { target: { value: "1" } });

그게 고군분투하는 사람들에게 도움이 되길 바라.

In case you are not using a 를 사용하지 않는 경우label element, the way to go with 요소, 사용 방법react-select-event is:다음과 같습니다.

const select = screen.container.querySelector(
  "input[name='select']"
);

selectEvent.select(select, "Value");
export async function selectOption(container: HTMLElement, optionText: string) {
  let listControl: any = '';
  await waitForElement(
    () => (listControl = container.querySelector('.Select-control')),
  );
  fireEvent.mouseDown(listControl);
  await wait();
  const option = getByText(container, optionText);
  fireEvent.mouseDown(option);
  await wait();
}

메모: 컨테이너: 선택 상자용 컨테이너(예: container = getBy)TestId('secelectTestId')

리액트 테스트 라이브러리 스펙트럼 채팅에서 찾을 수 있는 리액트 선택 조롱이나 별도의 라이브러리가 필요 없는 대체 솔루션.

으로는, 는 이 말을 .container.querySelectorRTL이 보다 내광성이 높은 셀렉터를 선호하지 않도록 권고한다.

어떤 이유로든 같은 이름의 라벨이 있는 경우 이것을 사용합니다.

const [firstLabel, secondLabel] = getAllByLabelText('State');
    await act(async () => {
      fireEvent.focus(firstLabel);
      fireEvent.keyDown(firstLabel, {
        key: 'ArrowDown',
        keyCode: 40,
        code: 40,
      });

      await waitFor(() => {
        fireEvent.click(getByText('Alabama'));
      });

      fireEvent.focus(secondLabel);
      fireEvent.keyDown(secondLabel, {
        key: 'ArrowDown',
        keyCode: 40,
        code: 40,
      });

      await waitFor(() => {
        fireEvent.click(getByText('Alaska'));
      });
    });

또는 data-testid를 사용하여 섹션을 쿼리하는 방법이 있는 경우 다음 중 하나를 사용할 수 있습니다.

within(getByTestId('id-for-section-A')).getByLabelText('Days')
within(getByTestId('id-for-section-B')).getByLabelText('Days')

왜냐하면 나는 포장된 컴포넌트를 테스트하고 싶었기 때문이다.react-select<select>원소가 작동하지 않았을 거예요그래서 저는 패키지의 자체 테스트에서 사용하는 것과 동일한 접근방식을 사용하게 되었습니다. 즉, 이 접근방식은className소품에서, 그리고 그것을 함께 사용합니다.querySelector()테스트에서 렌더링된 요소에 액세스하려면:

const BASIC_PROPS: BasicProps = {
  className: 'react-select',
  classNamePrefix: 'react-select', 
  // ...
};

let { container } = render(
  <Select {...props} menuIsOpen escapeClearsValue isClearable />
);
fireEvent.keyDown(container.querySelector('.react-select')!, {
  keyCode: 27,
  key: 'Escape',
});
expect(
  container.querySelector('.react-select__single-value')!.textContent
).toEqual('0');

모든 사용자에게 - 클릭이 아닌 옵션으로 fireEvent.mouseDown을 선택하여 선택할 수 있습니다.

언급URL : https://stackoverflow.com/questions/55575843/how-to-test-react-select-with-react-testing-library

반응형