#reactjs #antd #react-testing-library
#reactjs #antd #react-testing-library
Вопрос:
Я использую компонент загрузки Ant Design.
<Upload
accept=".xlsx"
onChange={onImport}
>
<Button>Upload</Button>
</Upload>
Я попытался имитировать изменение с помощью fireEvent.change, который ничего не делает:
const inputEl = screen.getByText('Import');
const file = new File(['(⌐□_□)'], 'chucknorris.xlsx');
fireEvent.change(inputEl, { target: { files: [file] } });
Я также пытался использовать fireEvent.drop. Я попытался настроить как свойства передачи данных, так и файлы.
Object.defineProperty(inputEl, 'dataTransfer', {
value: {
files: [file]
}
});
Object.defineProperty(inputEl, 'files', {
value: [file]
});
fireEvent.drop(inputEl);
Это запускает загрузку, но я продолжаю получать следующую ошибку:
Cannot read property 'files' of undefined
at AjaxUploader._this.onFileDrop (node_modules/rc-upload/lib/AjaxUploader.js:108:63)
Как я могу протестировать загрузку Ant Design?
Ответ №1:
Вот как я с этим справился. Поскольку input
он скрыт, и вы не можете запросить его с помощью RTL, я просто запросил ввод, используя document
вот так:
async simulateFileUpload() {
const file = new File(['(⌐□_□)'], 'chucknorris.png', { type: 'image/png' });
const hiddenFileInput = document.querySelector('input[type="file"]') as Element;
await act(async () => {
fireEvent.change(hiddenFileInput, { target: { files: [file] } });
});
}
Не самое приятное, что можно сделать, но это единственный способ проверить функциональность загрузки.
Я завернул fireEvent
, await act()
но это только потому, что загрузка вызывает некоторые изменения состояния в моем приложении, вы можете просто использовать выбросить его, конечно
Ответ №2:
Вы можете использовать user-event; это вспомогательная библиотека для тестирования библиотеки, которая обеспечивает более продвинутую симуляцию взаимодействия с браузером, чем встроенный метод fireEvent.
Установка:
npm install --save-dev @testing-library/user-event
Использование:
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
test('upload file', () => {
const file = new File(['hello'], 'hello.png', { type: 'image/png' })
render(
<div>
<label htmlFor="file-uploader">Upload file:</label>
<input id="file-uploader" type="file" />
</div>
)
const input = screen.getByLabelText(/upload file/i)
userEvent.upload(input, file)
expect(input.files[0]).toStrictEqual(file)
expect(input.files.item(0)).toStrictEqual(file)
expect(input.files).toHaveLength(1)
})
Ответ №3:
Комбинация двух ответов плюс обработка запросов — это то, что сработало для меня. В этом примере вы не указываете URL-адрес для выполнения запроса POST, но компонент перетаскивания Ant Design имеет эту опцию. Я просто хочу поделиться своим решением этого вопроса дополнительная проблема, которую я обнаружил при использовании action
свойства, просто чтобы сэкономить ваше время.
Чтобы протестировать перетаскиватель, я сделал это:
test("Dragger functionality", async () => {
const flushPromises = () => new Promise(setImmediate);
const file = new File(["{test: 1}"], "test.json", {type: 'application/json'})
const input = screen.getByTestId("uploader");
// I added the data-testid property to the Dragger element, with the value "uploader"
await act(async () => {
fireEvent.change(input, {target: {files: [file]}});
});
await flushPromises();
});
Этот userEvent.upload
метод никогда не работал для меня. Я использовал userEvent
для всех других тестов, но в этом случае я не смог заставить его работать.
Дополнительно: если вы используете перетаскиватель, как я
<Dragger multiple={true} accept={".json"} onChange={onChange} action={"/test"} data-testid={"uploader"}>
со свойствами onChange
and action
вы, вероятно, не получите onChange
вызов.
Чтобы это сработало, вы должны обработать выполняемый POST-запрос, в данном случае к /test
. Итак, полный тест будет:
import { act, fireEvent, render, screen } from "@testing-library/react";
import { setupServer } from "msw/node";
import { rest } from "msw";
import React from "react";
import { Upload } from "antd";
const { Dragger } = Upload;
const onChangeMock = jest.fn();
const server = setupServer(rest.post("/test", (req, res, ctx) => {
return res(ctx.json({response: "200 OK"}));
}));
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
test("Dragger functionality", async () => {
const flushPromises = () => new Promise(setImmediate);
render (
<Dragger multiple={true} accept={".json"} onChange={onChangeMock} action={"/test"} data-testid={"uploader"}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">{"description"}</p>
<p className="ant-upload-hint">{"hint"}</p>
</Dragger>
);
const file = new File(["{test: 1}"], "test.json", {type: 'application/json'})
const input = screen.getByTestId("uploader");
// I added the data-testid property to the Dragger element, with the value "uploader"
await act(async () => {
fireEvent.change(input, {target: {files: [file]}});
});
await flushPromises();
expect(onChangeMock).toBeCalled();
});
Надеюсь, это кому-то пригодится.