67

I am trying to test a style attribute for a React component. What is the best way to get style params in the test?

At this moment, my best option is to test if the HTML includes the string, but I think there is a better option.

Case:

it('Should render large image when desktop', () => {
    const dummyUrl = 'http://dummyUrl';
    const wrapper = shallow(
      <MockedStore
        initialState={{
          app: fromJS({ browser: { desktop: true } }),
        }}
      >
        <LandingHero bigImage={dummyUrl} />
      </MockedStore>
    );
  });

The Component to test is:

// @flow
import React, { Component } from 'react';
import gc from 'styles/core.scss';
import $ from 'jquery';
import DownloadButton from 'components/DownloadButton';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import DownArrow from 'components/DownArrow';
import { connect } from 'react-redux';
import type { Map } from 'immutable';
import c from './styles.scss';

@withStyles([gc, c])
@connect(({ app }) => ({ app }))
class LandingHero extends Component {
  componentDidMount() {
    if ($(window).height() > 0) { // Necesary for webpack dev server
      $(this.hero).css('height', $(window).height() - 46);
    }
  }

  hero: HTMLElement;

  props: {
    app: Map<string, any>,
    copy: string,
    secondaryText: string,
    thirdText: string,
    bigImage?: string,
    smallImage: string,
  }

  render() {
    const { copy, secondaryText, thirdText } = this.props;
    const browser = this.props.app.has('browser') ? this.props.app.get('browser') : {};
    const backgroundImage = browser.desktop ? this.props.bigImage : this.props.smallImage;

    return (
      <div
        className={`${c.hero} ${gc.textCenter}` +
        ` ${gc.alignMiddle} ${gc.alignCenter} ${gc.row} ${gc.expanded}`}
        ref={(hero) => { this.hero = hero; }}
        style={{
          margin: 0,
          position: 'relative',
          background: `linear-gradient(to bottom, rgba($ixdarkprimary, .3), rgba($ixdarkprimary, .3)), url(${backgroundImage || ''})`,
        }}
      >
        <div className={`${gc.row} ${gc.alignCenter} ${gc.alignMiddle} ${gc.column} ${gc.medium10}`}>
          <div className={`${gc.textCenter}`}>
            <div
              className={`${gc.white} ${c.mainText} ${c.copy}`}
            >
              { copy }
            </div>
            <div className={`${gc.small6} ${gc.smallOffset3} ${gc.medium4} ${gc.mediumOffset4}`} style={{ marginBottom: 45 }}>
              <DownloadButton />
            </div>
            <div className={`${gc.white} ${gc.fontBold} ${gc.font24}`}>{secondaryText}</div>
            <p className={`${gc.white} ${gc.font20}`}>{thirdText}</p>
          </div>
          <DownArrow goTo="#content" />
        </div>
      </div>
    );
  }
}

export default LandingHero;
jacefarm
  • 6,747
  • 6
  • 36
  • 46
  • hey jacefarm what is the configuration you use for jest in order to use sass(scss)? I mean I have the following ` "moduleNameMapper": { "\\.(scss|css)$": "/src/sassMockForJest.js" },` but I got undefined errors when using properties for example if I used the same component like you I would see `Cannot read property 'textCenter' of undefined` because the `${gc.textCenter}` – Heriberto Magaña Jul 19 '17 at 18:12
  • Hey, you can get rid of your mock store by exporting your class as well. You get: `import ConnLandingHero, { LandingHero } from "../LandingHero";` It's saved our team a lot of time. – taystack Aug 06 '19 at 16:35

12 Answers12

60

You can use this method. It returns ReactElement.

let containerStyle = container.get(0).style;
expect(containerStyle).to.have.property('opacity', '1');
visortelle
  • 1,013
  • 1
  • 10
  • 15
34

Slightly elaborating on others' answers:

expect(component.find('#item-id').prop('style')).toHaveProperty('backgroundSize', '100%');

This will check the style prop of #item-id. This prop is an object and here toHaveProperty matcher checks if this object contains backgroundSize property and if its value is 100%.

This way other style properties are ignored.

Neurotransmitter
  • 6,289
  • 2
  • 51
  • 38
32
const elem = wrapper.find(Element);
expect(getComputedStyle(elem.getDOMNode()).getPropertyValue('opacity')).toBe('0.4');
Mahdi Abdi
  • 682
  • 6
  • 27
  • 7
    this is the correct answer if you want to assert on external CSS style applied to the particular element — that's opposed to inline CSS styles passed as props etc. – revelt Apr 03 '20 at 13:21
  • 3
    Works perfectly. Thank you so much. This should be the accepted answer! – Simon Long Jun 17 '20 at 14:26
  • 1
    great!, i keep thinking this – nick Mar 02 '22 at 02:17
  • 1
    The reason this should be the accepted answer, is because it is agnostic of implementation, using other answers, if you decide to move towards external style sheets, you will break all your unit tests, this way, you won't – Max Carroll Aug 23 '22 at 10:48
21

expect(component.find('#item-id').prop('style')).to.deep.equal({display: 'none'})

cyberjar09
  • 770
  • 1
  • 7
  • 18
10

If you use jest-styled-components then you can use toHaveStyleRule as follows:

expect(component.find('#item-id')).toHaveStyleRule('opacity', 'red');

DenisH
  • 859
  • 8
  • 12
3

Have a look at chaiEnzyme, which provides a handy little assertion you can use with chai to check whether a wrapper has a particular style (https://github.com/producthunt/chai-enzyme#stylekey-val), should help make your tests look a little cleaner.

Ben Hare
  • 4,365
  • 5
  • 27
  • 44
3

For me, it was a mash-up for a few answers. For those also using Jest / Enzyme:

let containerStyle = wrapper.find('#item-id').get(0).props.style;

expect(containerStyle).toHaveProperty('opacity', '1'); // ('propert', 'value')

Note:

  • find returns a ShallowWrapper so we need to .get(0) the first matching element
  • .props is an attribute not a function in this instance
  • jest uses toHaveProperty not to.have.property
Kitson
  • 1,153
  • 9
  • 22
1

I would like to add that the following props() method can also be used. https://airbnb.io/enzyme/docs/api/ShallowWrapper/props.html

let containerStyleOpacity = container.get(0).props().style.opacity; expect(containerStyleOpacity).to.be.equal('1');

Sark Peha
  • 451
  • 4
  • 5
1

This works for me also.

expect(containerStyle.getDOMNode()).toHaveStyle('opacity : 0');

I had to do this to replace

expect(getComputedStyle(checkbox.getDOMNode()).getPropertyValue('opacity')).toBe('0');

which worked when I ran the test locally in my Intellij IDE. However when I ran it using npm t it failed. Must be something to do with how getComputedStyle was being computed in the different scenarios.

toHaveStyle worked in both

Simon Long
  • 1,310
  • 4
  • 20
  • 39
1

We do like this using import { shallow } from "enzyme";

const component = shallow();

expect(component.find("[id="id_of_element"]")).toHaveStyleRule("border", "2px solid red");

CodeByAk
  • 139
  • 5
0

I don't know if Enzyme has changed with recent versions but I needed parentheses after props in order to get the top answer to work.

containerStyle = container.get(0).props().style;

feraleyebrows
  • 155
  • 1
  • 5
0
const node = wrapper.find(Element);
//Checking border property
expect(getComputedStyle(node.getDOMNode()).getPropertyValue('border')).toBe('2px solid red');
Shankar Ganesh Jayaraman
  • 1,401
  • 1
  • 16
  • 22
Dilip
  • 1
  • 2
  • 1
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Dec 22 '20 at 16:08
  • **identical** to [already existing](https://stackoverflow.com/a/54788930/104380) older answer in this page – vsync Nov 26 '21 at 22:00