Jest.js 如何为布尔值做一个单元测试,比如'loading'标签?

h79rfbju  于 2023-05-27  发布在  Jest
关注(0)|答案(1)|浏览(168)

如何测试依赖于要呈现的布尔变量的标签?例如,如果变量isLoading为true,则它将呈现<p>Loading...</p>
我试着去测试,却得到一个错误:

// AutoComplete.test.tsx

import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import AutoComplete from './AutoComplete';

describe('AutoComplete component', () => {
  test('renders loading state when isLoading is true', () => {
    render(<AutoComplete />);
    const loadingElement = screen.getByText('Loading...');
    expect(loadingElement).toBeInTheDocument();
  });

  test('renders "No countries found" when inputValue is at least 3 characters and searchResults is empty', () => {
    render(<AutoComplete />);
    const inputElement = screen.getByPlaceholderText('Search Country...');
    userEvent.type(inputElement, 'abc');
    const noCountriesElement = screen.getByText('No countries found');
    expect(noCountriesElement).toBeInTheDocument();
  });
});
// AutoComplete.tsx

import React, { useContext, useState, useEffect, useCallback } from 'react';
import { DataContext } from 'src/contexts';
import { Country } from 'src/types';
import Input from '../Input';
import './index.css';

const AutoComplete = () => {
  const { inputValue } = useContext(DataContext);
  const [searchResults, setSearchResults] = useState<Country[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  
  const fetchData = async (value: string) => {
    setIsLoading(true);

    try {
      const response = await fetch(
        `https://restcountries.com/v3/name/${value}`
      );

      if (response.ok) {
        const data = await response.json();
        setSearchResults(data);
      } else {
        setSearchResults([]);
      }
    } catch (error) {
      console.error('Error fetching data:', error);
    }

    setIsLoading(false);
  };

  const filterResults = useCallback(
    (results: Country[]) => {
      return results.filter((country) =>
        country.name.common.toLowerCase().includes(inputValue)
      );
    },
    [inputValue]
  );
  
  const highlightSearchTerm = (text: string) => {
    const regex = new RegExp(`(${inputValue})`, 'gi');    
    return text.replace(regex, '<span class="highlight">$1</span>');
  };

  useEffect(() => {
    if (inputValue && inputValue.length >= 3) {
      fetchData(inputValue);
    } else {
      setSearchResults([]);
    }
  }, [inputValue]);

  return (
    <div>
      <h1>Auto Complete</h1>
      <Input />

      <h2>Results: </h2>

      {isLoading ? (
        <p>Loading...</p>
      ) : inputValue?.length >= 3 && searchResults.length === 0 ? (
        <p>No countries found</p>
      ) : (
        <ul>
          {filterResults(searchResults).map((country, index) => (
            <li key={index}>
              <h3
                dangerouslySetInnerHTML={{
                  __html: highlightSearchTerm(country.name.common),
                }}
              />
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default AutoComplete;
aurhwmvo

aurhwmvo1#

如果你想让Loading...文本出现在屏幕上,你必须触发fetchData函数,这是一个设置isLoadingtrue。您可以通过模拟用户输入并保证fetch函数不返回任何数据来做到这一点。

import userEvent from '@testing-library/user-event'

describe('AutoComplete component', async () => {
  test('renders loading state when isLoading is true', () => {
    const user = userEvent.setup()
    const testText = "te"

    render(<AutoComplete />);

    // INFO: use the query that best suit your needs to access the input
    const autoCompleteInput = screen.getByLabelText(/input/i)

    await user.type(autocompleteInput, testText)

    const loadingElement = screen.getByText('Loading...');
    expect(loadingElement).toBeInTheDocument();
  });
})

我没有测试过这段代码,我不知道testing-library是否会在文本出现在屏幕上时捕获它,但你可能必须使用mock fetch,原因有二:

  • 控件需要一些时间来应答,以便Loading...有机会出现在屏幕上。
  • 将您的测试与外部隔离开来,并控制自动完成数据(这是您可能希望对每个其他测试用例都做的事情,而不仅仅是我们在这里关注的这个)

相关问题