Я делаю комплект модульных тестов javascript для компонента «реакт-редукс» с шуткой и энзимом; рассматриваемый компонент представляет собой форму загрузки файла с несколькими полями, в которой есть некоторые базовые изменения стиля, основанные на вводе пользователя и / или ответе сервера. Jest и энзим настроены и работают, и я могу успешно написать базовые тесты.
Я хочу смоделировать взаимодействие пользователя с этими элементами пользовательского интерфейса (файл ввода и текстовые поля), используя jest & энзим, но у меня возникают трудности при этом; Я довольно новичок в использовании этих платформ тестирования и имею базовое представление о response-redux, и я немного ошеломлен тем, чтобы убедиться, что для написания осмысленных модульных тестов созданы правильные части.
В целом: этот модульный тест проводится после того, как я работал, несколько месяцев назад я присоединился к этому проекту, использующему методы разработки, основанные на тестировании, и раньше я так не разрабатывал, поэтому я использую его в качестве примера / шаблона для будущее развитие.
На данный момент модульные тесты успешно создают компонент (с энзимами mount
& shallow
с mockStore и начальным состоянием). Я пытался сделать две вещи:
- создать api __mocks__ только для модульного тестирования, которое использует другой модуль (редуктор действия, который использует вспомогательный метод, который делает вызов api) согласно шуткам здесь
- поиск / доступ к полям формы (ввод файла и текстовая область) для имитации взаимодействия с пользователем
Я не достиг полного успеха в обоих случаях, и у меня есть модульные тесты, которые охватывают их аспекты, но не полностью интегрированы.
вот метод визуализации для компонента, для которого я пытаюсь выполнить модульные тесты:
render() {
const { dataset } = this.props;
let serverResp;
dataset ? serverResp = dataset.fileUploadResp : null;
let catFeats = this.state.catFeatures;
let errorMsg = this.state.errorResp;
let ordFeatureSelection = "";
let catFeatureSelection = "";
let dataPrevTable = this.getDataTablePreview();
// default to hidden until a file is selected, then display input areas
let formInputClass = "file-upload-form-hide-inputs";
// server message to display in popup (or other UI element)
serverResp ? serverResp = ( <p style={{display: 'block'}}> {JSON.stringify(serverResp)} </p> ) :
null;
// check if file with filename has been selected, if so then use css to show form
this.state.selectedFile && this.state.selectedFile.name ?
formInputClass = "file-upload-form-show-inputs" : null;
return (
<div>
<Form inverted>
<Segment className="file-upload-segment">
<Input
className="file-upload-form-text-input"
type="file"
label="Select new dataset"
id="upload_dataset_file_browser_button"
onChange={this.handleSelectedFile}
/>
<br/>
<div
id="file-upload-form-input-area"
className={formInputClass}
>
<Form.Input
label="Dependent Column"
placeholder="class"
value={this.state.dependentCol ? this.state.dependentCol : ""}
type="text"
onChange={this.handleDepColField}
/>
<Form.Input
label="Ordinal Features"
>
<textarea
label="Ordinal Features"
placeholder={"{\"ord_feat_1\": [\"MALE\", \"FEMALE\"], \"ord_feat_2\": [\"FIRST\", \"SECOND\", \"THIRD\"]}"}
onChange={this.handleOrdinalFeatures}
/>
</Form.Input>
<Form.Input
label="Categorical Features"
>
<textarea
label="Categorical Features"
placeholder={"cat_feat_1, cat_feat_2"}
onChange={this.handleCatFeatures}
/>
</Form.Input>
<Popup
header="Error Submitting Dataset"
content={serverResp}
open={errorMsg ? true : false}
trigger={
<Button
inverted
color="blue"
compact
size="small"
icon="upload"
content="Upload dataset"
onClick={this.handleUpload}
/>
}
/>
</div>
</Segment>
</Form>
{dataPrevTable}
</div>
);
}
Это довольно простой компонент реагирования, подключенный к хранилищу приложений, с некоторыми семантическими элементами пользовательского интерфейса для приятного стиля. Есть форма с вводом файла, вводом текстовой области и кнопкой / всплывающим окном; если файл не выбран, отображается только ввод файла, если попытка отправить файл не удалась, во всплывающем окне отображается сообщение об ошибке.
Для пункта 1 - я попытался следовать руководству / документам из шутки и создать макет API, который компонент использует и использует jest.mock()
jest.mock('../../utils/apiHelper');
import uploadDataset from '../../data/datasets/dataset/api';
Но в самом модульном тесте при попытке
it('testing promise for successfully case, proper dependent_col', () => {
expect.assertions(1);
return uploadDataset(fakeDataset).then(data => expect(data.name).toEqual('iris.csv'));
})
тест не пройден с TypeError: (0 , _api2.default) is not a function
Я прибег к непосредственному импорту фиктивного API и его непосредственному вызову, который работает нормально, но не может протестировать модуль, который должен выполнять вызов API; Я чувствую, что это почти спорный вопрос, чтобы проверить эту функциональность таким образом, и я бы предпочел протестировать компонент таким образом, чтобы должным образом эмулировать его работу, то есть вызвать событие, которое вызовет вызов API вместо простого вызова API. , Как jest.mock()
предполагается использовать? И я неправильно его использую?
Для пункта 2 - Я манипулирую состоянием реакции компонента напрямую и проверяю обновления пользовательского интерфейса, а не симулирую пользовательский ввод через поля формы. Я пытаюсь получить доступ к полю ввода файла с помощью энзима find
let testFileUpload;
beforeEach(() => {
testFileUpload = mount(<FileUpload store={store} testProp="hello" />);
})
... other tests ...
it('click file upload button', () => {
testFileUpload.find('#upload_dataset_file_browser_button').simulate("change",
{
target: {
files: [ 'iris.csv' ]
}
});
})
}
и тест не пройден с ошибкой Method “simulate” is meant to be run on 1 node. 2 found instead.
Как мне получить доступ к элементу input / html файла по идентификатору и / или что фермент ожидает с имитацией? Я провел последние несколько дней, просматривая документацию и примеры шуток / энзимов, и мне нужна помощь. Почему метод find возвращает 2 узла, когда есть только один элемент с таким идентификатором? И как я должен имитировать событие изменения для выбора файла на указанном узле?
Подобно вышеупомянутому обходному пути, я изменяю состояние компонента напрямую и проверяю вещи с этого момента, но я бы предпочел имитировать реальные варианты использования как можно ближе.
Любая помощь очень ценится.
С учетом всего сказанного, можно ли обойти определенные вещи в модульных тестах, чтобы по существу достичь тех же результатов? В связи с моей проблемой у меня возникли проблемы с имитацией ввода в поле формы, в котором предполагается использовать response setState при вводе / изменении пользователем, поэтому я просто изменяю состояние вместо получения ввода через элемент пользовательского интерфейса. По мнению людей, знакомых с модульным тестированием, достаточно ли этого метода модульного тестирования или он абсолютно некорректен? Сейчас я в значительной степени единственный человек, который выполняет модульные тесты для компонентов пользовательского интерфейса переднего плана в этом проекте, и я не слишком уверен, как правильно тестировать эти части.