Search code examples
reactjsjestjsnext.jsreact-testing-libraryemotion

Testing Library with Emotion 'css'


Hello there I have two question with Next.js, testing-library/react and emotion.

before ask, I'll show you code below

// component
import { css, Theme } from '@emotion/react';

function Foo() {
  return <h1 css={fooCss}>title</h1
}

const fooCss = (theme: Theme) => css`position: absoulte;`;
// test code
it('position absoulte', () => {
  render(<Foo />);
  expect(screen.getByRole('heading')).toHaveStyle('position: absoulte');
});

First Question. warning at jest : Invalid value for prop 'css' on tag... warning

enter image description here

Second Question. test failed with doesn't have style with css prop

enter image description here

How can I dealing with this warning and error ?

I'll post with babelrc, jest.config and setup

// jest.config.js
const nextJest = require('next/jest');

const createJestConfig = nextJest({
  dir: './',
});

const customJestConfig = {
  resetMocks: true,
  moduleDirectories: ['node_modules'],
  testEnvironment: 'jsdom',
  testRegex: '(/__tests__/.*|(\\.|/)(test))\\.[jt]sx?$',
  collectCoverageFrom: ['**/src/**/*.{js,ts,jsx,tsx}'],
  moduleNameMapper: {
    '~/(.*)': '<rootDir>/src/$1',
    '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2|ico)$': 'identity-obj-proxy',
  },
  moduleFileExtensions: ['js', 'jsx', 'json', 'ts', 'tsx'],
  transform: {
    '^.+\\.tsx?$': 'esbuild-jest',
  },
  coverageThreshold: null,
  setupFilesAfterEnv: ['./jest.setup.js'],
};

module.exports = createJestConfig(customJestConfig);
// jest.setup.js
import '@testing-library/jest-dom';

window.matchMedia = query => ({
  matches: false,
  media: query,
  onchange: null,
  addListener: jest.fn(), // deprecated
  removeListener: jest.fn(), // deprecated
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
  dispatchEvent: jest.fn(),
});
// .babelrc.js
module.exports = {
  presets: [
    [
      'next/babel',
      {
        'preset-react': {
          runtime: 'automatic',
          importSource: '@emotion/react',
        },
      },
    ],
  ],
  plugins: ['@emotion/babel-plugin'],
};


Solution

  • First question

    This is a problem related to passing a function (theme) => css`` or (theme) => css({}) into css prop.

    You could solve this with useTheme hook.

    import {css, Theme, useTheme} from '@emotion/react';
    
    function Foo() {
      const theme: Theme = useTheme()
      return (
        <h1 css={css`color: ${theme.colors.primary}`}>
          title
        </h1>
      )
    }
    

    Second question

    You need to use custom matchers from @emotion/jest .

    import {matchers} from '@emotion/jest'
    
    expect.extend(matchers)
    
    it('position absolute', () => {
      render(<Foo />);
      expect(screen.getByRole('heading')).toHaveStyleRule('position', 'absolute');
    });
    

    Note: In order to make this work, don't forget to add the pragma /** @jsxImportSource @emotion/react */ in components using css prop.