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
    
Top comments (2)
I done this before, and it's really good way of targeting elements. That said, instead of
data-testI just copied bootstraps approach to attributes (e.g.data-toggle="dropdown"&data-tatget="#something"), which seemed a bit more semantic.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-testis the intent it reveals. This is for easier test targeting. Not implementation detail.