【问题标题】:Testing a callback function in Jest在 Jest 中测试回调函数
【发布时间】:2021-07-15 20:19:35
【问题描述】:

不用说,这个应用程序比这个复杂得多,但要点是一样的。我无法对应用程序进行重大更改,例如导入/导出 onSuccess 函数或更改为基于类的组件。

单击按钮启动登录功能,我在其中传递了一个 onSuccess 功能。我想监视分析函数以确保它被调用,但在我的测试中我无法调用 onSuccess 函数

理想情况下,我想做这样的事情:

test("analyze should be called", () => {
  let analyzeSpy = jest.spyOn(Analytics, "analyze");
  onSuccess() //<- cannot do this
  expect(analyzeSpy).toHaveBeenCalledTimes(1);
});

这是应用程序:

import Analytics from "./Analytics";

export function Login({ onLoginSuccess }) {
  setTimeout(function () {
    console.log("TIMEOUT OVER");
    onLoginSuccess();
  }, 2000);
}

function App() {
  function handleClick() {
    console.log("Login");
    Login({
      onLoginSuccess: onSuccess,
    });
  }
  function onSuccess() {
    console.log("Login success");
    Analytics.analyze();
  }
  return (
    <>
      <button
        onClick={() => {
          handleClick();
        }}
      >
        Login
      </button>
    </>
  );
}

export default App;

这是 Analytics.js:

export default {
  analyze: () => {
    console.log("Analysis done");
  },
};

我该如何测试?

【问题讨论】:

  • 您要进行什么单元测试?你已经包含了几个文件、几个组件和几个函数?如果您想测试是否调用了 analyze,那么您需要渲染 App 并模拟单击按钮以启动回调链。需要明确的是,这不是单元测试,而是集成测试。
  • Login() 函数有一些依赖项,需要用户干预。也许我应该模拟登录功能。
  • 如果你不是,那么你应该使用react-testing-library,然后你渲染App组件,click按钮然后你会调用你的onSuccess来查看间谍是否被调用。

标签: javascript reactjs unit-testing testing jestjs


【解决方案1】:

使用react-dom模块的render()方法将你的组件渲染成js-dom提供的文档。

使用document.querySelector('button')获取按钮dom,派发鼠标点击事件。

使用jest.useFakeTimers() 来使用标准定时器函数的假版本(setTimeout)。

派发点击事件后,使用jest.advanceTimersByTime(2000)执行宏任务队列(由setTimeout排队的任务)。

然后,做一个断言。

例如

App.jsx:

import React from 'react';
import Analytics from './Analytics';

export function Login({ onLoginSuccess }) {
  setTimeout(function () {
    console.log('TIMEOUT OVER');
    onLoginSuccess();
  }, 2000);
}

function App() {
  function handleClick() {
    console.log('Login');
    Login({
      onLoginSuccess: onSuccess,
    });
  }
  function onSuccess() {
    console.log('Login success');
    Analytics.analyze();
  }
  return (
    <>
      <button
        onClick={() => {
          handleClick();
        }}
      >
        Login
      </button>
    </>
  );
}

export default App;

App.test.jsx:

import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { act } from 'react-dom/test-utils';
import App from './App';
import Analytics from './Analytics';

describe('68400320', () => {
  let container = null;
  beforeEach(() => {
    // setup a DOM element as a render target
    container = document.createElement('div');
    document.body.appendChild(container);
  });

  afterEach(() => {
    // cleanup on exiting
    unmountComponentAtNode(container);
    container.remove();
    container = null;
  });

  test('should pass', () => {
    const analyzeSpy = jest.spyOn(Analytics, 'analyze');
    jest.useFakeTimers();
    act(() => {
      render(<App />, container);
    });
    const button = document.querySelector('button');
    act(() => {
      button?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
      jest.advanceTimersByTime(2000);
    });
    expect(analyzeSpy).toBeCalledTimes(1);
  });
});

测试结果:

PASS  examples/68400320/App.test.jsx (8.12 s)
  68400320
    ✓ should pass (52 ms)

  console.log
    Login

      at handleClick (examples/68400320/App.jsx:13:13)

  console.log
    TIMEOUT OVER

      at examples/68400320/App.jsx:6:13

  console.log
    Login success

      at onSuccess (examples/68400320/App.jsx:19:13)

  console.log
    Analysis done

      at Object.analyze (examples/68400320/Analytics.js:3:13)

--------------|---------|----------|---------|---------|-------------------
File          | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
--------------|---------|----------|---------|---------|-------------------
All files     |     100 |      100 |     100 |     100 |                   
 Analytics.js |     100 |      100 |     100 |     100 |                   
 App.jsx      |     100 |      100 |     100 |     100 |                   
--------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        8.666 s, estimated 10 s
Ran all test suites related to changed files.

【讨论】:

    猜你喜欢
    • 2021-08-08
    • 2019-09-21
    • 2022-01-24
    • 2020-03-23
    • 2018-03-25
    • 1970-01-01
    • 2022-01-01
    • 2021-06-16
    • 2017-07-09
    相关资源
    最近更新 更多