英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论