Implementing createMatchMedia() for material-ui. I'm using a material ui hidden component to hide buttons while I'm trying to test them

Viewed 828

I'm using React-testing-library getByText to find a button that's hidden by a material ui component called Hidden. Since RTL won't find it, Material ui has an implementation of it here https://material-ui.com/components/use-media-query/#testing. But I can't figure out how to implement it to simply to find a button. The button is located once I remove Hidden, I am just not sure how to use their createMatchMedia() for a query within my test.

The Hidden component hides my button at 959px and down .

import React from "react"
import { render } from '../../../../test/test-utils'
import Collections from "./Collections"
import userEvent from '@testing-library/user-event'
import mediaQuery from 'css-mediaquery'

function createMatchMedia(width: any) {
  return (query: string): any => ({
    matches: mediaQuery.match(query, { width }),
    addListener: () => {},
    removeListener: () => {},
  });
}

type CollectionsProps = React.ComponentProps<typeof Collections>

const baseProps: CollectionsProps = {
  setValue: () => {},
  setSelectedIndex: () => {},
  pageStyle: {},
  pageAnimations: {transition : {}, variants: {}},
  motions: {animate:'', initial: '', exit: ''},
  jumpTo: (jumpingTarget: string | number | Element): void => {}
}

const renderUI = (props: Partial<CollectionsProps>) =>
     render(<Collections {...baseProps} {...props} />, {}) 

describe('When a filter is clicked', () => {

  beforeAll( () => {
    window.matchMedia = createMatchMedia(window.innerWidth)
  })

  let { getByText } = renderUI({})

    test('items shown are only related to the picked Category', () => {
      userEvent.click(getByText(/Team Colors/))
    })  
}) 
1 Answers

RTL is not the problem here. The problem is in jsdom which doesn't have an implementation of matchMedia(). Jest uses jsdom internally and without an existing matchMedia() no media query will match in Material UI's Hidden API.

  1. You may solve this by first installing NPM packages css-mediaquery and @types/css-mediaquery.
  2. Then create a mock for matchMedia like so:
// matchMedia.mock.ts
export const createMatchMedia = (width: number) => (query: string): MediaQueryList => ({
  matches: mediaQuery.match(query, { width }),
  media: query,
  onchange: null,
  addListener: () => jest.fn(),
  removeListener: () => jest.fn(),
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
  dispatchEvent: jest.fn()
});

window.matchMedia = createMatchMedia(window.innerWidth);

export default {};
  1. Import the mock file above in setupTest.ts (your Jest test setup file) like so:
// setupTests.ts
import './__mocks__/matchMedia.mock';
...
  1. Write your test as you normally would. No need to use the beforeAll() to create a new window.matchMedia. The mock file takes care of that for you.
Related