如何正确测试 React Dropzone onDrop 方法
How to test properly React Dropzone onDrop method
我正在测试 React Dropzone,我需要检查 onDrop 函数。该函数有两个参数(acceptedFiles 和 rejectedFiles)。我正在这样模拟文件:
let image = {
name: 'cat.jpg',
size: 1000,
type: 'image/jpeg'
};
然后在我的测试中,我这样做:
it('should call handleOnDrop with more than 5 acceptedFiles', () => {
const wrapper = mount(mockComponent());
for (let index = 0; index < 5; index++) {
images.push(image);
}
wrapper.find(Dropzone).simulate('drop', { dataTransfer: { files: images } });
expect(setUserNotificationsSpy).toHaveBeenCalledTimes(1);
});
这是我的 onDrop 函数:
const handleOnDrop = (acceptedFiles, rejectedFiles) => {
if (rejectedFiles && rejectedFiles.length) {
checkMaxFile(rejectedFiles, maxSize) && setUserNotifications('error_big_image');
}
acceptedFiles && acceptedFiles.length <= maxFiles ? onDrop(acceptedFiles) : setUserNotifications('more_than_5');
};
预期的结果是 handleOnDrop returns acceptedFiles 但 returns rejectedFiles 我不知道为什么。
Mime 类型还可以,大小也可以。
这是 react-dropzone 的功能:
fileAccepted(file) {
// Firefox versions prior to 53 return a bogus MIME type for every file drag, so dragovers with
// that MIME type will always be accepted
return file.type === 'application/x-moz-file' || accepts(file, this.props.accept);
}
谢谢。
路过时
let image = {
name: 'cat.jpg',
size: 1000,
type: 'image/jpeg'
};
进入
wrapper.find(Dropzone).simulate('drop', { dataTransfer: { files: images } });
它会认为图像未定义或为空。
我能够解决这个问题的方法是
//Create a non-null file
const fileContents = "file contents";
const file = new Blob([fileContents], { type: "text/plain" });
wrapper.find(Dropzone).simulate("drop", { dataTransfer: { files: [file] } });
这当然是您对纯文本文件的处理方式。对于不同类型的图像,您需要指定图像类型而不是 "text/plain"
我在使用 useDropzone
钩子时 运行 遇到了这个问题。使用
wrapper.find(...).simulate('drop', ...);
不适合我。
相反,我在 input
字段上模拟了 change
。这适合我对组件进行单元测试的用例。我不关心测试组件的特定放置功能,因为这超出了对我的组件进行单元测试的范围。假设 react-dropzone
正常运行,我只需要测试我的组件是否正确处理了文件放置事件,我仍然可以通过与 input
字段交互来测试它。而且它具有更通用的良好副作用,以防我将来换掉 dropzone 库。
wrapper.find('input').simulate('change', {
target: { files },
preventDefault: () => {},
persist: () => {},
});
我这样定义 files
:
const createFile = (name, size, type) => ({
name,
path: name,
size,
type,
});
const files = [
createFile('foo.png', 200, 'image/png'),
createFile('bar.jpg', 200, 'image/jpeg'),
];
同样,它适合我的用例,只创建像这样的模拟文件对象,而不是使用原生 File
。如果需要,您可以添加更多属性(例如 lastModifiedDate
),但我没有。
如果出于某种原因,您觉得需要创建适当的 File
实例,您也可以这样做:
const createFile = (name, size, type) => {
// the first arg, [], is the file content
// it's irrelevant, so I left it blank
// you can fill it like ['foobar'] or [name] if you want to
const file = new File([], name, { type });
Reflect.defineProperty(file, 'size', {
get() {
return size;
}
});
return file;
};
由于未设置 path
属性,我在测试过程中遇到了一些问题。检查原生 File
对象的相等性也很麻烦。序列化的文件对象最终会变成 {}
,这显然没有用。我相信您可以让它工作,但是 IMO,如果可以的话,请避免使用本机 File
对象。在我的测试中使用它们没有任何好处。
如果有人在创建存根文件后遇到任何进一步的问题,我发现还在 dataTransfer 选项中提供了一个类型字段来绕过 react-dropzone 使用的一些检查。我正在使用 RTL,所以 ymmv.
const fakeVideo = new File(['muhaahahah'], 'hello.mp4', { type: 'video/mp4' });
fireEvent.drop(getByTestId('test-input'), {
dataTransfer: { files: [fakeVideo], types: ['Files'] }
});
我正在使用反应测试库,这对我来说很有效,
我已将测试 ID 附加到从 useDropZone 挂钩中获取 getRootProps 的 div,它不一定必须是 div 它可以是任何容器元素
function dispatchEvt(node: any, type: any, data: any) {
const event = new Event(type, { bubbles: true });
Object.assign(event, data);
fireEvent(node, event);
}
async function flushPromises(rerender: any, ui: any) {
await act(() => wait(() => rerender(ui)));
}
const onDropMock = jest.fn();
it("The on Drop is called on dragging a file ", async () => {
const file = new File([JSON.stringify({ ping: true })], "fileName.csv", { type: "text/csv" });
const data = mockData([file]);
const ui = <MyComponent onDrop={onDropMock} />;
const { container, rerender } = render(ui);
const input = screen.getByTestId("testId-for-div");
dispatchEvt(input, "drop", data);
await flushPromises(rerender, ui);
expect(onDropMock).toHaveBeenCalled();
});
我在官方文档中找到了所有这些信息here
我正在测试 React Dropzone,我需要检查 onDrop 函数。该函数有两个参数(acceptedFiles 和 rejectedFiles)。我正在这样模拟文件:
let image = {
name: 'cat.jpg',
size: 1000,
type: 'image/jpeg'
};
然后在我的测试中,我这样做:
it('should call handleOnDrop with more than 5 acceptedFiles', () => {
const wrapper = mount(mockComponent());
for (let index = 0; index < 5; index++) {
images.push(image);
}
wrapper.find(Dropzone).simulate('drop', { dataTransfer: { files: images } });
expect(setUserNotificationsSpy).toHaveBeenCalledTimes(1);
});
这是我的 onDrop 函数:
const handleOnDrop = (acceptedFiles, rejectedFiles) => {
if (rejectedFiles && rejectedFiles.length) {
checkMaxFile(rejectedFiles, maxSize) && setUserNotifications('error_big_image');
}
acceptedFiles && acceptedFiles.length <= maxFiles ? onDrop(acceptedFiles) : setUserNotifications('more_than_5');
};
预期的结果是 handleOnDrop returns acceptedFiles 但 returns rejectedFiles 我不知道为什么。
Mime 类型还可以,大小也可以。
这是 react-dropzone 的功能:
fileAccepted(file) {
// Firefox versions prior to 53 return a bogus MIME type for every file drag, so dragovers with
// that MIME type will always be accepted
return file.type === 'application/x-moz-file' || accepts(file, this.props.accept);
}
谢谢。
路过时
let image = {
name: 'cat.jpg',
size: 1000,
type: 'image/jpeg'
};
进入
wrapper.find(Dropzone).simulate('drop', { dataTransfer: { files: images } });
它会认为图像未定义或为空。 我能够解决这个问题的方法是
//Create a non-null file
const fileContents = "file contents";
const file = new Blob([fileContents], { type: "text/plain" });
wrapper.find(Dropzone).simulate("drop", { dataTransfer: { files: [file] } });
这当然是您对纯文本文件的处理方式。对于不同类型的图像,您需要指定图像类型而不是 "text/plain"
我在使用 useDropzone
钩子时 运行 遇到了这个问题。使用
wrapper.find(...).simulate('drop', ...);
不适合我。
相反,我在 input
字段上模拟了 change
。这适合我对组件进行单元测试的用例。我不关心测试组件的特定放置功能,因为这超出了对我的组件进行单元测试的范围。假设 react-dropzone
正常运行,我只需要测试我的组件是否正确处理了文件放置事件,我仍然可以通过与 input
字段交互来测试它。而且它具有更通用的良好副作用,以防我将来换掉 dropzone 库。
wrapper.find('input').simulate('change', {
target: { files },
preventDefault: () => {},
persist: () => {},
});
我这样定义 files
:
const createFile = (name, size, type) => ({
name,
path: name,
size,
type,
});
const files = [
createFile('foo.png', 200, 'image/png'),
createFile('bar.jpg', 200, 'image/jpeg'),
];
同样,它适合我的用例,只创建像这样的模拟文件对象,而不是使用原生 File
。如果需要,您可以添加更多属性(例如 lastModifiedDate
),但我没有。
如果出于某种原因,您觉得需要创建适当的 File
实例,您也可以这样做:
const createFile = (name, size, type) => {
// the first arg, [], is the file content
// it's irrelevant, so I left it blank
// you can fill it like ['foobar'] or [name] if you want to
const file = new File([], name, { type });
Reflect.defineProperty(file, 'size', {
get() {
return size;
}
});
return file;
};
由于未设置 path
属性,我在测试过程中遇到了一些问题。检查原生 File
对象的相等性也很麻烦。序列化的文件对象最终会变成 {}
,这显然没有用。我相信您可以让它工作,但是 IMO,如果可以的话,请避免使用本机 File
对象。在我的测试中使用它们没有任何好处。
如果有人在创建存根文件后遇到任何进一步的问题,我发现还在 dataTransfer 选项中提供了一个类型字段来绕过 react-dropzone 使用的一些检查。我正在使用 RTL,所以 ymmv.
const fakeVideo = new File(['muhaahahah'], 'hello.mp4', { type: 'video/mp4' });
fireEvent.drop(getByTestId('test-input'), {
dataTransfer: { files: [fakeVideo], types: ['Files'] }
});
我正在使用反应测试库,这对我来说很有效, 我已将测试 ID 附加到从 useDropZone 挂钩中获取 getRootProps 的 div,它不一定必须是 div 它可以是任何容器元素
function dispatchEvt(node: any, type: any, data: any) {
const event = new Event(type, { bubbles: true });
Object.assign(event, data);
fireEvent(node, event);
}
async function flushPromises(rerender: any, ui: any) {
await act(() => wait(() => rerender(ui)));
}
const onDropMock = jest.fn();
it("The on Drop is called on dragging a file ", async () => {
const file = new File([JSON.stringify({ ping: true })], "fileName.csv", { type: "text/csv" });
const data = mockData([file]);
const ui = <MyComponent onDrop={onDropMock} />;
const { container, rerender } = render(ui);
const input = screen.getByTestId("testId-for-div");
dispatchEvt(input, "drop", data);
await flushPromises(rerender, ui);
expect(onDropMock).toHaveBeenCalled();
});
我在官方文档中找到了所有这些信息here