The scenario
Trying to test a simple React component using Jest (and Enzyme). This component uses react-dropzone
and I want to test some operations involving the DOM so I use jsdom (as already configured by create-react-app
)
The problem
The document
object while available in the my test code and also available inside of the component, is undefined
inside of the dropzone onDrop
callback, which prevents the test from running.
The code
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() })
Config
- Default
create-react-app
jest config withsetupJest.js
added tosetupFiles
- Run: yarn test
Error
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)
More info
Consider that document
is always defined if running that code in the browser, so to me the issue seems related with jsdom or Jest.
I am not sure if it is related with Promises, with the FileReaded or with the JS scope in general.
Maybe a bug on Jest side ?