带有 sinon 存根的模拟反应自定义钩子

问题描述 投票:0回答:1

我有一个自定义挂钩,可以返回 api 调用。它看起来像这样:

export const useApiData = () => {
    const queryClient = useQueryClient();
    const [networkError, setNetworkError] = useState<string>(null);

    const getCase = (caseId: number) =>
        useQuery({
            queryKey: `case-${caseId}`,
            queryFn: (): Promise<AxiosResponse<CaseDto>> => CASE_API.api.getCase(caseId),
            staleTime: Infinity,
            suspense: true,
        });

    const api = {
        getCase,
    };

    return { api, networkError };
};

我想用 sinon 存根来存根这个自定义钩子:

export function mockGetCase(sinonSandbox: SinonSandbox = sinon.createSandbox()) {
    const { api } = useApiData();
    sinonSandbox.stub(api, "getCase").callsFake(() => {
        return () => Promise.resolve(caseMockApiData);
    });

    return sinonSandbox;
}

但是,这行不通,因为我在 React 组件之外调用 hook:

警告:挂机无效。钩子只能在 功能组件的主体。这可能发生在其中一个 以下原因:

  1. 你可能有不匹配的 React 版本和渲染器(例如 React DOM)
  2. 你可能违反了 Hooks 规则
  3. 您可能在同一个应用程序中有多个 React 副本有关如何调试的提示,请参阅https://reactjs.org/link/invalid-hook-call

如何使用 sinon 存根自定义 React Hook?

并解决这个问题。

我在我的组件中使用这样的钩子:

const { caseId } = useCase();
const { api } = useApiData();
const {
    data: { data: case },
} = api.getCase(caseId);

CASE_API 看起来像这样:

export const CASE_API: CaseApi<CaseDto> = useApi(
    new CaseApi({ baseURL: environment.url.case }),
    "case",
    "gcp"
);

钩子

useApi
看起来像这样:

export function useApi<T extends AxiosClient>(api: T, app: string, cluster: string): T {
    api.instance.interceptors.request.use(
        async (config: InternalAxiosRequestConfig) => {
            const secHeaders = await createDefaultHeaders(app, cluster);
            Object.assign(config.headers, secHeaders);

            return config;
        },
        function (error) {
            // error handling here
            return Promise.reject(error);
        }
    );

    api.instance.interceptors.response.use(
        function (response) {
            return response;
        },
        function (error) {
            return Promise.reject(error);
        }
    );

    return api;
}

const createDefaultHeaders = async (app: string, cluster: string) => {
    const idToken = await SecuritySessionUtils.getSecurityTokenForApp(app, cluster);
    const correlationId = SecuritySessionUtils.getCorrelationId();
    return {
        Authorization: "Bearer " + idToken,
        "Content-type": "application/json; charset=UTF-8",
        "X-Correlation-ID": correlationId,
        "Call-Id": correlationId,
        "Consumer-Id": SecuritySessionUtils.getAppName(),
    };
};

我尝试使用 mock service worker 来模拟 api 调用:

const server = setupServer(
    rest.get(`${environment.url.case}/api/case/:caseId`, (req, res, ctx) => {
        return res(ctx.set("Content-Type", "application/json"), ctx.body(JSON.stringify(caseMockApiData)));
    })
);

before(() => {
    server.listen();
});
afterEach(() => server.resetHandlers());
after(() => server.close());

但是,然后我得到一个错误:

TypeError: 只支持绝对 URL 在 Function.getSecurityTokenForApp

getSecurityTokenForApp
是从 useApi 调用的函数:

const createDefaultHeaders = async (app: string, cluster: string) => {
    const idToken = await SecuritySessionUtils.getSecurityTokenForApp(app, cluster);

它看起来像这样:

static async getSecurityTokenForApp(app: string, cluster?: string) {
    const tokenReq = await fetch("/token", {
        method: "POST",
        body: JSON.stringify({ app, cluster }),
        headers: { "Content-type": "application/json; charset=UTF-8" },
    });
    return await tokenReq.text();
}
javascript reactjs mocha.js sinon
1个回答
-2
投票

你应该这样使用钩子:

const { caseId } = useCase();
const { isLoading, isError, data, ...otherStuffFromReactQuery } = useApiData(caseId);

这里是钩子:

export const useApiData = (caseId: number) => {
    return useQuery({
            queryKey: `case-${caseId}`,
            queryFn: (): Promise<AxiosResponse<CaseDto>> => CASE_API.api.getCase(caseId),
            staleTime: Infinity,
            suspense: true,
    })
}
© www.soinside.com 2019 - 2024. All rights reserved.