TDD with Enzyme shallow and mount? - reactjs

When I render a component using shallow or mount, the component is rendered in memory and is not attached to DOM.
This means that, while I run my tests, I don't actually see any output in the browser.
How am I supposed to do Test Driven Development if I can't see if the component I'm developing looks as it should? (css style, sizes etc)

If you want your component to be rendered an mounted une the "browser", than use the render() method of Enzyme. Be sure to have a window available (see jsdom to fake a window). But IMO, you should be able to do all of your test with shallow or mount, the API is nice

How am I supposed to do Test Driven Development if I can't see if the
component I'm developing looks as it should? (css style, sizes etc)
The purpose of Enzyme is not visual regression test, for that you will have to use tools like PhantomJS, related article https://css-tricks.com/visual-regression-testing-with-phantomcss/
You can achieve some kind of styling testing by checking if your component has the right selectors when they are rendered. e.g.
it( 'should add the "selected" class when a click happend to one of the Elements', () => {
const wrapper = mount( <Elements /> );
const option = wrapper.find( 'h5' );
expect( option.hasClass( 'selected' ) ).to.equal( false );
option.simulate( 'click' );
expect( option.hasClass( 'selected' ) ).to.equal( true );
} );

Related

React jest snapshot only returning empty DocumentFragment

I am using React and writing a Modal component like so:
const MyModal: FC<MyModalProps> = memo((props) => {
return (
<Modal isOpen={true} data-client-id={modal-client-id}>
...
</Modal>
);
});
I am trying to test this using testing-library and jest like so:
const { asFragment } = render(<MyModal {...myTestProps} />);
const renderFragment = asFragment();
expect(renderFragment).toMatchSnapshot();
However, when I check the snapshot I only see <DocumentFragment />. I can test whether the modal is there by a getByTestId(modal-client-id) and I can see that the modal is rendering and appearing when I run in Storybook with the exact same props. The snapshot also works and returns the inner components when I remove the surrounding Modal component. Is there a reason why Snapshot would only return the DocumentFragment and not the full snapshot? Would it just imply that within the unit test the component is not rendering?
Testing-Library render appends the passed in component to a parent div. This corresponds with the Container option of the render function. By default Testing-Library creates a div and appends to it. In the case of the modal, the modal is a separate pop up that was not being rendered as a child of the div, which explains why the fragment only rendered as:
<DocumentFragment>
<div />
</DocumentFragment>
To debug this, printing out the rendered screen gave the clue with: screen.debug(). This showed that the modal was being rendered outside of the container div, which is why other queries/gets were able to find components.
Alternatively, we can also override the baseElement option, which defaults to document.body if not specified. In my case because any modal rendered would correctly be rendered on top of a component, I instead did:
const result = render(<MyModal {...myTestProps} />);
const modalComponent = screen.getByTestId('modal-client-id');
expect(modalComponent).toMatchSnapshot();
This avoids messing around with attempting to specify the container or baseElement options since anything rendered will be rendered on top.

How to test a component composed of other components with react-testing-library?

I am completely new to react-testing-library. I just started reading all the various "Getting Started" documentation and blog posts I could find after I had no success testing a component with Enzyme. Most of the examples I could find are pretty simple, like those in the "Introducing the react-testing-library" blog post. I would like to see examples of how to test a component that itself is composed of other components, since Component composition is one of the greatest things about React (in this SO post I will call an example of such ComposedComponent for lack of a better name).
When I wrote tests for a ComposedComponented in Enzyme, I could just assert that the correct props were passed to some ChildComponent and trust that ChildComponent had its own tests and I would not have to be concerned with what ChildComponent actually rendered to the DOM within my tests for ComposedComponent. But with react-testing-library, I am concerned that since "rather than dealing with instances of rendered react components, your tests will work with actual DOM nodes", I will also have to test the behavior of ChildComponent by making assertions about the DOM nodes it renders in response to its relationship to ComposedComponent. That would mean that the higher up I go in the Component hierarchy in a React application, the longer and more exhaustive my tests would become. The gist of my question is this: How can I test the behavior of a component that has other components as children without also testing the behavior of those child components?
I truly hope that I am just suffering from a failure of imagination and somebody can help me figure out how to properly use this library that has gained such a following as a replacement for Enzyme.
What I do when testing components that happen to render other (already tested) components is mock them. For example, I have a component that displays some text, a button, and a modal. The modal itself is already tested so I don't want to test it again.
import React from 'react';
import { render, fireEvent } from '#testing-library/react';
import { ComponentUnderTest } from '.';
// Mock implementation of a sub component of the component being tested
jest.mock('../Modals/ModalComponent', () => {
return {
__esModule: true,
// the "default export"
default: ({ isOpen, onButtonPress }) =>
isOpen && (
// Add a `testid` data attribute so it is easy to target the "modal's" close button
<button data-testid="close" onClick={onButtonPress} type="button" />
),
};
});
describe('Test', () => {
// Whatever tests you need/want
});

enzyme test, context not rendering elements

I am using enzyme to write my tests, before adding a context to my component which is the consumer component in this case, the snapshot rendered is not showing any elements and every time i add a dive() or shallow() I got the same error
how can i access the elements while using context
const wrapper = shallow(
<MyComponent {...initialProps} store={mockStore(initialState)} />,
{context},
);
const contents = wrapper
.dive() // dive in connect
.dive() // dive in withLogss
.dive() // dive in Motion
.find("MyComponent")
.dive(); // dive in Host
expect(contents.context()).toEqual({myBoolean: true});
it("should render properly", () => {
expect(contents).toMatchSnapshot();
});
Result:
<ContextConsumer>
<Component />
</ContextConsumer>
Enzyme prior to v3.10.0 lacked support of React's new Context API.
From the v3.10.0 Changelog:
shallow: Support rendering and dive()ing createContext() providers and consumers (#1966)
Make sure you are using enzyme v3.10.0 or later and enzyme-adapter-react-16 v1.15.1 or later.

How to you test a redux dumb component that renders smart components?

A "dumb" React view can be testing by passing it props before rendering it with enzyme/jsdom. Snapshot testing can then be used to validate the behavior (as in jest).
A smart component composed of a 'dumb view' connected with mapStateToProps/mapDispatchToProps can be tested by:
unit testing mapXxxToProps to check the logic is right
testing the dumb view
and optionnaly:
render the smart component by wrapping it in a Provider
However, this seems to break whenever a dumb view starts to nest other smart containers ; the rendering of the dumb view is not possible simply with props, since some child components down the chain might need a store.
Is there a way around that ?
Am I missing something ?
With enzyme, you can use a shallow render to test the dumb component is rendering the expected smart components, without actually rendering them completely.
Component (Bar is a smart component):
const Foo = () => {
return (
<div>
<Bar />
</div>
)
}
Test:
import { shallow } from 'enzyme';
...
it('should render <Foo /> component', () => {
const wrapper = shallow(<Foo />)
expect(wrapper.contains(<Bar />)).to.be.true
})

React Native Testing - How to TDD and test components beyond snapshots?

I'm really struggling with how to test React Native components beyond using snapshots from jest. Those are great for testing the look of something based on some data passed into a component, but it doesn't seem like there is a way to test events or event handlers, checking if event listeners were setup or disconnected correctly in lifecycle methods, etc...like it feels like I'm either missing something or the tooling is not complete.
Also on a side note snapshot testing feels backwards in terms of TDD since you can only write your tests once you have your application code...any thoughts on this?
With snapshot test you can only check the values in props and styles etc. To check some logic in container i used 'shallow' from enzyme ;)
You can still use snapshots with events for things like: click a button and verify the rendered output after the click:
it('should render Markdown in preview mode', () => {
const wrapper = shallow(
<MarkdownEditor value="*Hello* Jest!" />
);
expect(wrapper).toMatchSnapshot();
wrapper.find('[name="toggle-preview"]').simulate('click');
expect(wrapper).toMatchSnapshot();
});
To test that event handler was called property you can do something like that:
it('should pass a selected value to the onChange handler', () => {
const value = '2';
const onChange = jest.fn();
const wrapper = shallow(
<Select items={ITEMS} onChange={onChange} />
);
expect(wrapper).toMatchSnapshot();
wrapper.find('select').simulate('change', {
target: { value },
});
expect(onChange).toBeCalledWith(value);
});
(Both examples are from my article on testing React components with Jest.)

Resources