jss icon indicating copy to clipboard operation
jss copied to clipboard

[react-jss] Testing components with styles.

Open HenriBeck opened this issue 7 years ago • 12 comments

From @kof on June 5, 2017 20:35

Motivation: when you snapshot components with jest, you can also snapshot css generated by the component. Ideally this should also work with styled-jss. Also we should support testing generated CSS without jest.

See for e.g. https://github.com/styled-components/jest-styled-components/

Copied from original issue: cssinjs/react-jss#93

HenriBeck avatar Aug 03 '18 07:08 HenriBeck

From @kof on June 29, 2017 15:36

Right now one can obtain all sheets by using SheetsRegistryProvider or JssProvider if you are on the next branch/pre release version.

import {SheetsRegistryProvider, SheetsRegistry} from 'react-jss'

it('should match the css snapshot', () => {
  const sheets = new SheetsRegistry()
  render(
    <SheetsRegistryProvider registry={sheets}>
      <Component />
    </SheetsRegistryProvider>
  )
  const snapshot = 'some css'
  expect(sheets.toString()).to.be(snapshot)
})

HenriBeck avatar Aug 03 '18 07:08 HenriBeck

From @kserjey on June 29, 2017 15:40

But what if i use enzyme for testing instead of jest snapshot?

HenriBeck avatar Aug 03 '18 07:08 HenriBeck

From @kof on June 29, 2017 15:41

Thats fine, the example above is not using jest. This issue is basically about simplifying it in the future. It is already possible now.

HenriBeck avatar Aug 03 '18 07:08 HenriBeck

From @kserjey on July 4, 2017 12:1

I often use selectors to find component in Enzyme testing and for that i map classes to new object with next function:

ruleName => sheet.getRule(ruleName).selectorText

Is there more reliable method?

HenriBeck avatar Aug 03 '18 07:08 HenriBeck

From @kof on July 4, 2017 13:5

  1. for testing you may want to pass your simplified selector generator so that you can use a simpler selector without counters and hardcode the result
  2. you can use a different attribute for testing

HenriBeck avatar Aug 03 '18 07:08 HenriBeck

From @kof on July 4, 2017 13:18

Also what about classes object?

HenriBeck avatar Aug 03 '18 07:08 HenriBeck

any news on this ? i can not get the way that @kof gives as an example to work..

jb-san avatar Dec 11 '18 18:12 jb-san

Got it working with a helper

import React from 'react';
import { JssProvider, SheetsRegistry, ThemeProvider } from 'react-jss';
import { mount } from 'enzyme';
import mockTheme from './defaultTheme';

/**
 *  JSS helper mount
 * Wrapps the passed in component in Themeprovider and captures the styles generated
 * @param {React component} Component
 * @returns {Array} First item in array is the stylesheet generated by jss, the second is the rendered component for further expects
 */
export const themeMount = Component => {
    const sheets = new SheetsRegistry();
    const ClonedComponent = React.cloneElement(Component, { _renderid: 'rendered-component' });

    const tree = mount(
        <JssProvider registry={sheets}>
            <ThemeProvider theme={{ theme: mockTheme }}>{ClonedComponent}</ThemeProvider>
        </JssProvider>
    );
    return [sheets.toString(), tree.findWhere(node => node.props()._renderid === 'rendered-component')];
};

then in the tests

import React from 'react';

import Button from 'components/Button';
describe('Button', () => {
    test('should render a default button', () => {
        const [styleSheets, component] = themeMount(<Button>Test</Button>);
        expect(styleSheets.toString()).toMatchSnapshot();
        expect(component).toMatchSnapshot();
    });
});

jb-san avatar Dec 14 '18 10:12 jb-san

Thanks for the code @jb-san, we've run into issues where the order of the attributes was not guaranteed with that approach thus the snapshots would fail at random. We're now transitioning to making visual snapshots with storybook, I feel that this might be a better path going forward.

If you're interested hit me up!

LaurensBosscher avatar Dec 14 '18 10:12 LaurensBosscher

Another solution could be to render the generated styles next to the component so they would be included in the component snapshot and someone wouldn't need to wrap every component around a JssProvider and collect the sheets manually.

HenriBeck avatar Mar 16 '19 22:03 HenriBeck

What if, when passing a custom theming context to the react-jss HOC, it is able to use the React Context's default value?

// themes.js

const defaultTheme = {
  color: 'red'
}

const ThemeContext = React.createContext(defaultTheme)

export const theming = createTheming(ThemeContext)

// component.jsx
import {theming} from './themes

/* ... */

export default withStyles(styles, {theming})(Component)

Then unit tests which depend on a ThemeProvider can just fallback on the default theme.

EDIT - though on a closer look at the source code, maybe this should be handled by the theming library.

kilrain avatar Jun 06 '19 19:06 kilrain

@kilrain This should already be the case.

For the default theming context this is sadly not possible.

HenriBeck avatar Jun 07 '19 07:06 HenriBeck