我有这个组件,我试图测试,但无论我try 什么,我得到的错误:

import {useEffect, useState} from 'react';
import {useUser} from '.';

/**
 * Check If the company is locked
 */
export const useIsCompanyLocked = (): boolean => {
  const userInfo = useUser();
  const [status, setStatus] = useState(false);

  useEffect(() => {
    if (!userInfo) {
      return;
    }

    (async (): Promise<void> => {
      setStatus(false);
      // Do some stuff
      setStatus('do some condition which returns a boolean result');
    })();
  }, [userInfo, status]);

  return status;
};

下面是我的jest测试,但失败了:

/**
 * @jest-environment jsdom
 */
import {useIsCompanyLocked} from '../useIsCompanyLocked';
import {mockUseUser} from '@myTest/test-utilities';
import React from 'react';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const appUtils = require('@myTest/app-utilities');

describe('useUserHasSecurityPermissionForCompany', () => {
  const setStatus = jest.fn();
  let useStateSpy: any;

  beforeEach(() => {
    useStateSpy = jest.spyOn(React, 'useState');
    useStateSpy.mockImplementation((initialState: any) => [initialState, setStatus]);
  });

  it('should return "false" if user is Admin', () => {
    let mockUser = mockUseUser();
    mockUser = {
      ...mockUser,
      isAdmin: true
      ]
    };
    jest.spyOn(appUtils, 'useUser').mockReturnValue(mockUser);
    const obj = useIsCompanyLocked();
    expect(obj).toEqual(false);
  });
});

我已经try 了这个测试的许多不同的迭代,但我总是以一些错误结束.测试这个函数'useIsCompanyLocked'的正确方法是什么?

这是我得到的错误:

Summary of all failing tests
FAIL src/hooks/__tests__/useIsCompanyLocked.test.tsx (10.631s)
  ● useIsCompanyLocked › should return "false" if user is Admin

    expect(received).toEqual(expected) // deep equality

    Expected: false
    Received: [false, [Function mockConstructor]]

      39 |     jest.spyOn(appUtils, 'useUser').mockReturnValue(mockUser);
      40 |     const obj = useIsCompanyLocked();
    > 41 |     expect(obj).toEqual(false);
         |                 ^
      42 |   });
      43 |

      at Object.<anonymous> (src/hooks/__tests__/useIsCompanyLocked.test.tsx:41:17)

推荐答案

Issue

这里的问题是你的单元测试代码直接调用了一个React钩子,而不是在React组件或自定义React钩子中调用.

Solution

单元测试React钩子的常见方法是使用React-Hooks-Testing-LibraryrenderHook实用程序.很可能你已经在使用React-Testing-Library(if you are not you really ought to consider using it as it's the standard testing library for React UI),其中包含了React hooks测试库.

详情请看renderHook

基本示例用法:

/**
 * @jest-environment jsdom
 */
import React from 'react';
import { renderHook } from '@testing-library/react';
import { mockUseUser } from '@myTest/test-utilities';
import { useIsCompanyLocked } from '../useIsCompanyLocked';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const appUtils = require('@myTest/app-utilities');

describe('useUserHasSecurityPermissionForCompany', () => {
  it('should return "false" if user is Admin', async () => {
    // Prime useUser hook to return user with "isAdmin: true"
    const mockUser = mockUseUser();
    mockUser.isAdmin = true;
    jest.spyOn(appUtils, 'useUser').mockReturnValue(mockUser);

    const { result } renderHook(() => useIsCompanyLocked());

    expect(result.current).toEqual(false);
  });
});

测试useIsCompanyLocked钩子的另一个问题是useEffect钩子中的异步逻辑,它更新了你实际想要断言的status状态.为此,你需要模拟that逻辑,并使用act实用程序来"解析"它并触发一个"重新渲染".因此测试可以访问status状态105,效果的异步逻辑已经用模拟用户对象的结果更新了状态.

/**
 * @jest-environment jsdom
 */
import React from 'react';
import { act, renderHook } from '@testing-library/react';
import { mockUseUser } from '@myTest/test-utilities';
import { useIsCompanyLocked } from '../useIsCompanyLocked';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const appUtils = require('@myTest/app-utilities');

describe('useUserHasSecurityPermissionForCompany', () => {
  it('should return "false" if user is Admin', async () => {
    // Setup/mock the asynchronous logic
    const resolvedPromise = Promise.resolve(/* whatever the logic needs in the hook */);
    // any additional mocks, e.g. `fetch` or `axios`, etc

    // Prime useUser hook to return user with "isAdmin: true"
    const mockUser = mockUseUser();
    mockUser.isAdmin = true;
    jest.spyOn(appUtils, 'useUser').mockReturnValue(mockUser);

    const { result } renderHook(() => useIsCompanyLocked());

    // wait for the asynchronous logic to complete
    await act(() => resolvedPromise);

    expect(result.current).toEqual(false);
  });
});

Typescript相关问答推荐

Typescript:将内部函数参数推断为子对象键的类型

界面中这种类型的界面界面中的多态性

TypScript手册中的never[]参数类型是什么意思?

泛型函数类型验证

部分类型化非 struct 化对象参数

TypeScrip省略了类型参数,仅当传递另一个前面的类型参数时才采用默认类型

错误TS2403:后续变量声明必须具有相同的类型.变量';CRYPTO';的类型必须是';CRYPATO';,但这里的类型是';CRYPATO';

使用KeyOf和Never的循环引用

将带点的对象键重新映射为具有保留值类型的嵌套对象

声明文件中的类型继承

TypeScrip:强制使用动态密钥

为什么我的导航在使用Typescript的React Native中不起作用?

回调函数中的TypeScrip类型保护返回Incorect类型保护(具有其他未定义类型的返回保护类型)

如何使用泛型函数参数定义类型脚本函数

Typescript,如何在通过属性存在过滤后重新分配类型?

当传递带有或不带有参数的函数作为组件props 时,我应该如何指定类型?

Svelte+EsBuild+Deno-未捕获类型错误:无法读取未定义的属性(读取';$$';)

Typescript 确保通用对象不包含属性

在 TypeScript 中实现类型级别深度优先搜索

Typescript,如何从对象的对象中获取分离的类型