DEV Community

Radoslav Stankov
Radoslav Stankov

Posted on • Edited on • Originally published at blog.rstankov.com

5 1

Using "data-test" in Tests

When testing HTML components, I often see people using class names as selectors. For example:

element.find('.description button.expand-button').simulate('click');

While this seems convenient at first, there are some drawbacks. HTML structure and css classes tend to change due to design changes. Which will cause you re-write tests quite often. Also, if you are using css-modules you can't rely on class names.

Because of that, for quite some time now, I have started marking elements with data-test attribute.

React example (using enzyme and chai-enzyme):

describe(Description.name, () => {
  it('cut off text based on `cutoffLength`', () => {
    const el = shallow(<Description text="test" cutoffLength={1} />);

    expect(el).to.have.text('t...');
    expect(el).not.to.have.text('test');
  });

  it('hides expand button when text is short', () => {
    const el = shallow(<Description text="test" cutoffLength={10} />);
    expect(el).not.to.have.descendants('[data-text="expand-button"]');
  });

  it('shows expand button when text is long', () => {
    const el = shallow(<Description text="test" cutoffLength={1} />);
    expect(el).to.have.descendants('[data-test="expand-button"]');
  });

  it('clicking expand button reveals the whole text', () => {
    const el = shallow(<Description text="test" cutoffLength={1} />);

    el.find('[data-test="expand-button"]').simulate('click');

    expect(el).not.to.have.descendants('[data-test="expand-button"]');
    expect(el).to.have.text('test');
  });
});

The component code:

import React from 'react';
import styles from "./style.css";

export default Description extends React.Component {
  state = { expanded: false };

  render() {
    const { text, cutoffLength } = this.props;

    if (this.state.expanded || text.length < cutoffLength) {
      return (
        <div className={styles.description}>
          {this.props.text}
        </div>
      );
    }

    return (
      <div className={styles.description}>
        {`${ text.substr(0, cutoffLength) }...`}
        <button 
          data-test="expand-button" 
          className={styles.expand} 
          onClick={this.expand}>show more</button>
      </div>
    );
  }

  expand = () => {
    this.setState({ expanded: true });
  };
}

I'm also using data-test attributes for testing with Capybara in Ruby land.

describe 'Product page' do
  it 'has product description rev' do
    product = create :post, :with_long_description

    visit product_path(product)

    expect(page).not_to have_text product.description

    # This can be extracted into `find_test_attr` or `click_test_attr`
    find(:css, '[data-test="expand"]').click

    expect(page).to have_text product.description

    # This can be extracted into `have_test_arr`
    expect(page).not_to have_css('[data-test="expand"]')
  end
end

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (2)

Collapse
 
mikerogers0 profile image
Mike Rogers ✈️

I done this before, and it's really good way of targeting elements. That said, instead of data-test I just copied bootstraps approach to attributes (e.g. data-toggle="dropdown" & data-tatget="#something"), which seemed a bit more semantic.

Collapse
 
rstankov profile image
Radoslav Stankov

I like the bootstrap technique too. Used it in couple of times in the past. Don't do it recently, since most of browser work, I do is React now days.

What I like about data-test is the intent it reveals. This is for easier test targeting. Not implementation detail.

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay