Enzyme shallow test on custom component - reactjs

I have this test:
it('renders', () => {
wrapper = shallow(<CustomComponent {...props} />);
expect(wrapper.length).toBeGreaterThan(0);
expect(wrapper.text()).toContain('Text example');
});
I had to change on the code the string 'Text example' with a custom component:
<Custom resourceKey='Text example'/>
so now the second expect won't work, I don't have much experience with enzyme testing, I would check the text ignoring the Custom tag and that's where I got lost, I tried many different properties, but still can't find the correct one.
The closets I got was this:
expect(wrapper.children().text()).toContain('Text example');
But still not working.
Can anyone help?
Thanks

Related

Jest: Prevent output to be omitted [duplicate]

I am using react jest with react testing library to test my component.
I am facing a weird issue. I am usng debug return by render from testing-library.
test('component should work', async () => {
const { findByText, debug } = render(<MyComponent />);
const myElement = await findByText(/someText/i);
debug();
});
As you can see in the screenshot there are incomplete dev and closing tags for parents are missing.
You need to change the value of DEBUG_PRINT_LIMIT env variable (default is 7000).
For example, run your tests with: DEBUG_PRINT_LIMIT=10000 yarn test
Source: https://github.com/testing-library/dom-testing-library/blob/master/src/pretty-dom.js#L33
I am using this version: "#testing-library/react": "^11.0.4"
able to do just like below, we can change 300000 as the max length of output.
debug(undefined, 300000)
Another option
screen.debug(undefined, Infinity);
The second argument of the debug() function can be used to set maxLengthToPrint.
E.g. to print everything in myElement using the recommended screen approach:
import {render, screen} from '#testing-library/react'
render(<MyComponent />);
const myElement = await screen.findByText(/someText/i);
const maxLengthToPrint = 100000
screen.debug(myElement, maxLengthToPrint);
See:
Api docs for debug() in render results
Api docs for screen.debug()
You can use Jest Preview (https://github.com/nvh95/jest-preview) to view your app UI when testing in a browser, instead of HTML in the terminal, just by 2 lines of code:
import { debug } from 'jest-preview';
describe('App', () => {
it('should work as expected', () => {
render(<App />);
debug();
});
});
It works great with jest and react-testing-library.
Introduction: https://www.jest-preview.com/docs/getting-started/intro
Installation guide: https://www.jest-preview.com/docs/getting-started/installation
If none of the other answers work for you, make sure it's not your terminal limit. For example VS Code only keeps 5000 lines in buffer. Try Mac OS terminal.
This worked for me:
debug(undefined, 300000);
It will give you the markeup of whatever you passed into render() as:
import {render, screen} from '#testing-library/react'
render(<MyComponent />);
You can read about more ways to help you with printing out the results, including prettifying the resulting markup at:
API doc for debug
This worked for me
const history = createMemoryHistory()
const { debug } = renderWithRedux(
<Router history={history}>
<SideBar />
</Router>
, state);
screen.debug(debug(), 20000);
Since the DOM size can get really large, you can set the limit of DOM content to be printed via environment variable DEBUG_PRINT_LIMIT. The default value is 7000. You will see ... in the console, when the DOM content is stripped off, because of the length you have set or due to default size limit. Here's how you might increase this limit when running tests:
DEBUG_PRINT_LIMIT=10000 npm test
Here more about debuggin on documentation
Adding on top of answer by #Haryono
Also make sure you don't have silent flag set in scripts
"test": "jest --config jest.config.js --silent";
Removing silent flag should work.
Note: I think silent flag supresses warnings and debug outputs
Also be sure your terminal allows you to scroll back that far. In iTerm2, I had my "Scrollback lines" set to 1000. Changed it to "Unlimited scrollback" and how life is good iTerm2:
By default RTL doesn't show comments, <script /> and <style /> tags. In my case I needed to test for a commented node in the DOM.
If you want your tests to include all the nodes, you can use prettyDOM like this:
// render DOM with a commented node
const html = {__html: '<!--this is a commented DOM element-->'};
const element = <div dangerouslySetInnerHTML={html} />;
const { container } = render(element);
// This is what tells RLT to print all nodes!
const prettyfiedDOM = prettyDOM(container, undefined, { filterNode: () => true}) || '';
expect(prettyfiedDOM.includes('<!--this is a commented DOM element-->')).toBeTruthy();
Notice that the filterNode function always returns true, which tells RTL to print all DOM nodes, and hence you can test comments, styles, tags, etc. You can read more on prettyDOM source code and configure your desired behavior of DOM filtering.
View the live demo here
Hope that helps!

React Testing Library - Unable to find the element with data-testid

I am following the docs for react-testing-library to find if the element with data-testid attribute is rendered or not.
The react-testing-library is not able to find the element even though it exists.
TEST
test('Renders step based on the active step', () => {
render(<RenderStep />, { initialState: { implOnboard: initialState } });
});
expect(screen.getByTestId('step-1')).toBeDefined(); // 👉 THROWS ERROR ❌
}
COMPONENT
// redux
const { activeStep } = useSelector((state) => state.implOnboard);
const renderStep = () => {
switch (activeStep) {
case 1:
console.log('Rendering this 🔥'); // 👈 THIS IS GETTING LOGGED TOO!
return (
<div data-testid="step-1">
<StepOne />
</div>
);
case 2:
return (
<div data-testid="step-2">
<StepTwo />
</div>
);
}
};
return <React.Fragment>{renderStep()}</React.Fragment>;
ERROR
TestingLibraryElementError: Unable to find an element by: [data-testid="step-1"]
Please use the queryByTestId instead getByTestId for the case. It will work.
The answer from Elena is wrong and just masks the error. Using queryByTestId will return null if the element is not found, instead of an error when using getByTestId, and the assertion will actually be:
expect(null).toBeDefined();
and this WILL pass. This is not testing anything. toBeDefined() fails only if the element is equal to undefined and it passes for everything else.
If OP wants to actually check if that element is NOT present they should do:
expect(screen.queryByTestId('step-1')).not.toBeInTheDocument();
The original error from OP is probably happening because the expect is outside the test block.
Adding to Elena's response, we need to use queryByTestId because, queryByTestId returns null value if element is not found instead of throwing error unlike getByTestId. Here's the image that explains when to use different methods.
Sometimes you get an error even when using this queryBy, so please check other code before this statement.
Reference - https://www.youtube.com/watch?v=Yghw9FkNGsc&list=PL4cUxeGkcC9gm4_-5UsNmLqMosM-dzuvQ&index=5&ab_channel=TheNetNinja
For those using React Native Web, you will need to use testID which will compile down to data-testid on the element. It needs to be on a react native element not your custom one (pass it through as a prop and put it on a View, etc.).

How to get the root tag name in enzyme?

I am trying to test a component whose output depends on a property, ie: props.editable == 'true' : render input otherwise render div
I have tried doing:
expect(wrapper.first().type()).toBe('div')
but instead I get [Function: ComponentName]
Here is my code:
ComponentFile.js
function ComponentName(props) {
if (props.editable) return <input />
else return <div />
}
ComponentFile.test.js
it('should render a div if not editable', () => {
const wrapper = mount(<ComponentName editable={false} />
expect(wrapper.first().type()).toBe('div')
})
The above test fails because it gets [Function: ComponentName]
I have also tried wrapper.getElement().type but it is also a funcion.
I was able to temporarily get the results I want by doing:
expect(wrapper.html().substr(0, 4)).toBe('<div')
but I was hoping there was a more idiomatic way
EDIT:
Solved. Turns out it works if you use shallow instead of mount.
I think you just miss typed there. You should use .to.equal instead of toBe:
expect(wrapper.first().type()).toEqual('div')
Reference:
https://airbnb.io/enzyme/docs/api/ShallowWrapper/type.html
P.S.:
This will work only if you use shallow instead of mount, to render your component. Not sure why...
Update:
Matt comments above have a good answer with an example. Posting here for visibility:
https://codesandbox.io/s/function-testing-6sxt5

ReactTable and custom server side data update

Has anybody ever used this awesome react components processing server side data?
The solution given here is excellent if you don't need to manually update the data.
I would need to refresh the data not only when changing page/pageSize/sorting/filtering, but also after some intervalled time, to see if data got changed.
Also I have an extension of the table that allows the user to do a full text search on all columns so I would need to update the data when the user changes the content of the custom search box too.
I had the same problem as yours and I started looking for asynchronous tests with ReactJs and I found this article that was very useful. The key part was to use "update" method on the Enzyme component, like below:
const items = ['die Straße', 'die Adresse', 'die Nationalität'];
jest.useFakeTimers();
describe('<DelayedList />', () => {
test('it renders the items with delay', () => {
const component = shallow(
<DelayedList items={items} />
);
jest.runAllTimers();
component.update(); // <--- force re-render of the component
expect(component.state().currentIndex).toEqual(items.length);
expect(component).toMatchSnapshot();
});
For more information, see this medium article.

Testing scrollintoview Jest

I have a simple function:
scrollToSecondPart() {
this.nextPartRef.current.scrollIntoView({ behavior: "smooth" });
}
and I would like to test it using Jest. When I call my function I have this error:
TypeError: Cannot read property 'scrollIntoView' of null
The code works great in the application but not in the unit test.
Here is the unit test:
it("should scroll to the second block", () => {
const scrollToSecondPart = jest.spyOn(LandingPage.prototype, 'scrollToSecondPart');
const wrapper = shallow(<LandingPage />);
const instance = wrapper.instance();
instance.scrollToSecondPart();
expect(scrollToSecondPart).toHaveBeenCalled();
});
I guess the problem is that the unit test can't access to this.nextPartRef but I don't know how I should mock this element.
By the way, I'm using "Refs" has described in https://reactjs.org/docs/refs-and-the-dom.html (I'm using React.createRef()).
Thank you!
So I stumbled on this question because I thought it was about how to test Element.scrollIntoView(), which can be done by mocking it with jest as follows:
let scrollIntoViewMock = jest.fn();
window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
<execute application code that triggers scrollIntoView>
expect(scrollIntoViewMock).toBeCalled();
However, that does not seem to be your goal. In your test you are calling scrollToSecondPart() in your test and then expect(scrollToSecondPart).toHaveBeenCalled() which is essentially testing that scrollToSecondPart is a function of LandingPage or am I missing something?
for me i had to mock the scrollIntoView for elements like this:
const scrollIntoViewMock = jest.fn();
Element.prototype.scrollIntoView = scrollIntoViewMock()
as found here:
https://github.com/jsdom/jsdom/issues/1695#issuecomment-449931788

Resources