admin管理员组文章数量:1336311
The scenario
Trying to test a simple React ponent using Jest (and Enzyme). This ponent 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 ponent, 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 ponent', () => {
it('Mounts', () => {
const p = mount(<MyDropzone />)
const dz = p.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 ?
The scenario
Trying to test a simple React ponent using Jest (and Enzyme). This ponent 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 ponent, 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 ponent', () => {
it('Mounts', () => {
const p = mount(<MyDropzone />)
const dz = p.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 ?
Share asked Feb 6, 2018 at 12:07 stilllifestilllife 1,8061 gold badge20 silver badges39 bronze badges 8- stackoverflow./questions/41098009/mocking-document-in-jest – Daniel Conde Marin Commented Feb 6, 2018 at 12:14
- 1 I'm experiencing the same issue reading file on disk with a promise using jest. – Guillaume Malartre Commented Mar 15, 2018 at 17:35
- Everything is proper in jest setup. Using jsdom for document in test environment. Except for inside promise where document is null everywhere else document is defined. – Zword Commented Apr 24, 2018 at 14:41
- @Zword, can you give a minimal repo for debugging? It would be much faster – Tarun Lalwani Commented Apr 24, 2018 at 19:07
- @TarunLalwani here ya go. Interestingly enough, I found this was easy to reproduce with a JS app, but not with a TS app. – Mike Patrick Commented Apr 27, 2018 at 1:03
1 Answer
Reset to default 6 +50So I was able to resolve this. The assumption that it works without any config changes is wrong. First you need to add few more packages added. Below is my updated 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"
}
}
Also I removed --env=jsdom
from the test script. As I was not able to make it work with that bination
After that you need to create a src/setupTests.js
, which is load globals for your tests. This where you need to load jsdom
and 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() });
After that your tests would error out with below error
/Users/tarun.lalwani/Desktop/tarunlalwani./tarunlalwani/workshop/ub16/so/jsdom-js-demo/node_modules/react-scripts/scripts/test.js:20
throw err;
^
ReferenceError: FileReader is not defined
The issue seems to be that FileReader
should referred with a window
scope. So you need to update it like below
const reader = new window.FileReader()
And then run the tests again
Now the tests work fine
本文标签: javascriptJest with jsdomdocument is undefined inside Promise resolveStack Overflow
版权声明:本文标题:javascript - Jest with jsdom, document is undefined inside Promise resolve - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742260922a2442495.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论