英文:
Testing functions containing Promise and FileReader() in Jest
问题
目前正在尝试测试以下函数:
const readFileAsync = (file, use = false) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
if (use) reader.readAsDataURL(file);
else reader.readAsArrayBuffer(file);
});
export default readFileAsync;
但在模拟FileReader方面遇到了大问题。有什么建议吗?
英文:
Currently trying to test the following function:
const readFileAsync = (file, use = false) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
if (use) reader.readAsDataURL(file);
else reader.readAsArrayBuffer(file);
});
export default readFileAsync;
But having massive issues with the FileReader aspect in regards to mocking. Any advice?
答案1
得分: 1
Here is the translated code portion you requested:
虽然我们模拟了 FileReader 的 onload 方法,但在执行 readFileAsync 方法后,reader.onload 被分配给了一个匿名函数(未模拟)。因此,我们需要暴露 reader 实例,获取测试用例中的 reader 实例并手动执行 reader.onload 方法。然后,承诺将使用模拟值 reader.result 解析。
例如:
index.ts:
const readFileAsync = (file, use = false) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
if (use) reader.readAsDataURL(file);
else reader.readAsArrayBuffer(file);
(readFileAsync as any)._reader = reader;
});
export default readFileAsync;
根据 (readFileAsync as any)._reader 暴露 reader 实例。
index.test.ts:
import readFileAsync from './';
const mFileReader = jest.fn(() => {
return {
readAsDataURL: jest.fn(),
readAsArrayBuffer: jest.fn(),
};
});
(global as any).FileReader = mFileReader;
describe('59581721', () => {
afterEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
});
it('should read as data url correctly', async () => {
const blob = new Blob(['a']);
const pending = readFileAsync(blob, true);
const mReader = (readFileAsync as any)._reader;
mReader.result = 'mocked result';
mReader.onload();
const actual = await pending;
expect(actual).toBe('mocked result');
expect(mReader.readAsDataURL).toBeCalledWith(blob);
});
it('should read as array buffer corectly', async () => {
const blob = new Blob(['a']);
const pending = readFileAsync(blob);
const mReader = (readFileAsync as any)._reader;
mReader.result = 'mocked result';
mReader.onload();
const actual = await pending;
expect(actual).toBe('mocked result');
expect(mReader.readAsArrayBuffer).toBeCalledWith(blob);
});
});
带覆盖率报告的单元测试结果:
PASS src/stackoverflow/59581721/index.test.ts (13.673s)
59581721
✓ should read as data url correctly (21ms)
✓ should read as array buffer corectly (2ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 15.648s
我的测试环境是 node。
源代码链接:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59581721
英文:
Although we mock FileReader onload method, after executing readFileAsync method, reader.onload is to assign to an anonymous function (not mocked). So we need to expose the reader instance, get the reader instance in the test case and execute reader.onload method manually. Then, the promise will be resolved with the mocked value of reader.result.
E.g.
index.ts:
const readFileAsync = (file, use = false) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
if (use) reader.readAsDataURL(file);
else reader.readAsArrayBuffer(file);
(readFileAsync as any)._reader = reader;
});
export default readFileAsync;
Expose the reader instance according to (readFileAsync as any)._reader.
index.test.ts:
import readFileAsync from './';
const mFileReader = jest.fn(() => {
return {
readAsDataURL: jest.fn(),
readAsArrayBuffer: jest.fn(),
};
});
(global as any).FileReader = mFileReader;
describe('59581721', () => {
afterEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
jest.restoreAllMocks();
});
it('should read as data url correctly', async () => {
const blob = new Blob(['a']);
const pending = readFileAsync(blob, true);
const mReader = (readFileAsync as any)._reader;
mReader.result = 'mocked result';
mReader.onload();
const actual = await pending;
expect(actual).toBe('mocked result');
expect(mReader.readAsDataURL).toBeCalledWith(blob);
});
it('should read as array buffer corectly', async () => {
const blob = new Blob(['a']);
const pending = readFileAsync(blob);
const mReader = (readFileAsync as any)._reader;
mReader.result = 'mocked result';
mReader.onload();
const actual = await pending;
expect(actual).toBe('mocked result');
expect(mReader.readAsArrayBuffer).toBeCalledWith(blob);
});
});
Unit test result with coverage report:
PASS src/stackoverflow/59581721/index.test.ts (13.673s)
59581721
✓ should read as data url correctly (21ms)
✓ should read as array buffer corectly (2ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 15.648s
My testing environment is node.
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59581721
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论