NotYanka
NotYanka

Reputation: 547

How to test React components inside react-responsive tags

Inside a <MyComponent> component I am using react-responsive <MediaQuery> components to distinguish between rendering mobile and desktop content.

export class MyComponent extends React.Component {

  //...

    render() {
      <MediaQuery query="(max-width: 600)">
        <div className="inside-mobile">mobile view</div>
      </MediaQuery>
    }
}

I want to test the HTML inside <MyComponent>'s render() using enzyme, but can't seem to dive into the child elements of <MediaQuery>:

it('should dive into <MediaQuery>', () => {
    const wrapper = mount(<Provider store={mockedStore}><MyComponent/></Provider>)
    const actual = wrapper.getDOMNode().querySelectorAll(".inside-mobile")       
    expect(actual).to.have.length(1)
}

A console.log(wrapper.debug())shows that nothing inside <MediaQuery> is being rendered, though. I'm guessing in a test (with no actual browser) window.width is not set which leads to the <MediaQuery> component not rendering anything.

What I want to do:

I want to be able to test <MyComponent>'s content using enzyme with react-responsive (or something similar such as react-media) to deal with mobile vs desktop viewports.

Things I've tried:

console.log(wrapper.debug()) shows:

<MyComponent content={{...}}>
    <Media query="(min-width: 600px)" defaultMatches={true} />
</MyComponent>

Upvotes: 2

Views: 2279

Answers (1)

NotYanka
NotYanka

Reputation: 547

I found a working solution, using react-media instead of react-responsive, by mocking window.matchMedia so that matches is set to true during the test:

Create specific media components for different viewports:

const Mobile = ({ children, content }) => <Media query="(max-width: 600px)" children={children}>{matches => matches ? content : "" }</Media>;
const Desktop = ...

Use specific media component:

<MyComponent>
    <Mobile content={
        <div className="mobile">I'm mobile</div>
    }/>
    <Desktop content={...}/>
</MyComponent>

Test content per viewport:

const createMockMediaMatcher = matches => () => ({
    matches,
    addListener: () => {},
    removeListener: () => {}
});

describe('MyComponent', () => {
    beforeEach(() => {
        window.matchMedia = createMockMediaMatcher(true);
    });

    it('should display the correct text on mobile', () => {

        const wrapper = shallow(<MyComponent/>);
        const mobileView = wrapper.find(Mobile).shallow().dive();
        const actual = mobileView.find(".mobile").text();

        expect(actual).to.equal("I'm mobile");
    });
});

Upvotes: 2

Related Questions