리액트 테스트 라이브러리를 사용하여 html 태그를 포함하는 텍스트 문자열로 쿼리하려면 어떻게 해야 합니다.
현재 기능하고 있는 솔루션
다음 html 사용:
<p data-testid="foo">Name: <strong>Bob</strong> <em>(special guest)</em></p>
리액트 테스트 라이브러리를 사용할 수 있습니다. getByTestId
를 찾는 방법textContent
:
expect(getByTestId('foo').textContent).toEqual('Name: Bob (special guest)')
더 좋은 방법이 있을까요?
간단하게 다음 html을 사용하고 싶습니다.
<p>Name: <strong>Bob</strong> <em>(special guest)</em></p>
리액트 테스트 라이브러리 사용getByText
다음과 같은 방법을 사용합니다.
expect(getByText('Name: Bob (special guest)')).toBeTruthy()
하지만 이것은 효과가 없다.
그래서 질문은...
Respect Testing Library를 사용하여 태그가 제거된 텍스트 컨텐츠 문자열을 찾는 더 간단한 방법이 있습니까?
업데이트 2
저는 이걸 여러 번 사용해서 도우미를 만들었습니다.다음으로 이 도우미를 사용한 테스트 예를 나타냅니다.
테스트 도우미:
// withMarkup.ts
import { MatcherFunction } from '@testing-library/react'
type Query = (f: MatcherFunction) => HTMLElement
const withMarkup = (query: Query) => (text: string): HTMLElement =>
query((content: string, node: HTMLElement) => {
const hasText = (node: HTMLElement) => node.textContent === text
const childrenDontHaveText = Array.from(node.children).every(
child => !hasText(child as HTMLElement)
)
return hasText(node) && childrenDontHaveText
})
export default withMarkup
테스트:
// app.test.tsx
import { render } from '@testing-library/react'
import App from './App'
import withMarkup from '../test/helpers/withMarkup'
it('tests foo and bar', () => {
const { getByText } = render(<App />)
const getByTextWithMarkup = withMarkup(getByText)
getByTextWithMarkup('Name: Bob (special guest)')
})
업데이트 1
여기 새로운 매처(matcher)가getByTextWithMarkup
작성됩니다.이 기능은 확장됩니다.getByText
테스트에서는, 따라서 거기서 정의되어야 한다. (확실히 함수는 받아들여지도록 갱신될 수 있다.getByText
를 파라미터로 합니다.
import { render } from "@testing-library/react";
import "jest-dom/extend-expect";
test("pass functions to matchers", () => {
const Hello = () => (
<div>
Hello <span>world</span>
</div>
);
const { getByText } = render(<Hello />);
const getByTextWithMarkup = (text: string) => {
getByText((content, node) => {
const hasText = (node: HTMLElement) => node.textContent === text
const childrenDontHaveText = Array.from(node.children).every(
child => !hasText(child as HTMLElement)
)
return hasText(node) && childrenDontHaveText
})
}
getByTextWithMarkup('Hello world')
다음은 Giorgio Polvara의 블로그에서 Testing Library에 대해 몰랐던 5가지 중 4가지에 대한 확실한 답변입니다.
쿼리는 함수도 받아들입니다.
다음과 같은 오류가 발생했을 수 있습니다.
다음 텍스트로 요소를 찾을 수 없습니다.안녕 세계.이는 텍스트가 여러 요소에 의해 분할되었기 때문일 수 있습니다.이 경우 텍스트 매처 기능을 제공하여 매처 유연성을 높일 수 있습니다.
일반적으로 HTML이 다음과 같이 생겼기 때문에 발생합니다.
<div>Hello <span>world</span></div>
해결 방법은 "[...] 텍스트 입력 도구에 대한 함수를 제공할 수 있습니다 [...]"라는 오류 메시지 안에 포함되어 있습니다.
그게 도대체 뭐에 관한 건가요?학생들은 문자열, 정규 표현 또는 함수를 받아들이는 것으로 나타났습니다.
렌더링하는 각 노드에 대해 함수가 호출됩니다.노드 내용과 노드 자체의 두 가지 인수를 수신합니다.노드가 원하는 노드인지에 따라 true 또는 false를 반환하기만 하면 됩니다.
예를 들면 다음과 같습니다.
import { render } from "@testing-library/react";
import "jest-dom/extend-expect";
test("pass functions to matchers", () => {
const Hello = () => (
<div>
Hello <span>world</span>
</div>
);
const { getByText } = render(<Hello />);
// These won't match
// getByText("Hello world");
// getByText(/Hello world/);
getByText((content, node) => {
const hasText = node => node.textContent === "Hello world";
const nodeHasText = hasText(node);
const childrenDontHaveText = Array.from(node.children).every(
child => !hasText(child)
);
return nodeHasText && childrenDontHaveText;
});
});
우리는 무시한다.content
이 경우 "Hello", "world" 또는 빈 문자열 중 하나가 되기 때문입니다.
대신 현재 노드에 올바른 textContent가 있는지 확인합니다. hasText
그러기 위한 작은 도우미 기능입니다.깨끗하게 하기 위해 선언했어요.
그러나 그게 다가 아니야.우리들의div
우리가 찾고 있는 텍스트가 있는 유일한 노드가 아닙니다.예를들면,body
이 경우 텍스트는 동일합니다.필요 이상의 노드가 반환되지 않도록 하기 위해 부모 텍스트와 동일한 텍스트가 있는 하위 노드가 없는지 확인합니다.이렇게 하면 반환되는 노드가 가장 작은 노드인지 확인할 수 있습니다. 즉, 노드가 DOM 트리의 맨 아래에 닫힙니다.
테스트 라이브러리에 대해 몰랐던 나머지 5가지 사항을 읽어보십시오.
「 」를 사용하고 testing-library/jest-dom
를 참조해 주세요. 이 경우에도 하실 수 있습니다.toHaveTextContent
.
expect(getByTestId('foo')).toHaveTextContent('Name: Bob (special guest)')
부분 일치가 필요한 경우 regex 검색 패턴을 사용할 수도 있습니다.
expect(getByTestId('foo')).toHaveTextContent(/Name: Bob/)
패키지 링크입니다.
매칭에서는, 「어느 쪽인가」를 패스 할 수 .{ exact: false }
:
https://testing-library.com/docs/dom-testing-library/api-queries#textmatch
const el = getByText('Name:', { exact: false })
expect(el.textContent).toEqual('Name: Bob (special guest)');
기존 답변은 구식입니다.새로운 *ByRole 쿼리는 다음을 지원합니다.
getByRole('button', {name: 'Bob (special guest)'})
갱신하다
다음 솔루션은 작동하지만 경우에 따라 여러 결과가 반환될 수 있습니다.올바른 실장은 다음과 같습니다.
getByText((_, node) => {
const hasText = node => node.textContent === "Name: Bob (special guest)";
const nodeHasText = hasText(node);
const childrenDontHaveText = Array.from(node.children).every(
child => !hasText(child)
);
return nodeHasText && childrenDontHaveText;
});
가지 .getbyText
:
getByText((_, node) => node.textContent === 'Name: Bob (special guest)')
항상 코드를 입력할 필요가 없도록 도우미 기능에 코드를 넣을 수 있습니다.
const { getByText } = render(<App />)
const getByTextWithMarkup = (text) =>
getByText((_, node) => node.textContent === text)
여러 요소의 일치를 피하기 위해 일부 사용 사례에서는 텍스트 컨텐츠가 실제로 있는 요소만 반환하는 경우 원치 않는 상위 요소를 필터링합니다.
expect(
// - content: text content of current element, without text of its children
// - element.textContent: content of current element plus its children
screen.getByText((content, element) => {
return content !== '' && element.textContent === 'Name: Bob (special guest)';
})
).toBeInTheDocument();
위의 내용은 테스트 중인 요소에 대한 몇 가지 콘텐츠가 필요하므로 다음과 같은 경우에 사용할 수 있습니다.
<div>
<p>Name: <strong>Bob</strong> <em>(special guest)</em></p>
</div>
...하지만 만약<p>
에는 자체 텍스트 내용이 없습니다.
<div>
<p><em>Name: </em><strong>Bob</strong><em> (special guest)</em></p>
</div>
따라서 일반적인 솔루션이라면 다른 답변이 확실히 더 낫습니다.
다른 답변은 타입 에러 또는 전혀 기능하지 않는 코드로 종료.이건 나한테 효과가 있었어.
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」screen.*
import React from 'react';
import { screen } from '@testing-library/react';
/**
* Preparation: generic function for markup
* matching which allows a customized
* /query/ function.
**/
namespace Helper {
type Query = (f: MatcherFunction) => HTMLElement
export const byTextWithMarkup = (query: Query, textWithMarkup: string) => {
return query((_: string, node: Element | null) => {
const hasText = (node: Element | null) => !!(node?.textContent === textWithMarkup);
const childrenDontHaveText = node ? Array.from(node.children).every(
child => !hasText(child as Element)
) : false;
return hasText(node) && childrenDontHaveText
})}
}
/**
* Functions you use in your test code.
**/
export class Jest {
static getByTextWithMarkup = (textWithMarkup: string) => Helper.byTextWithMarkup(screen.getByText, textWithMarkup);
static queryByTextWith = (textWithMarkup: string) => Helper.byTextWithMarkup(screen.queryByText, textWithMarkup);
}
사용방법:
Jest.getByTextWithMarkup("hello world");
Jest.queryByTextWithMarkup("hello world");
이제 'toHaveTextContent' 메서드를 사용하여 텍스트를 하위 문자열 또는 마크업과 일치시킬 수 있습니다.
예를들면
const { container } = render(
<Card name="Perro Loko" age="22" />,
);
expect(container).toHaveTextContent('Name: Perro Loko Age: 22');
getByText('Hello World'); // full string match
getByText('llo Worl', { exact: false }); // substring match
getByText('hello world', { exact: false }); // ignore case-sensitivity
출처 : https://testing-library.com/docs/react-testing-library/cheatsheet/ #whttp://https://testing-library.com/docs/react-testing-library/cheatsheet/
언급URL : https://stackoverflow.com/questions/55509875/how-to-query-by-text-string-which-contains-html-tags-using-react-testing-library
'programing' 카테고리의 다른 글
React에서 .map()을 사용하는 경우의 빈 배열 처리 (0) | 2023.02.22 |
---|---|
JSON을 사용하여 개체 직렬화/비직렬화 사전.그물 (0) | 2023.02.22 |
특정 JDBC 접속의 데이터베이스 유형을 판별하려면 어떻게 해야 합니까? (0) | 2023.02.22 |
Oracle이 없는 경우 삽입 (0) | 2023.02.22 |
Preact에 의해 잘못된 컴포넌트가 렌더링됨 (0) | 2023.02.22 |