reactjs - 如何在 React 功能组件中模拟 ipcRenderer.on 功能

标签 reactjs mocking electron jestjs react-testing-library

我正在编写一个 Electron 应用程序,前端使用 React,运行测试使用 JEST + React 测试库。我在模块中有以下简化代码:

import React from 'react';
import { ipcRenderer } from 'electron';
import Paper from '@material-ui/core/Paper';
import LinearProgress from '@material-ui/core/LinearProgress';


const AccountCheckModule = () => {

  const [listingsCount, setListingsCount] = React.useState(0);

  React.useEffect(() => {
    ipcRenderer.on('count-listings', (event, count) => {
      setListingsCount(count);
    });

    ipcRenderer.send('count-listings');

    // Cleanup the listener events so that memory leaks are avoided.
    return function cleanup() {
      ipcRenderer.removeAllListeners('count-listings');
    };
  }, []);

  return (
    <Paper elevation={2} data-testid="paper">
        <p
          className={classes.listingsNumberTracker}
          data-testid="free-listings-counter"
        >
          Free listings: {listingsCount}/100
        </p>
        <BorderLinearProgress
          className={classes.margin}
          variant="determinate"
          color="secondary"
          value={listingsCount}
          data-testid="border-linear-progress"
        />
    </Paper>
  );
};

export default AccountCheckModule;

基本上,React.useEffect() 运行一次,调用 ipcRenderer.send('count-listings'); 并设置一个监听器等待来自主要过程。主进程以列表计数作为响应,并在收到时用于更新 listingsCount 状态 -> setListingsCount(count)

是否可以使用 Jest 模拟此监听器函数以返回“计数”数字。

ipcRenderer.on('count-listings', (event, count) => {
    setListingsCount(count);
});

如果是,您将如何实现这一目标?

最佳答案

这是一个单元测试解决方案,我创建了一个简单的 electron 模块来模拟真实的 electron 节点模块并简化您的组件 JSX 元素。

例如

index.tsx:

import React from 'react';
import { ipcRenderer } from './electron';

const AccountCheckModule = () => {
  const [listingsCount, setListingsCount] = React.useState(0);

  React.useEffect(() => {
    ipcRenderer.on('count-listings', (event, count) => {
      setListingsCount(count);
    });

    ipcRenderer.send('count-listings', 2);

    // Cleanup the listener events so that memory leaks are avoided.
    return function cleanup() {
      ipcRenderer.removeAllListeners('count-listings');
    };
  }, []);

  return <div>{listingsCount}</div>;
};

export default AccountCheckModule;

electron.ts:

export const ipcRenderer = {
  events: {},
  on(event, handler) {
    this.events[event] = handler;
  },
  send(event, data) {
    this.events[event](event, data);
  },
  removeAllListeners(event) {
    this.events[event] = undefined;
  }
};

index.spec.tsx:

import React from 'react';
import { render, act } from '@testing-library/react';
import { ipcRenderer } from './electron';
import AccountCheckModule from './';

describe('AccountCheckModule', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should render correct', async () => {
    const events = {};
    const onSpy = jest.spyOn(ipcRenderer, 'on').mockImplementation((event, handler) => {
      events[event] = handler;
    });
    const sendSpy = jest.spyOn(ipcRenderer, 'send').mockImplementation((event, data) => {
      events[event](event, data);
    });
    const { getByText, container } = render(<AccountCheckModule></AccountCheckModule>);
    const mCount = 666;
    act(() => {
      ipcRenderer.send('count-listings', mCount);
    });
    const element = getByText(mCount.toString());
    expect(element).toBeDefined();
    expect(onSpy).toBeCalledWith('count-listings', expect.any(Function));
    expect(sendSpy).toBeCalledWith('count-listings', mCount);
    expect(container).toMatchSnapshot();
  });
});

SFC 100% 覆盖率报告的单元测试结果:

PASS  src/stackoverflow/58048849/index.spec.tsx
  AccountCheckModule
    ✓ should render correct (47ms)

-------------|----------|----------|----------|----------|-------------------|
File         |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-------------|----------|----------|----------|----------|-------------------|
All files    |    88.89 |      100 |    71.43 |     87.5 |                   |
 electron.ts |       50 |      100 |    33.33 |       50 |               4,7 |
 index.tsx   |      100 |      100 |      100 |      100 |                   |
-------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        4.247s, estimated 11s

index.spec.tsx.snap:

// Jest Snapshot v1

exports[`AccountCheckModule should render correct 1`] = `
<div>
  <div>
    666
  </div>
</div>
`;

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58048849

关于reactjs - 如何在 React 功能组件中模拟 ipcRenderer.on 功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58048849/

相关文章:

python - pytest-mock assert_called_with 类函数失败

javascript - decoratorsBeforeExport使用electron-webpack开发人员时出错

electron - 有没有办法设置 electron-builder 自动更新程序来检查来自 Google Cloud Storage 的更新?

json - Node.js和AWS凭证错误

reactjs - 样式组件不带 Prop

javascript - 链中提取和 Promise.all 的多个 API 调用

javascript - 破坏参数会导致语法错误

javascript - 在 React/Redux 应用程序中将 SignalR hub 放在哪里?

unit-testing - PHPUnit - Setter 不修改我的模拟

java - 使用 JOOQ 的 MockDataProvider,如何设置返回的 lastId()?