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 ?
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 made a small react project with typescript
and i made it to print numbers of li tag to browser.
so i tried to implement unit test that test component create HTMLElement
but I really confused. I'm a newbie with typescript
import * as React from "react";
import { render } from "#testing-library/react";
import List from "../component/List";
describe("<List />", () => {
it("check li tags were made perfectly", async () => {
const component = render(<List />);
component.getByText("li");
});
this code's output is error at render(<List />);
my component doesn't require any props
how can i make this code is able to run properly?
Thanks to, #Edward Choupuryan
it was just simple problem.
i wanted to test react component with typescript, and that file need to has extension tsx . mine was just *.test.ts
i changed my testfile testfile.test.ts to testfile.test.tsx, and problem solved
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 :)
I am using jest and enzyme to test my react component which relies on antd - a 3rd react UI library.
For illustrative purpose, I produce the minimal code that is fair enough to show my question.
See my test component as follow:
import React from 'react';
import { Button } from 'antd';
function Test({onSubmit}) {
return (
<div>
<Button htmlType="submit" type="primary" />
</div>
);
}
export default Test;
Q1: I mock up the Button as below since unit test requires us to isolate the target and mock up any other dependencies.
Is that correct?
__mocks__
antd.js
antd.js
import mockComponent from '../mockComponent';
const list = [
'Form',
'Input',
'Button',
'Spin',
'Icon'
];
const mockups = list.reduce((prev, next) => {
prev[next] = mockComponent(next);
return prev;
}, {});
mockups.Form.Item = mockComponent('Form.Item');
export const Form = mockups.Form;
export const Input = mockups.Input;
export const Button = mockups.Button;
export const Spin = mockups.Spin;
export const Icon = mockups.Icon;
mockComponent.js
import React from 'react';
export default function mockComponent (name) {
return props => React.createElement(name, props, props.children);
}
Q2. I have got the following warning even if the test passes. How can I resolve that?
test.spec.js
import React from 'react';
import { shallow, mount } from 'enzyme';
import renderer from 'react-test-renderer';
import Test from '../components/question';
describe('mount test', () => {
let wrapper;
let props;
let mountedLogin;
const test = () => {
if (!mountedLogin) {
mountedLogin = mount(<Test {...props} />);
}
return mountedLogin;
};
beforeEach(() => {
mountedLogin = null;
});
it('always render test as the root', () => {
const divs = test().find('div');
expect(divs.length).toBeGreaterThan(0);
});
});
warning
console.error node_modules/fbjs/lib/warning.js:36
Warning: Unknown prop `htmlType` on <Button> tag. Remove this prop from the
element. For details, see
in Button (created by Unknown)
in Unknown (created by Test)
in div (created by Test)
in Test (created by WrapperComponent)
in WrapperComponent
A side note, I haven't got any jest configs in my package.json.
Can anybody help me out with these.
Many thanks
Q1: I mock up the Button as below since unit test requires us to
isolate the target and mock up any other dependencies. Is that
correct?
Currently, the recommended approach for React unit testing is shallow rendering. It basically renders the given component one level deep. If we shallow render your Test component, it will call render method of Test component, but not the render method of Button component. Even though Button is 3rd party component and dependency, we don't need to mock it. Because we don't render it. But still, we will be able to see whether it's in the component tree and it has got the correct props. This is what essentially we will assert with the mocking approach also. However, shallow rendering has few limitations also, but usually, it works very well for most of the scenarios.
But you can obviously mock children and render the whole component also. But it's time-consuming and problematic, at least with my experience.
Q2: I have got the following warning even if the test passes. How can
I resolve that?
Since you pass a string as name for React.createElement, React think you want to create a normal HTML element, and not a React component. But since there is a no HTML element call Button (case sensitive) and it doesn't know prop called htmlType, you get this unknown prop type warning. To prevent this warning, either you can stop passing props to React.createElement or pass a mock component to React.createElement instead of the name string.
import React from 'react';
function Mock(){
retun (<div/>);
}
export default function mockComponent (name) {
return props => {
return React.createElement(Mock, {...props, name}, props.children);
}
}
If you need to read more about react unit testing, I suggest you to go through this thread from react discuss forum.
Hope this helps!