pcvnes
pcvnes

Reputation: 977

Testing css-modules styles in testing library

A React Context provider imports style classes from a module.scss file. When executing this component a selected style class is loaded and passed as the className to child components.

import React, {createContext, ReactChild, useState} from 'react'
import themes from './ThemeProvider.module.scss'

type ThemeContext = {
  activeTheme: string
  changeTheme: (theme: string) => void
}

const validThemes = Object.keys(themes)
console.log(themes)
const defaultTheme = 'light'

const defaultThemeContext: ThemeContext = {
  activeTheme: defaultTheme,
  changeTheme: () => undefined
}

type ThemeProviderProps = {
  children: ReactChild
}

export const ThemeContext = createContext<ThemeContext>(defaultThemeContext)

export const ThemeProvider = ({children}: ThemeProviderProps): JSX.Element => {
  const [theme, setTheme] = useState(defaultThemeContext.activeTheme)

  const changeTheme = (themeName: string): void => {
    console.log('changing theme')
    console.log(themes[themeName])
    if (validThemes.includes(themeName)) {
      setTheme(themeName)
    } else {
      setTheme(defaultTheme)
    }
  }

  const themeContext = {
    activeTheme: theme,
    changeTheme: changeTheme
  }

  return (
    <ThemeContext.Provider value={themeContext}>
      <div className={themes[theme]} data-testid='theme-provider'>
        {children}
      </div>
    </ThemeContext.Provider>
  )
}

If changeTheme is invoked the following output is logged to the console.

{
    "dark": "x05Ym2JQjxImZ4atKmpS",
    "light": "hOdKKkIeHEdunEiPWlEL"
}

changing Theme
x05Ym2JQjxImZ4atKmpS

When trying to test this component in using testing-library using a custom renderer

/**
 * Custom renderer
 */
const ThemeConsumer = (): JSX.Element => {
  const {changeTheme, activeTheme} = useContext(ThemeContext)
  return (
    <div>
      <button
        data-testid='theme-consumer-btn'
        onClick={() => {
          console.log('CLICK!')
          changeTheme('dark')
        }}
      />
      <p>Theme:{activeTheme} </p>
    </div>
  )
}

And the following test

  test('changes theme', async () => {
    render(
      <ThemeProvider>
        <ThemeConsumer />
      </ThemeProvider>
    )

    const consumerBtn = (await screen.findByTestId(
      'theme-consumer-btn'
    )) as HTMLButtonElement

    await userEvent.click(consumerBtn)
    await waitFor(() => screen.getByText('Theme:dark'))
    screen.debug(undefined, Infinity)
  })

On execution of the test the CLICK! message from the custom renderer is logged as the same console.log statements when executed in a browser. Only, where the CSS style classes were expected i get an empty object.

{}

changing Theme
dark

Used Jest config is

/**
 * @jest-environment jsdom
 */

module.exports = {
  collectCoverageFrom: ['src/**/*.ts', 'src/**/*.tsx', '!src/**/*.test.*'],
  moduleNameMapper: {
    '\\.(scss)$': '<rootDir>/node_modules/jest-css-modules'
  },
  testEnvironment: 'jsdom',
  globals: {
    PRODUCTION: true
  },
  testMatch: ['**/?(*.)test.[tj]sx'],
  testURL: 'https://www.mijnmarkt.nl',
  coverageThreshold: {
    global: {
      lines: 100,
      statements: 100
    }
  }
}

Is there a configuration, module or any other change to be able to parse css-modules in Jest as when hosting it locally through a Webpack serve?

Upvotes: 2

Views: 5786

Answers (1)

pcvnes
pcvnes

Reputation: 977

replacing the jest-css-modules moduleNameMapper with the following two jest transform configurations fixed the issue.

yarn add --dev babel-jest jest-css-modules-transform

and jest config

  transform: {
    '^.+\\.[jt]sx?$': 'babel-jest',
    '.+\\.(css|styl|less|sass|scss)$': 'jest-css-modules-transform'
  },

Upvotes: 3

Related Questions