Gowtham Manthena
Gowtham Manthena

Reputation: 279

How to write unit test cases for different screen sizes?

I have two buttons to display based on the screen size(for medium screen one button and another button for other screens). I'm using Material UI's MediaQuery and theme.breakpoints to define the screen size.

This is my UI code and I'm using Typescript in React.

import React from "react";
import Button from "@material-ui/core/Button";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { useTheme } from "@material-ui/core/styles";

export default function SimpleCard() {
  const theme = useTheme();
  const isMd = useMediaQuery(theme.breakpoints.only("md"));

  return (
    <div>
      {isMd ? (
        <Button
          data-testid="mediumScreenButton"
          onClick={() => console.log("medium")}
        >
          medium screen
        </Button>
      ) : (
        <Button
          data-testid="otherScreenButton"
          onClick={() => console.log("other")}
        >
          Other screen
        </Button>
      )}
    </div>
  );
}

This is my test code

import React from 'react';
import { render, fireEvent, screen, waitFor, cleanup } from '@testing-library/react';
import Demo from './Demo'

beforeEach(() =>
{
  window.scrollTo = jest.fn();
  window.HTMLDivElement.prototype.scrollIntoView = jest.fn();

  // window.matchMedia('(max-width: 999px)');

});

describe('To test cond. for screen sizes', () =>
{
  afterEach(cleanup);

  it('Medium screen', async () =>
  {
    const { container } = render(<Demo />)

    const mediumScreenButton = screen.getByTestId('mediumScreenButton');
    fireEvent.click(mediumScreenButton);

    expect(container).toMatchSnapshot();

  });

});

I don't understand how to set the screen size to medium in my test file so that my test case will pass. But right now, the test case is failing as "unable to find element with data testid mediumScreenButton ". Can someone help me in solving this.

Thank you.

Upvotes: 4

Views: 13761

Answers (2)

Gowtham Manthena
Gowtham Manthena

Reputation: 279

I'm using Typescript in my project. The below code is worked for me. Thanks to @Luis for the hint.

install css-mediaquery

npm install css-mediaquery

add this function in your test file

function createMatchMedia(width) {
  Object.defineProperty(window, 'matchMedia', {
    writable: true,
    value: jest.fn().mockImplementation(query => ({
      matches: mediaQuery.match(query, { width }),
      media: query,
      onchange: null,
      addListener: jest.fn(), // deprecated
      removeListener: jest.fn(), // deprecated
      addEventListener: jest.fn(),
      removeEventListener: jest.fn(),
      dispatchEvent: jest.fn(),
    })),
  });
};

Finally place this in your test case (it)

createMatchMedia('999px');

Overall test code would be

import React from 'react';
import { render, fireEvent, screen, cleanup } from '@testing-library/react';
import Demo from './Demo';
import mediaQuery from 'css-mediaquery'; // install this package

function createMatchMedia(width) {
  Object.defineProperty(window, 'matchMedia', {
    writable: true,
    value: jest.fn().mockImplementation(query => ({
      matches: mediaQuery.match(query, { width }),
      media: query,
      onchange: null,
      addListener: jest.fn(), // deprecated
      removeListener: jest.fn(), // deprecated
      addEventListener: jest.fn(),
      removeEventListener: jest.fn(),
      dispatchEvent: jest.fn(),
    })),
  });
};

beforeEach(() => {
  window.scrollTo = jest.fn();
  window.HTMLDivElement.prototype.scrollIntoView = jest.fn();
});

describe('To test cond. for screen sizes', () => {
  afterEach(cleanup);

  it('Medium screen', async () => {
    createMatchMedia('999px');
    const { container } = render(<Demo />);

    const mediumScreenButton = screen.getByTestId('mediumScreenButton');
    fireEvent.click(mediumScreenButton);

    expect(container).toMatchSnapshot();

  });
});

Upvotes: 4

Luis Paulo Pinto
Luis Paulo Pinto

Reputation: 6036

Mui docs have some example on how do to it.

You need an implementation of matchMedia in your test environment.

For instance, jsdom doesn't support it yet. You should polyfill it. Using css-mediaquery to emulate it is recommended.

So first you need to install css-mediaquery:

npm install css-mediaquery
// OR
yarn add css-mediaquery

And your test could be:

import mediaQuery from "css-mediaquery";
import Demo from './Demo'

const createMatchMedia = (width) => (query) => ({
  matches: mediaQuery.match(query, { width }),
  addListener: () => {},
  removeListener: () => {}
});

describe("Media Test", () => {
  it("Desktop Test", async () => {
    window.matchMedia = createMatchMedia(1000);

    render(<Demo />);

    const buttonEl = screen.getByRole("button");

    expect(buttonEl).toHaveTextContent("medium screen");
  });

  it("Mobile Test", async () => {
    window.matchMedia = createMatchMedia(200);

    render(<Demo />);

    const buttonEl = screen.getByRole("button");

    expect(buttonEl).toHaveTextContent("Other screen");
  });
});

* A tip about your code:

Avoid use getByTestId to find elements with testing-library. In their documents has a query priority recommendation, as you can check here. So, in your case you can use getByRole('button')

Upvotes: 7

Related Questions