I've been working on optimising my react project and today I implemented lazy loading of all my images using react-lazyload (https://github.com/jasonslyvia/react-lazyload).
The package works just fine but as soon as I tried to update my snapshot tests they all failed!
The error I'm getting is:
Uncaught [TypeError: Cannot read property 'position' of undefined]
I tried seeing what I could find on google but nothing came up.
Here is an example of one of my snapshot tests (they're about as basic as can be):
import React from 'react';
import renderer from 'react-test-renderer';
import App from './App';
describe('App', () => {
describe('Component Snapshot', () => {
it('should render correctly', () => {
const componentSnapshot = renderer.create(<App />).toJSON();
expect(componentSnapshot).toMatchSnapshot();
});
});
});
Do I need to mock the lazy load package? If so does anyone have any advice of how I would go about doing that?
Any help is greatly appreciated.
Incase anyone runs into this issue, I solved it by using 'enzyme-to-json' instead of 'react-test-renderer' in conjunction with enzymes own 'render' function.
Here is the updated test so you can see what I mean.
import React from 'react';
import { render } from 'enzyme';
import toJson from 'enzyme-to-json';
import App from './App';
describe('App', () => {
describe('Component Snapshot', () => {
it('should render correctly', () => {
const componentRender = render(<App />);
expect(toJson(componentRender)).toMatchSnapshot();
});
});
});
I don't know the exact reasons why react-test-renderer was bugging out, my gut is telling me that because there isn't a window within node for my lazy-load placeholders to populate there isn't a 'position' to define. I would guess that enzyme has some clever stuff going on behind the scenes to get around that?
If anyone has a more definitive explanation I'd love to hear it, but for now at least the problem is fixed :)
Related
Trying to test the Material-UI Slider with Reat-Test-Renderer gets an error: Uncaught [TypeError: Cannot read property 'addEventListener' of null]
Codesandbox Link
import React from "react";
import { Slider } from "#material-ui/core";
import renderer from "react-test-renderer";
it("should render", () => {
renderer.create(<Slider />);
});
This is not the case with any other Material UI components that I know of.
It seems to be related to forwardRef as described here, but I could not figure out a way to get it to work.
EDIT Unfortunately switching over to #testing-library/react is not an option this project I'm working on.
EDIT 2 The reason I am doing this is because I am trying to render and test a more complex component of my own which contains the Slider. It took me a while to figure out that this is what's causing the issue, and the code above is the minimal amount of code to replicate the issue.
EDIT 3 Error message screenshot
React Test Renderer only renders the components as a JS object rather than to a browser environment. Hence, anything that uses dom based refs will have this issue. Related jest issue: https://github.com/facebook/jest/issues/5462.
There is a section in the React Docs for a way to workaround it: https://reactjs.org/docs/test-renderer.html#ideas
EDIT:
Here's a working test. It likely makes a lot of the functionality of the slider not work, since we are setting the internal refs to null. But it does run. The "Next" branch on MUI doesn't have the findDOMNode function there, so that might be easier to work with.
I wasn't able to get these to work on CodeSandbox because jest was undefined, and I couldn't find how to fix that.
import React from 'react';
import { Slider } from '#material-ui/core';
import renderer from 'react-test-renderer';
jest.mock('react-dom', () => ({
// the useIsFocusVisible function in Slider.js (MUI component) uses findDOMNOde
// Luckily it checks if there's nulls, so we can return a null
// https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/utils/useIsFocusVisible.js#L136
findDOMNode: () => null,
}));
it('should render', () => {
renderer.create(<Slider />);
});
If you want to try and mock the full functionality (sort of), you can use this implementation of the findDOMNode mock, which will return the values that are needed for the useIsFocusVisible to run successfully including adding the event listener:
import React from 'react';
import { Slider } from '#material-ui/core';
import renderer from 'react-test-renderer';
jest.mock('react-dom', () => ({
// the useIsFocusVisible function in Slider.js (MUI component) uses findDOMNOde
// https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/utils/useIsFocusVisible.js#L136
findDOMNode: (instance) => {
return { ownerDocument: instance };
},
}));
it('should render', () => {
let eventListenerFn = jest.fn();
renderer.create(<Slider />, {
createNodeMock: (element) => {
if (element.type === 'span') {
return {
addEventListener: eventListenerFn,
};
}
},
});
});
In order to figure out how to get these tests to succesfully run, I had to step through the error stacks/MUI source code to find out what's going wrong and what values were needed to be mocked in order to not throw errors.
Original, showing how much better #testing-library is for this:
However, may I suggest using #testing-library? It's nice to work with and uses jsdom to render the components so it'll work with this component.
I went ahead and made a couple of random tests for the Slider using the testing library to show that it works with Slider and throws no errors:
import React from "react";
import { Slider } from "#material-ui/core";
import { render } from "#testing-library/react";
it("should render", () => {
render(<Slider />);
});
it("should render an input", () => {
const component = render(<Slider />);
const input = component.baseElement.querySelector("input");
expect(input).toBeDefined();
});
it("Should have the correct value", () => {
const component = render(<Slider value={50} />);
const input = component.baseElement.querySelector("input");
expect(input.value).toBe("50");
});
CodeSandbox
I've created a very basic functional component in React (using Typescript).
However when I go to test it - I keep getting received {} when I ask it gather the divs:
So the component looks like:
export const TestComponent: React.FC<FakeInt> = () => {
return (
<div>ARE YOU WORKING
<div>Checking here</div>
</div>
)
};
along with
interface FakeInt {}
And the test:
it('It does something', () => {
let wrapper = shallow(<TestComponent />);
expect(wrapper.find("div")).toEqual("")
});
(I've just put equal to "" - as I'd expect to see something received/just want to confirm its actually finding those divs)
If I had console.log(wrapper.debug()); I actually see the wrapper's content which is strange.
The version of Jest I'm using came with my React app.
And another piece of info. expect(wrapper).toMatchSnapshot(); creates a snapshot file which also contains an empty object {}
Any ideas what's up here/why this wouldn't work?
Thanks.
please provide the version of enzyme you are using, also for react you should use enzyme-adapter-react-16 (or what ever version of react you are using)
in the test:
import { shallow, configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
configure({ adapter: new Adapter() })
than it should work
I am writing a test for a component that is wrapped in a withStyles() from Material UI using Jest. I need to test the children elements, but my wrapper is undefined.
I've seen another post similar to writing tests with withStyles(), but the undefined error still persists.
Test File:
import { shallow } from 'enzyme';
import { TempComponent } from '../../../../src/components/helpers/temp';
describe('temp', () => {
let wrapper;
const renderComponent = () => shallow(<TempComponent />);
beforeEach(() => {
wrapper = renderComponent();
});
it('render correctly', () => {
expect(wrapper.type()).toEqual('div');
});
});
Component:
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
const TempComponent = () => <button>Click Me!</button>;
export default withStyles({})(TempComponent);
I get this error for my test:
Invariant Violation: ReactShallowRenderer render(): Shallow rendering works only with custom components, but the provided element type was undefined.
I am wanting the wrapper component to behave the same way as a wrapper without the withStyles() component. Any help would be appreciated!
Note: I am not doing snapchat testing with jest
This appears to be the issue and solution:
https://github.com/mui-org/material-ui/issues/9266#issuecomment-349447137
The issue isn't about the children elements but with the intermediary
element, it's creating. The shallow() API of enzyme only render one
level depth. Any higher-order component is going to obfuscate the
children. You have different workarounds. I would encourage you to
refer to the enzyme documentation. Still, here they are:
use mount()
use .dive()
use our createShallow() public API
use our internal until() helper
I'm having an issue testing components using Card component (Ant Design). Every time I run my tests I encounter messages like this :
Error: Uncaught [RangeError: Maximum call stack size exceeded]
The above error occurred in the component
Does anybody know about this issue ? I tried to find something on Ant Design git but the few pages I found were not in english and do not seems to be realted to my issue.
I tried to test directly the Ant Design component (Card) with a mount (https://github.com/ant-design/ant-design/blob/master/components/card/tests/index.test.js) but I encouter the same error...
Here is my second test with only Ant Design component :
import React from 'react'
import { mount } from 'enzyme'
import { Card } from 'antd'
describe('Card', () => {
beforeAll(() => {
jest.useFakeTimers()
})
afterAll(() => {
jest.useRealTimers()
})
it('should still have padding when card which set padding to 0 is loading', () => {
const wrapper = mount(<Card title="xxx">xxx</Card>)
})
})
I have an Enzyme adapter in my setup. Here I just wanted to show you how simple my code is however I can't product any result...
Somebody can help ?
I want to do some basic unit test to my app which I created with "create-react-app" package. I believe it already has Jest installed.
I have some basic redux code in my app.
I want to test:
It renders the main component(App.js) without crashing
Clicking to show next item funcion
I have installed Enzyme using "npm install --save-dev enzyme" and "enzyme-adapter-react-15".
Here is my code:
import React from 'react';
import ReactDOM from 'react-dom';
import {App} from './App';
import { shallow, mount, render, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';
configure({ adapter: new Adapter() });
describe('A test for App component', () => {
let wrapper
beforeEach(()=>{
wrapper = shallow(<App />);
})
it('should render App Component', () => {
expect(wrapper).to.have.length(1)
})
})
I can't get the test to start to work. The error message:
TypeError: Cannot read property 'length' of undefined
and
TypeError: Cannot read property 'have' of undefined
I think there is some basic things I am doing wrong.
Any help is appreciated!!!
You are using Jest's expect function. You need to explicitly declare the import from chai.
it will look something like:
import { expect } from 'chai'
it('should render App Component', () => {
expect(wrapper).to.have.length(1)
})
Also, instead of adding the adapter configuration for each test, you could add a file setupTests.js to /src and it will work for all tests :-)
You probably copied it from the examples on enzyme's website, which uses chai. The jest equivalent for what you're trying to test is:
it('should render App Component', () => {
expect(wrapper).toHaveLength(1)
})