Using "data-test" in Tests
Tags: testing, ruby, javascript, react
Published: 2019-06-29 08:19:29

---
title: Using "data-test" in Tests
published: true
description: A better approach for selecting elements during testing, than using custom class names.
tags: Testing, Ruby, Javascript, React
canonical_url: https://blog.rstankov.com/using-rel-in-testing/
---

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

```javascript
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](https://github.com/css-modules/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](https://github.com/airbnb/enzyme/) and [chai-enzyme](https://github.com/producthunt/chai-enzyme))_:

```jsx
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:

```jsx
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](https://github.com/jnicklas/capybara) in Ruby land.

```ruby
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
```