简体   繁体   English

在 Jest 中测试回调函数

[英]Testing a callback function in Jest

Needless to say, the app is a lot more complicated that this, but the gist is the same.不用说,该应用程序比这复杂得多,但要点是相同的。 I cannot make major changes to the App, such as import/export the onSuccess function or changing to a class based component.我无法对应用程序进行重大更改,例如导入/导出 onSuccess 函数或更改为基于类的组件。

A button click kicks off the Login function, where I pass in an onSuccess function.单击按钮会启动 Login 函数,我在其中传入 onSuccess 函数。 I want to spy on the analyze function to make sure it is called, but in my test I have no way of calling the onSuccess function我想监视分析函数以确保它被调用,但在我的测试中我无法调用 onSuccess 函数

Ideally I would like to do something like this:理想情况下,我想做这样的事情:

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

Here is the app:这是应用程序:

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;

This is Analytics.js:这是 Analytics.js:

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

How can I test this?我该如何测试?

Use render() method of react-dom module to render your component into document provided by js-dom .使用react-dom模块的render()方法将您的组件渲染到js-dom提供的文档中。

Use document.querySelector('button') to get the button dom, dispatch a mouse click event.使用document.querySelector('button')获取按钮 dom,调度鼠标点击事件。

Use jest.useFakeTimers() to use fake versions of the standard timer functions( setTimeout ).使用jest.useFakeTimers()来使用标准定时器函数( setTimeout )的假版本。

After dispatching the click event, use jest.advanceTimersByTime(2000) to executes the macro task queue (tasks queued by setTimeout ).分派点击事件后,使用jest.advanceTimersByTime(2000)执行宏任务队列(由setTimeout排队的任务)。

Then, make an assertion.然后,做一个断言。

Eg例如

App.jsx : 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 : 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);
  });
});

test result:测试结果:

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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM