Reactjs Jest тест не проходит с ошибкой: неопределено не является итерируемым объектом (нельзя прочитать свойство Symbol(Symbol.iterator))

Вопросы и ответы

Я пытаюсь написать простой тест, в котором пытаюсь протестировать форму регистрации, отображаемую на странице в проекте Reactjs, но получаю ошибку типа TypeError: undefined is not iterable (не удается прочитать свойство Symbol(Symbol.iterator)). Я пытался обновить мока useSearchParam, но безуспешно. Пожалуйста, помогите.

import React from "react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { createMemoryHistory } from "history";
import { Router } from "react-router-dom";
import RegisterPage from "./RegisterPage";
import { useAuth } from "../../hooks/useAuth";
import { useForm } from "react-hook-form";
import ReCAPTCHA from "react-google-recaptcha";

// Мока зависимости
jest.mock("react-hook-form", () => ({
  useForm: jest.fn(),
}));
jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
  useNavigate: jest.fn(),
  useSearchParams: jest
    .fn()
    .mockReturnValue([new URLSearchParams(), jest.fn()]), // Возвращает мокированный массив
  useLocation: jest.fn().mockReturnValue({ pathname: "/register" }),
}));

jest.mock("../../hooks/useAuth", () => ({
  useAuth: jest.fn(),
}));
jest.mock("react-google-recaptcha", () => jest.fn(() => <div>ReCAPTCHA</div>));

describe("RegisterPage", () => {
  const mockRegister = jest.fn();
  const mockNavigate = jest.fn();
  const mockGetValues = jest.fn();
  const mockCaptchaRef = { current: { getValue: jest.fn(), reset: jest.fn() } };

  beforeEach(() => {
    useForm.mockReturnValue({
      handleSubmit: jest.fn((fn) => (e) => {
        e.preventDefault();
        fn();
      }),
      register: jest.fn(),
      getValues: mockGetValues,
      formState: { errors: {} },
    });

    useAuth.mockReturnValue({
      user: null,
      register: mockRegister,
    });

    jest.spyOn(React, "useRef").mockReturnValue(mockCaptchaRef);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  test("рендерит RegisterPage", () => {
    const history = createMemoryHistory();
    render(
      <Router location={history.location} navigator={history}>
        <RegisterPage />
      </Router>
    );

    expect(screen.getByText("Регистрация")).toBeInTheDocument();
    expect(screen.getByLabelText("Имя")).toBeInTheDocument();
    expect(screen.getByLabelText("Электронная почта")).toBeInTheDocument();
    expect(screen.getByLabelText("Пароль")).toBeInTheDocument();
    expect(screen.getByLabelText("Подтвердите пароль")).toBeInTheDocument();
    expect(screen.getByLabelText("Адрес")).toBeInTheDocument();
    expect(screen.getByText("ReCAPTCHA")).toBeInTheDocument();
    expect(screen.getByText("Регистрация")).toBeInTheDocument();
    expect(screen.getByText("Уже есть аккаунт?")).toBeInTheDocument();
  });

Ответ

Ошибка undefined is not iterable (cannot read property Symbol(Symbol.iterator)) может возникнуть в вашем тесте в результате неправильной имитации хука useSearchParams из react-router-dom. Давайте разберем код и внесем необходимые исправления для устранения данной ошибки.

Анализ и Решение

  1. Проверка имитации useSearchParams: Ваша текущая имитация useSearchParams возвращает массив с new URLSearchParams() и функцией. Это может быть причиной ошибки, если где-то в компоненте RegisterPage используются в виде итерации (например, для map или других методов, которые требуют итерируемый объект).

  2. Изменение на коректные значения по умолчанию: Вместо создания нового экземпляра URLSearchParams, попробуйте вернуть значение, которое точно будет итерироваться. Например, можно вернуть пустой массив или другой корректный объект.

  3. Исправление теста и его зависимостей: Убедитесь, что каждый хук и все зависимости корректно замокированы.

Вот исправленный код вашего теста:

import React from "react";
import { render, screen } from "@testing-library/react";
import { createMemoryHistory } from "history";
import { Router } from "react-router-dom";
import RegisterPage from "./RegisterPage";
import { useAuth } from "../../hooks/useAuth";
import { useForm } from "react-hook-form";
import ReCAPTCHA from "react-google-recaptcha";

// Mock dependencies
jest.mock("react-hook-form", () => ({
  useForm: jest.fn(),
}));
jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
  useNavigate: jest.fn(),
  useSearchParams: jest.fn().mockReturnValue([new URLSearchParams(), jest.fn()]), // Вернуть завершающий объект
  useLocation: jest.fn().mockReturnValue({ pathname: "/register" }),
}));

jest.mock("../../hooks/useAuth", () => ({
  useAuth: jest.fn(),
}));
jest.mock("react-google-recaptcha", () => jest.fn(() => <div>ReCAPTCHA</div>));

describe("RegisterPage", () => {
  const mockRegister = jest.fn();
  const mockNavigate = jest.fn();
  const mockGetValues = jest.fn();
  const mockCaptchaRef = { current: { getValue: jest.fn(), reset: jest.fn() } };

  beforeEach(() => {
    useForm.mockReturnValue({
      handleSubmit: jest.fn((fn) => (e) => {
        e.preventDefault();
        fn();
      }),
      register: jest.fn(),
      getValues: mockGetValues,
      formState: { errors: {} },
    });

    useAuth.mockReturnValue({
      user: null,
      register: mockRegister,
    });

    jest.spyOn(React, "useRef").mockReturnValue(mockCaptchaRef);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  test("renders RegisterPage", () => {
    const history = createMemoryHistory();
    render(
      <Router location={history.location} navigator={history}>
        <RegisterPage />
      </Router>
    );

    expect(screen.getByText("Register")).toBeInTheDocument();
    expect(screen.getByLabelText("Name")).toBeInTheDocument();
    expect(screen.getByLabelText("Email")).toBeInTheDocument();
    expect(screen.getByLabelText("Password")).toBeInTheDocument();
    expect(screen.getByLabelText("Confirm Password")).toBeInTheDocument();
    expect(screen.getByLabelText("Address")).toBeInTheDocument();
    expect(screen.getByText("ReCAPTCHA")).toBeInTheDocument();
    expect(screen.getByText("Register")).toBeInTheDocument();
    expect(screen.getByText("Already a user?")).toBeInTheDocument();
  });
});

Заключение

Теперь ваш тестовый код должен корректно работать без ошибки undefined is not iterable. Убедитесь, что компонент RegisterPage правильно обрабатывает возвращаемые параметры, и что все необходимые импорты и шутки замокированы корректно. Если ошибка все еще возникает, вам стоит проверить используемые вами зависимости и версии библиотек, а также логику самого компонента `.

Оцените материал
Добавить комментарий

Капча загружается...