我正在编写一个Electron应用程序,将React用于前端,将JEST + React Testing库用于运行测试。我在模块中有以下简化代码:
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);
});
如果是,您将如何实现这一目标?
答案 0 :(得分:0)
这是一个单元测试解决方案,我创建了一个简单的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();
});
});
具有100%SFC覆盖率报告的单元测试结果:
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