Шутка с JSDOM, документ не определен внутри Обещание решить
Сценарий
Попытка протестировать простой компонент React с использованием Jest (и Enzyme). Этот компонент использует react-dropzone
и я хочу протестировать некоторые операции с участием DOM, поэтому я использую jsdom (как уже настроено create-react-app
)
Эта проблема
document
объект доступен в тестовом коде my, а также доступен внутри компонента, undefined
внутри дропзоны onDrop
обратный вызов, который препятствует выполнению теста.
Код
MyDropzone
import React from 'react'
import Dropzone from 'react-dropzone'
const MyDropzone = () => {
const onDrop = ( files ) =>{
fileToBase64({file: files[0]})
.then(base64Url => {
return resizeBase64Img({base64Url})
})
.then( resizedURL => {
console.log(resizedURL.substr(0, 50))
})
}
return (
<div>
<Dropzone onDrop={onDrop}>
Some text
</Dropzone>
</div>
);
};
const fileToBase64 = ({file}) => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => {
return resolve(reader.result)
}
reader.onerror = (error) => {
return reject(error)
}
reader.readAsDataURL(file)
})
}
/**
* Resize base64 image to width and height,
* keeping the original image proportions
* with the width winning over the height
*
*/
const resizeBase64Img = ({base64Url, width = 50}) => {
const canvas = document.createElement('canvas')
canvas.width = width
const context = canvas.getContext('2d')
const img = new Image()
return new Promise((resolve, reject) => {
img.onload = () => {
const imgH = img.height
const imgW = img.width
const ratio = imgW / imgH
canvas.height = width / ratio
context.scale(canvas.width / imgW, canvas.height / imgH)
context.drawImage(img, 0, 0)
resolve(canvas.toDataURL())
}
img.onerror = (error) => {
reject(error)
}
img.src = base64Url
})
}
export default MyDropzone;
MyDropzone.test.jsx
import React from 'react'
import { mount } from 'enzyme'
import Dropzone from 'react-dropzone'
import MyDropzone from '../MyDropzone'
describe('DropzoneInput component', () => {
it('Mounts', () => {
const comp = mount(<MyDropzone />)
const dz = comp.find(Dropzone)
const file = new File([''], 'testfile.jpg')
console.log(document)
dz.props().onDrop([file])
})
})
setupJest.js
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
configure({ adapter: new Adapter() })
конфиг
- По умолчанию
create-react-app
шутить сsetupJest.js
Добавлено вsetupFiles
- Run: тест пряжи
ошибка
TypeError: Cannot read property 'createElement' of undefined
at resizeBase64Img (C:\dev\html\sandbox\src\MyDropzone.jsx:44:29)
at fileToBase64.then.base64Url (C:\dev\html\sandbox\src\MyDropzone.jsx:8:20)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
Больше информации
Считают, что document
всегда определяется, если запустить этот код в браузере, поэтому мне кажется, что проблема связана с jsdom или Jest.
Я не уверен, связано ли это с Promises, с FileReaded или с областью JS в целом.
Может быть, ошибка на стороне Jest?
1 ответ
Так что я смог решить это. Предположение, что оно работает без каких-либо изменений конфигурации, неверно. Сначала вам нужно добавить еще несколько пакетов. Ниже мой обновленный package.json
{
"name": "js-cra",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-dropzone": "^4.2.9",
"react-scripts": "1.1.4",
"react-test-renderer": "^16.3.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"devDependencies": {
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"jest-enzyme": "^6.0.0",
"jsdom": "11.10.0",
"jsdom-global": "3.0.2"
}
}
Также я удалил --env=jsdom
из тестового скрипта. Поскольку я не смог заставить его работать с этой комбинацией
После этого вам нужно создать src/setupTests.js
, который загружает глобалы для ваших тестов. Это где вам нужно загрузить jsdom
а также enzyme
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import 'jest-enzyme';
import 'jsdom-global/register'; //at the top of file , even , before importing react
configure({ adapter: new Adapter() });
После этого ваши тесты будут с ошибкой ниже
/Users/tarun.lalwani/Desktop/tarunlalwani.com/tarunlalwani/workshop/ub16/so/jsdom-js-demo/node_modules/react-scripts/scripts/test.js:20
throw err;
^
ReferenceError: FileReader is not defined
Проблема, кажется, в том, что FileReader
следует упомянуть с window
объем. Так что вам нужно обновить его, как показано ниже
const reader = new window.FileReader()
А затем снова запустите тесты
Теперь тесты работают нормально