Back to Repositories

Testing DOM Ancestor Detection Features in Capybara

This test suite validates the ancestor element detection functionality in Capybara, focusing on the #have_ancestor and #have_no_ancestor matchers. It ensures proper DOM traversal and relationship verification between elements in web pages during testing.

Test Coverage Overview

The test suite comprehensively covers ancestor element validation in Capybara with multiple scenarios:
  • Direct ancestor detection using CSS selectors
  • Multi-level ancestor validation
  • Multiple matching ancestors handling
  • Negative ancestor assertions
  • Count-based ancestor validations

Implementation Analysis

The implementation uses RSpec’s expectation syntax with Capybara’s custom matchers. The tests leverage CSS selectors for element location and employ both positive and negative assertions through have_ancestor and have_no_ancestor matchers. The implementation includes count validation methods like .once and .exactly(n).times.

Technical Details

Tools and configurations include:
  • RSpec testing framework
  • Capybara’s SpecHelper for test setup
  • CSS selector-based element location
  • Before hooks for test state initialization
  • Custom expectation matchers for ancestor validation

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Isolated test cases with clear assertions
  • Consistent setup using before blocks
  • Both positive and negative test scenarios
  • Edge case handling for multiple matches
  • Explicit count validation tests

teamcapybara/capybara

lib/capybara/spec/session/has_ancestor_spec.rb

            
# frozen_string_literal: true

Capybara::SpecHelper.spec '#have_ancestor' do
  before do
    @session.visit('/with_html')
  end

  it 'should assert an ancestor using the given locator' do
    el = @session.find(:css, '#ancestor1')
    expect(el).to have_ancestor(:css, '#ancestor2')
  end

  it 'should assert an ancestor even if not parent' do
    el = @session.find(:css, '#child')
    expect(el).to have_ancestor(:css, '#ancestor3')
  end

  it 'should not raise an error if there are multiple matches' do
    el = @session.find(:css, '#child')
    expect(el).to have_ancestor(:css, 'div')
  end

  it 'should allow counts to be specified' do
    el = @session.find(:css, '#child')

    expect do
      expect(el).to have_ancestor(:css, 'div').once
    end.to raise_error(RSpec::Expectations::ExpectationNotMetError)

    expect(el).to have_ancestor(:css, 'div').exactly(3).times
  end
end

Capybara::SpecHelper.spec '#have_no_ancestor' do
  before do
    @session.visit('/with_html')
  end

  it 'should assert no matching ancestor' do
    el = @session.find(:css, '#ancestor1')
    expect(el).to have_no_ancestor(:css, '#child')
    expect(el).to have_no_ancestor(:css, '#ancestor1_sibling')
    expect(el).not_to have_ancestor(:css, '#child')
    expect(el).not_to have_ancestor(:css, '#ancestor1_sibling')
  end
end