jquery не работает с jsdom/энзимом

У меня есть минимальное тестовое приложение со следующим компонентом:

import React from 'react';
import $ from 'jquery';

export default class App extends React.Component {
    componentDidMount() {
        console.log('componentDidMount', $('#helloDiv').length);
    }

    render() {
        return <div id='helloDiv'>
            Hello React!
                </div>;
    }
}

это отлично работает при загрузке в браузере (Chrome). console.log() в componentDidMount() выводит 1 найденный элемент helloDiv

Однако, если я запускаю тест, используя mocha + энзим + jsdom, тот же самый console.log() в компоненте приложения выводит 0:

import React from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import App from '../src/client/app/first'

describe('first test', () => {
    it('should pass', () => {        
        const app = mount(<App />);
        expect(app.find('#helloDiv').length).to.eq(1);
    });
});

Примечание. У меня нет проблем с этим модульным тестом, он проходит. Настоящая проблема заключается в том, что когда ‹ App /> монтируется с использованием фермента, вызывается componentDidMount(), но оператор console.log() внутри него выводит 0 вместо 1

Вот как я запускаю мокко:

mocha --require enzyme/withDom --compilers js:babel-core/register test/index.test.js

Есть идеи, почему селектор jquery ничего не находит в тесте? Это не должно быть проблемой мокко, потому что такая же проблема возникает, если я перехожу на шутку


person Phuong Nguyen    schedule 10.02.2017    source источник
comment
Рассмотрите возможность использования cheerio для приложений Node.Js вместо jQuery.   -  person Mijago    schedule 10.02.2017
comment
@Mijago спасибо за предложение. Однако в моем случае у меня нет большого выбора, по крайней мере, на данный момент. Это упрощенная версия текущего проекта, над которым я работаю, и jquery используется на протяжении всего проекта.   -  person Phuong Nguyen    schedule 10.02.2017
comment
Может быть, app.find('#helloDiv') ищет внутри приложения, но у самого приложения есть идентификатор? Ваша версия jQuery выполняет поиск по всему документу.   -  person Prinzhorn    schedule 10.02.2017
comment
@Prinzhorn извините, я думаю, что мой тест немного вводит в заблуждение. У меня нет проблем с самим ожиданием. Проблема заключается в том, что при монтировании компонента ‹App /› вызывается componentDidMount(), но console.log() внутри него выводит 0. Я обновлю вопрос, чтобы прояснить это   -  person Phuong Nguyen    schedule 10.02.2017
comment
Я думаю, ответ все еще актуален. Компонент на самом деле не монтируется внутри какого-либо документа, где jQuery может его найти. Он существует только внутри фермента ReactWrapper?   -  person Prinzhorn    schedule 10.02.2017
comment
@Prinzhorn поправьте меня, если я ошибаюсь: насколько я понимаю, фермент будет использовать jsdom в качестве безголового браузера и монтировать (полностью отображать) этот компонент реакции внутри документа jsdom. В этом случае jquery будет работать с документом jsdom и сможет найти helloDiv?   -  person Phuong Nguyen    schedule 10.02.2017
comment
Если вы используете React, не используйте также jQuery. React позволяет вам программировать с явным обещанием, что факт наличия DOM не имеет значения. Все, что вам нужно сделать, вы делаете, не касаясь DOM; это работа React под капотом. Если вам нужно знать, сколько дочерних элементов содержится в компоненте: вы знаете сколько, потому что вы написали код, генерирующий эти дочерние элементы, как часть функции render(). Использование jQuery для поиска информации путем проверки DOM не имеет смысла в этом контексте.   -  person Mike 'Pomax' Kamermans    schedule 11.02.2017


Ответы (3)


Наконец нашел проблему:

Enzyme mount(<SomeComponent />) по умолчанию выполняет полный рендеринг DOM, но не вставляет визуализированный компонент в текущий документ (JSDom). Вот почему jQuery не может найти ни одного элемента в текущем документе.

Чтобы выполнить полный рендеринг DOM И прикрепить к текущему документу:

mount(<SomeComponent />, { attachTo: document.getElementById('app') });

Где app — пустой div, доступный при настройке jsdom:

global.document = jsdom('<html><head></head><body><div id="app" /></body></html>');
person Phuong Nguyen    schedule 14.02.2017
comment
У меня похожая проблема. Ваш ответ частично решает это. Но проблема в том, что я запускаю свои тестовые примеры с помощью npm run test -- --watch, где test — это mocha --require babel-polyfill --require babel-core/register --require ./test/withDom.js --require ./test/test_helper.js --recursive ./test команда для запуска тестовых случаев. Итак, при первом запуске все работает нормально, но как только я изменяю некоторые тестовые примеры, наблюдатель автоматически повторно запускает тестовые случаи, и проблема, о которой вы упомянули, появляется снова. Буду очень признателен, если вы решите это. - person geeksal; 01.09.2019

Прежде чем вы сможете использовать jsdom с jquery в node-env, необходимо выполнить некоторую настройку.

Попробуйте это, если это поможет.

Создайте тестовый вспомогательный файл следующим образом:

test_helper.js

import _$ from 'jquery';
import jsdom from 'jsdom';
import chai, { expect } from 'chai';
import chaiJquery from 'chai-jquery';

global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = global.document.defaultView;
global.navigator = global.window.navigator;
const $ = _$(window);

chaiJquery(chai, chai.util, $);

export {expect};

Во время бега -

mocha --require enzyme/withDom --compilers js:babel-core/register --require test/test_helper.js test/index.test.js

или другим способом используйте jsdom-global без файла test_helper.js.

npm install --save-dev jsdom-global

Затем :

import 'jsdom-global/register'; 

//at the top of file , even  , before importing react
person WitVault    schedule 11.02.2017
comment
нет, я не получаю никакой ошибки. вывод console.log() по-прежнему равен 0. Я думаю, если это проблема с jquery, он будет жаловаться на $ not found и т. д. - person Phuong Nguyen; 11.02.2017
comment
используется ли ваш файл test_helper из предоставленного вами каталога? поместите некоторый console.log в файл test_helper.js, чтобы увидеть, правильно ли он указан - person WitVault; 11.02.2017
comment
Извините за поздний ответ. Я нашел проблему. Смотрите мой ответ для более подробной информации - person Phuong Nguyen; 14.02.2017
comment
Проблема, безусловно, была связана с jsdom. - person WitVault; 14.02.2017

Мне не удалось заставить ответ Фуонга Нгуена работать. Я нашел соответствующую страницу в документации по ферментам. В итоге я получил что-то вроде, основываясь на последнем примере на этой странице:

const div = global.document.createElement('div');
global.document.body.appendChild(graphDiv);
const wrapper = mount(<SomeComponent />, { attachTo: div });  // same as the other answer
// clean up after ourselves
wrapper.detach();
global.document.body.removeChild(div);
person user60561    schedule 28.04.2017
comment
Кажется, что graphDiv не определено. Возможно, graphDiv следует заменить на div. Это правильно? - person A.Chao; 18.10.2020