Enzyme can't shallow render because of an imported script using 'addEventListener'
Long story short, I have a React app that is importing a vanilla.js component. This component interacts with the DOM outside of the React app, but sometimes the React app needs to use the component. When I try and shallow render the React component that imports the Login component, Jest gets hung up on 'addEventListener' in the vanilla.js Login component:
TypeError: Cannot read property 'addEventListener' of null
90 | }
91 |
> 92 | document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
| ^
93 | document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
94 | };
So I have my react app:
import React from 'react';
import Login from '../login';
const Component = () =>
return (
<h3>
<span className='cc-stats-login-btn' onClick=(e) =>
Login.openRegister(e, 'Statistics')>Register</span>
or
<span className='cc-stats-login-btn' onClick=(e) => Login.openLogin(e, 'Statistics')>login</span>
to view advanced analytics and graphs
</h3>
);
;
The test for that app currently looks like:
document.body.innerHTML =
'<div class="login-modal-bg">' +
' <div class="login-modal-close"></div>' +
'</div>';
describe('<Component />', () =>
test('renders', () =>
const wrapper = shallow(
<Component />
);
expect(wrapper.exists()).toBe(true);
);
);
The js for the login component that Jest seems to be failing on:
const Login = (() =>
const config =
selectors:
loginModal: '.login-modal-bg',
loginClose: '.login-modal-close'
;
[...]
const initialize = () =>
document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
;
;
As far as I can tell based on Jest docs, all I need is a simple string as a 'mock dom' and the addEventListener should work. But all I get is the above TypeError. Any ideas?
javascript reactjs jestjs enzyme
|
show 2 more comments
Long story short, I have a React app that is importing a vanilla.js component. This component interacts with the DOM outside of the React app, but sometimes the React app needs to use the component. When I try and shallow render the React component that imports the Login component, Jest gets hung up on 'addEventListener' in the vanilla.js Login component:
TypeError: Cannot read property 'addEventListener' of null
90 | }
91 |
> 92 | document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
| ^
93 | document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
94 | };
So I have my react app:
import React from 'react';
import Login from '../login';
const Component = () =>
return (
<h3>
<span className='cc-stats-login-btn' onClick=(e) =>
Login.openRegister(e, 'Statistics')>Register</span>
or
<span className='cc-stats-login-btn' onClick=(e) => Login.openLogin(e, 'Statistics')>login</span>
to view advanced analytics and graphs
</h3>
);
;
The test for that app currently looks like:
document.body.innerHTML =
'<div class="login-modal-bg">' +
' <div class="login-modal-close"></div>' +
'</div>';
describe('<Component />', () =>
test('renders', () =>
const wrapper = shallow(
<Component />
);
expect(wrapper.exists()).toBe(true);
);
);
The js for the login component that Jest seems to be failing on:
const Login = (() =>
const config =
selectors:
loginModal: '.login-modal-bg',
loginClose: '.login-modal-close'
;
[...]
const initialize = () =>
document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
;
;
As far as I can tell based on Jest docs, all I need is a simple string as a 'mock dom' and the addEventListener should work. But all I get is the above TypeError. Any ideas?
javascript reactjs jestjs enzyme
1
Testability is one of reasons why direct DOM access is not a good idea in React. I would suggest to mockdocument.querySelectorcalls instead of mocking DOM.
– estus
Nov 13 '18 at 19:15
I agree that the direct DOM access isn't great in React. But due to far stranger business related decisions, it's not something I can do. I tried the following to mock document.querySelector and none of it works:document.querySelector = jest.fn();global.document.querySelector = jest.fn();global.document.querySelector.addEventListener = jest.fn();
– BrockBeldham
Nov 13 '18 at 19:25
What was the result?
– estus
Nov 13 '18 at 19:26
always the same error:TypeError: Cannot read property 'addEventListener' of null
– BrockBeldham
Nov 13 '18 at 19:29
1
Yes, that's an antipattern. I updated the answer. Since addEventListener doesn't even used in tested component, there's no need to even bother with it. Mock entire Login module and test it separately.
– estus
Nov 13 '18 at 20:29
|
show 2 more comments
Long story short, I have a React app that is importing a vanilla.js component. This component interacts with the DOM outside of the React app, but sometimes the React app needs to use the component. When I try and shallow render the React component that imports the Login component, Jest gets hung up on 'addEventListener' in the vanilla.js Login component:
TypeError: Cannot read property 'addEventListener' of null
90 | }
91 |
> 92 | document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
| ^
93 | document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
94 | };
So I have my react app:
import React from 'react';
import Login from '../login';
const Component = () =>
return (
<h3>
<span className='cc-stats-login-btn' onClick=(e) =>
Login.openRegister(e, 'Statistics')>Register</span>
or
<span className='cc-stats-login-btn' onClick=(e) => Login.openLogin(e, 'Statistics')>login</span>
to view advanced analytics and graphs
</h3>
);
;
The test for that app currently looks like:
document.body.innerHTML =
'<div class="login-modal-bg">' +
' <div class="login-modal-close"></div>' +
'</div>';
describe('<Component />', () =>
test('renders', () =>
const wrapper = shallow(
<Component />
);
expect(wrapper.exists()).toBe(true);
);
);
The js for the login component that Jest seems to be failing on:
const Login = (() =>
const config =
selectors:
loginModal: '.login-modal-bg',
loginClose: '.login-modal-close'
;
[...]
const initialize = () =>
document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
;
;
As far as I can tell based on Jest docs, all I need is a simple string as a 'mock dom' and the addEventListener should work. But all I get is the above TypeError. Any ideas?
javascript reactjs jestjs enzyme
Long story short, I have a React app that is importing a vanilla.js component. This component interacts with the DOM outside of the React app, but sometimes the React app needs to use the component. When I try and shallow render the React component that imports the Login component, Jest gets hung up on 'addEventListener' in the vanilla.js Login component:
TypeError: Cannot read property 'addEventListener' of null
90 | }
91 |
> 92 | document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
| ^
93 | document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
94 | };
So I have my react app:
import React from 'react';
import Login from '../login';
const Component = () =>
return (
<h3>
<span className='cc-stats-login-btn' onClick=(e) =>
Login.openRegister(e, 'Statistics')>Register</span>
or
<span className='cc-stats-login-btn' onClick=(e) => Login.openLogin(e, 'Statistics')>login</span>
to view advanced analytics and graphs
</h3>
);
;
The test for that app currently looks like:
document.body.innerHTML =
'<div class="login-modal-bg">' +
' <div class="login-modal-close"></div>' +
'</div>';
describe('<Component />', () =>
test('renders', () =>
const wrapper = shallow(
<Component />
);
expect(wrapper.exists()).toBe(true);
);
);
The js for the login component that Jest seems to be failing on:
const Login = (() =>
const config =
selectors:
loginModal: '.login-modal-bg',
loginClose: '.login-modal-close'
;
[...]
const initialize = () =>
document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
;
;
As far as I can tell based on Jest docs, all I need is a simple string as a 'mock dom' and the addEventListener should work. But all I get is the above TypeError. Any ideas?
javascript reactjs jestjs enzyme
javascript reactjs jestjs enzyme
edited Nov 13 '18 at 20:33
skyboyer
3,75311229
3,75311229
asked Nov 13 '18 at 18:30
BrockBeldhamBrockBeldham
164
164
1
Testability is one of reasons why direct DOM access is not a good idea in React. I would suggest to mockdocument.querySelectorcalls instead of mocking DOM.
– estus
Nov 13 '18 at 19:15
I agree that the direct DOM access isn't great in React. But due to far stranger business related decisions, it's not something I can do. I tried the following to mock document.querySelector and none of it works:document.querySelector = jest.fn();global.document.querySelector = jest.fn();global.document.querySelector.addEventListener = jest.fn();
– BrockBeldham
Nov 13 '18 at 19:25
What was the result?
– estus
Nov 13 '18 at 19:26
always the same error:TypeError: Cannot read property 'addEventListener' of null
– BrockBeldham
Nov 13 '18 at 19:29
1
Yes, that's an antipattern. I updated the answer. Since addEventListener doesn't even used in tested component, there's no need to even bother with it. Mock entire Login module and test it separately.
– estus
Nov 13 '18 at 20:29
|
show 2 more comments
1
Testability is one of reasons why direct DOM access is not a good idea in React. I would suggest to mockdocument.querySelectorcalls instead of mocking DOM.
– estus
Nov 13 '18 at 19:15
I agree that the direct DOM access isn't great in React. But due to far stranger business related decisions, it's not something I can do. I tried the following to mock document.querySelector and none of it works:document.querySelector = jest.fn();global.document.querySelector = jest.fn();global.document.querySelector.addEventListener = jest.fn();
– BrockBeldham
Nov 13 '18 at 19:25
What was the result?
– estus
Nov 13 '18 at 19:26
always the same error:TypeError: Cannot read property 'addEventListener' of null
– BrockBeldham
Nov 13 '18 at 19:29
1
Yes, that's an antipattern. I updated the answer. Since addEventListener doesn't even used in tested component, there's no need to even bother with it. Mock entire Login module and test it separately.
– estus
Nov 13 '18 at 20:29
1
1
Testability is one of reasons why direct DOM access is not a good idea in React. I would suggest to mock
document.querySelector calls instead of mocking DOM.– estus
Nov 13 '18 at 19:15
Testability is one of reasons why direct DOM access is not a good idea in React. I would suggest to mock
document.querySelector calls instead of mocking DOM.– estus
Nov 13 '18 at 19:15
I agree that the direct DOM access isn't great in React. But due to far stranger business related decisions, it's not something I can do. I tried the following to mock document.querySelector and none of it works:
document.querySelector = jest.fn(); global.document.querySelector = jest.fn(); global.document.querySelector.addEventListener = jest.fn();– BrockBeldham
Nov 13 '18 at 19:25
I agree that the direct DOM access isn't great in React. But due to far stranger business related decisions, it's not something I can do. I tried the following to mock document.querySelector and none of it works:
document.querySelector = jest.fn(); global.document.querySelector = jest.fn(); global.document.querySelector.addEventListener = jest.fn();– BrockBeldham
Nov 13 '18 at 19:25
What was the result?
– estus
Nov 13 '18 at 19:26
What was the result?
– estus
Nov 13 '18 at 19:26
always the same error:
TypeError: Cannot read property 'addEventListener' of null– BrockBeldham
Nov 13 '18 at 19:29
always the same error:
TypeError: Cannot read property 'addEventListener' of null– BrockBeldham
Nov 13 '18 at 19:29
1
1
Yes, that's an antipattern. I updated the answer. Since addEventListener doesn't even used in tested component, there's no need to even bother with it. Mock entire Login module and test it separately.
– estus
Nov 13 '18 at 20:29
Yes, that's an antipattern. I updated the answer. Since addEventListener doesn't even used in tested component, there's no need to even bother with it. Mock entire Login module and test it separately.
– estus
Nov 13 '18 at 20:29
|
show 2 more comments
1 Answer
1
active
oldest
votes
Testing against DOM (it isn't real in Jest because it uses JSDOM) in unit tests provides additional moving parts. document.querySelector can be mocked instead:
const loginModalMock = jest.fn();
const loginCloseMock = jest.fn();
jest.spyOn(document, 'querySelector')
.mockReturnValue()
.mockReturnValueOnce( addEventListener: loginModalMock )
.mockReturnValueOnce( addEventListener: loginCloseMock )
const wrapper = shallow(
<Component />
);
...
In this specific case document.querySelector is used not in tested module. The module that uses it can be mocked at the top of test file:
jest.mock('.../login', () => ( openLogin: jest.fn() ));
I believeLoginshould be better mocked even if it was used inComponent.
– skyboyer
Nov 13 '18 at 20:44
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287392%2fenzyme-cant-shallow-render-because-of-an-imported-script-using-addeventlistene%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Testing against DOM (it isn't real in Jest because it uses JSDOM) in unit tests provides additional moving parts. document.querySelector can be mocked instead:
const loginModalMock = jest.fn();
const loginCloseMock = jest.fn();
jest.spyOn(document, 'querySelector')
.mockReturnValue()
.mockReturnValueOnce( addEventListener: loginModalMock )
.mockReturnValueOnce( addEventListener: loginCloseMock )
const wrapper = shallow(
<Component />
);
...
In this specific case document.querySelector is used not in tested module. The module that uses it can be mocked at the top of test file:
jest.mock('.../login', () => ( openLogin: jest.fn() ));
I believeLoginshould be better mocked even if it was used inComponent.
– skyboyer
Nov 13 '18 at 20:44
add a comment |
Testing against DOM (it isn't real in Jest because it uses JSDOM) in unit tests provides additional moving parts. document.querySelector can be mocked instead:
const loginModalMock = jest.fn();
const loginCloseMock = jest.fn();
jest.spyOn(document, 'querySelector')
.mockReturnValue()
.mockReturnValueOnce( addEventListener: loginModalMock )
.mockReturnValueOnce( addEventListener: loginCloseMock )
const wrapper = shallow(
<Component />
);
...
In this specific case document.querySelector is used not in tested module. The module that uses it can be mocked at the top of test file:
jest.mock('.../login', () => ( openLogin: jest.fn() ));
I believeLoginshould be better mocked even if it was used inComponent.
– skyboyer
Nov 13 '18 at 20:44
add a comment |
Testing against DOM (it isn't real in Jest because it uses JSDOM) in unit tests provides additional moving parts. document.querySelector can be mocked instead:
const loginModalMock = jest.fn();
const loginCloseMock = jest.fn();
jest.spyOn(document, 'querySelector')
.mockReturnValue()
.mockReturnValueOnce( addEventListener: loginModalMock )
.mockReturnValueOnce( addEventListener: loginCloseMock )
const wrapper = shallow(
<Component />
);
...
In this specific case document.querySelector is used not in tested module. The module that uses it can be mocked at the top of test file:
jest.mock('.../login', () => ( openLogin: jest.fn() ));
Testing against DOM (it isn't real in Jest because it uses JSDOM) in unit tests provides additional moving parts. document.querySelector can be mocked instead:
const loginModalMock = jest.fn();
const loginCloseMock = jest.fn();
jest.spyOn(document, 'querySelector')
.mockReturnValue()
.mockReturnValueOnce( addEventListener: loginModalMock )
.mockReturnValueOnce( addEventListener: loginCloseMock )
const wrapper = shallow(
<Component />
);
...
In this specific case document.querySelector is used not in tested module. The module that uses it can be mocked at the top of test file:
jest.mock('.../login', () => ( openLogin: jest.fn() ));
edited Nov 13 '18 at 20:27
answered Nov 13 '18 at 19:38
estusestus
73.5k22108224
73.5k22108224
I believeLoginshould be better mocked even if it was used inComponent.
– skyboyer
Nov 13 '18 at 20:44
add a comment |
I believeLoginshould be better mocked even if it was used inComponent.
– skyboyer
Nov 13 '18 at 20:44
I believe
Login should be better mocked even if it was used in Component.– skyboyer
Nov 13 '18 at 20:44
I believe
Login should be better mocked even if it was used in Component.– skyboyer
Nov 13 '18 at 20:44
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287392%2fenzyme-cant-shallow-render-because-of-an-imported-script-using-addeventlistene%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Testability is one of reasons why direct DOM access is not a good idea in React. I would suggest to mock
document.querySelectorcalls instead of mocking DOM.– estus
Nov 13 '18 at 19:15
I agree that the direct DOM access isn't great in React. But due to far stranger business related decisions, it's not something I can do. I tried the following to mock document.querySelector and none of it works:
document.querySelector = jest.fn();global.document.querySelector = jest.fn();global.document.querySelector.addEventListener = jest.fn();– BrockBeldham
Nov 13 '18 at 19:25
What was the result?
– estus
Nov 13 '18 at 19:26
always the same error:
TypeError: Cannot read property 'addEventListener' of null– BrockBeldham
Nov 13 '18 at 19:29
1
Yes, that's an antipattern. I updated the answer. Since addEventListener doesn't even used in tested component, there's no need to even bother with it. Mock entire Login module and test it separately.
– estus
Nov 13 '18 at 20:29