You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest测试日期函数时出现Invalid hook call错误如何解决

问题原因

Invalid hook call报错的核心原因是违反了React Hook调用规则:

  • findNextClosestDate是普通JavaScript工具函数,既不是React函数组件,也不是自定义Hook
  • 你在这个普通函数内部直接调用了useAppSelector这个React Hook,而Hook仅允许在React函数组件顶层、自定义Hook顶层调用,普通函数直接调用Hook无论在业务运行环境还是Jest直接调用的测试环境,都会触发该报错。
修复方案

优先选择第一种方案,保持工具函数纯函数特性,易维护易测试。

方案1:将依赖的可变值作为入参传入(推荐)

把原本在函数内部通过Hook获取的language改为函数入参,移除函数内部的Hook调用,让findNextClosestDate成为纯函数。
修改后的工具函数代码:

export function findNextClosestDate(
  array: string[] | undefined,
  target: Date,
  language: string // 新增语言入参
): string | undefined {
  const targetDate = target.getTime();

  if (!array) return undefined;

  const closestDateFromArray = array.reduce(
    (accumulator: string | undefined, currentValue: string) => {
      const currentValueTime = new Date(currentValue).getTime();
      const accumulatedTime = accumulator && new Date(accumulator).getTime();
      if (
        currentValueTime > targetDate &&
        (!accumulatedTime || currentValueTime < accumulatedTime)
      ) {
        return currentValue;
      }
      return accumulator;
    },
    undefined
  );

  return closestDateFromArray
    ? new Date(closestDateFromArray).toLocaleString(language, {
        month: "long",
        day: "numeric",
      })
    : undefined;
}

对应修改测试用例,调用时传入测试环境指定的语言参数即可:

import { findNextClosestDate } from "./findNextClosestDate";

describe("findNextClosestDate", () => {
  it("return correct closest next date", () => {
    const array = [
      "2022-06-20 08:40:00",
      "2022-06-01 11:08:00",
      "2022-06-08 10:48:00",
      "2022-05-03 08:03:00",
      "2022-05-01 09:58:00",
      "2022-06-19 08:41:00",
    ];
    const target = new Date("2022-05-24 12:04:00");
    const expected = "June 1";
    // 传入en-US匹配英文日期格式化结果
    expect(findNextClosestDate(array, target, "en-US")).toEqual(expected);
  });
});

业务组件中调用该工具函数时,在组件层调用Hook拿到语言值再传入即可:

const YourComponent = () => {
  const language = useAppSelector(selectLocalizationLanguage);
  // 其余业务逻辑
  const nextDate = findNextClosestDate(dateList, targetDate, language);
  return <span>{nextDate}</span>
}

方案2:改造为自定义Hook(不推荐)

如果一定要在函数内部获取Redux状态,可将函数重命名为use开头的自定义Hook,测试时需要配合React测试库、Redux Provider包裹进行测试,这种写法会让工具函数和React生态强耦合,测试成本更高。
改造后的Hook代码:

import { selectLocalizationLanguage } from "domain/localization/localizationSlice";
import { useAppSelector } from "domain/storeHooks";

// 函数名以use开头,符合自定义Hook命名规范
export function useFindNextClosestDate(
  array: string[] | undefined,
  target: Date
): string | undefined {
  const language = useAppSelector(selectLocalizationLanguage);
  const targetDate = target.getTime();

  if (!array) return undefined;

  const closestDateFromArray = array.reduce(
    (accumulator: string | undefined, currentValue: string) => {
      const currentValueTime = new Date(currentValue).getTime();
      const accumulatedTime = accumulator && new Date(accumulator).getTime();
      if (
        currentValueTime > targetDate &&
        (!accumulatedTime || currentValueTime < accumulatedTime)
      ) {
        return currentValue;
      }
      return accumulator;
    },
    undefined
  );

  return closestDateFromArray
    ? new Date(closestDateFromArray).toLocaleString(`${language}`, {
        month: "long",
        day: "numeric",
      })
    : undefined;
}

对应测试用例需要用renderHook配合Store包装器:

import { renderHook } from "@testing-library/react";
import { Provider } from "react-redux";
import store from "domain/store";
import { useFindNextClosestDate } from "./findNextClosestDate";

describe("findNextClosestDate", () => {
  it("return correct closest next date", () => {
    const array = [
      "2022-06-20 08:40:00",
      "2022-06-01 11:08:00",
      "2022-06-08 10:48:00",
      "2022-05-03 08:03:00",
      "2022-05-01 09:58:00",
      "2022-06-19 08:41:00",
    ];
    const target = new Date("2022-05-24 12:04:00");
    const expected = "June 1";

    const wrapper = ({ children }) => <Provider store={store}>{children}</Provider>;
    const { result } = renderHook(() => useFindNextClosestDate(array, target), { wrapper });
    expect(result.current).toEqual(expected);
  });
});

内容的提问来源于stack exchange,提问作者Seweryn Kuliga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:21:44