diff --git a/History.md b/History.md index 282d7174f..7975c8496 100644 --- a/History.md +++ b/History.md @@ -5,6 +5,8 @@ Release date: unreleased * Support for multiple expression types in Selector definitions * Reduced wirecalls for common actions in Selenium driver +* Syntactic sugar `#once`, `#twice`, `#thrice`, `#excatly`, `#at_least`, `#at_most` to + `have_selector`, `have_css`, `have_xpath`, and `have_text` RSpec matchers ### Fixed diff --git a/lib/capybara/rspec/matchers/count_sugar.rb b/lib/capybara/rspec/matchers/count_sugar.rb new file mode 100644 index 000000000..cba67f2d9 --- /dev/null +++ b/lib/capybara/rspec/matchers/count_sugar.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Capybara + module RSpecMatchers + module CountSugar + def once; exactly(1); end + def twice; exactly(2); end + def thrice; exactly(3); end + + def exactly(number) + options[:count] = number + self + end + + def at_most(number) + options[:maximum] = number + self + end + + def at_least(number) + options[:minimum] = number + self + end + + def times + self + end + + private + + def options + (@args.last.is_a?(Hash) ? @args : @args.push({})).last + end + end + end +end diff --git a/lib/capybara/rspec/matchers/have_selector.rb b/lib/capybara/rspec/matchers/have_selector.rb index 2f5585ae6..413768217 100644 --- a/lib/capybara/rspec/matchers/have_selector.rb +++ b/lib/capybara/rspec/matchers/have_selector.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true require 'capybara/rspec/matchers/base' +require 'capybara/rspec/matchers/count_sugar' module Capybara module RSpecMatchers module Matchers class HaveSelector < WrappedElementMatcher + include CountSugar + def element_matches?(el) el.assert_selector(*@args, &@filter_block) end diff --git a/lib/capybara/rspec/matchers/have_text.rb b/lib/capybara/rspec/matchers/have_text.rb index dd1ac3e95..b5dc4ff6e 100644 --- a/lib/capybara/rspec/matchers/have_text.rb +++ b/lib/capybara/rspec/matchers/have_text.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true require 'capybara/rspec/matchers/base' +require 'capybara/rspec/matchers/count_sugar' module Capybara module RSpecMatchers module Matchers class HaveText < WrappedElementMatcher + include CountSugar + def element_matches?(el) el.assert_text(*@args) end diff --git a/lib/capybara/spec/session/has_css_spec.rb b/lib/capybara/spec/session/has_css_spec.rb index 865e58d06..5e8e82fef 100644 --- a/lib/capybara/spec/session/has_css_spec.rb +++ b/lib/capybara/spec/session/has_css_spec.rb @@ -146,7 +146,9 @@ context 'with count' do it 'should be true if the content occurs the given number of times' do expect(@session).to have_css('p', count: 3) + expect(@session).to have_css('p').exactly(3).times expect(@session).to have_css('p a#foo', count: 1) + expect(@session).to have_css('p a#foo').once expect(@session).to have_css('p a.doesnotexist', count: 0) expect(@session).to have_css('li', class: /guitar|drummer/, count: 4) expect(@session).to have_css('li', id: /john|paul/, class: /guitar|drummer/, count: 2) @@ -161,6 +163,7 @@ it 'should be false if the content occurs a different number of times than the given' do expect(@session).not_to have_css('p', count: 6) + expect(@session).not_to have_css('p').exactly(5).times expect(@session).not_to have_css('p a#foo', count: 2) expect(@session).not_to have_css('p a.doesnotexist', count: 1) end @@ -175,6 +178,7 @@ it 'should be true when content occurs same or fewer times than given' do expect(@session).to have_css('h2.head', maximum: 5) # edge case expect(@session).to have_css('h2', maximum: 10) + expect(@session).to have_css('h2').at_most(10).times expect(@session).to have_css('p a.doesnotexist', maximum: 1) expect(@session).to have_css('p a.doesnotexist', maximum: 0) end @@ -182,6 +186,7 @@ it 'should be false when content occurs more times than given' do expect(@session).not_to have_css('h2.head', maximum: 4) # edge case expect(@session).not_to have_css('h2', maximum: 3) + expect(@session).not_to have_css('h2').at_most(3).times expect(@session).not_to have_css('p', maximum: 1) end @@ -195,12 +200,14 @@ it 'should be true when content occurs same or more times than given' do expect(@session).to have_css('h2.head', minimum: 5) # edge case expect(@session).to have_css('h2', minimum: 3) + expect(@session).to have_css('h2').at_least(2).times expect(@session).to have_css('p a.doesnotexist', minimum: 0) end it 'should be false when content occurs fewer times than given' do expect(@session).not_to have_css('h2.head', minimum: 6) # edge case expect(@session).not_to have_css('h2', minimum: 8) + expect(@session).not_to have_css('h2').at_least(8).times expect(@session).not_to have_css('p', minimum: 10) expect(@session).not_to have_css('p a.doesnotexist', minimum: 1) end diff --git a/lib/capybara/spec/session/has_text_spec.rb b/lib/capybara/spec/session/has_text_spec.rb index fadb82c20..cd5370818 100644 --- a/lib/capybara/spec/session/has_text_spec.rb +++ b/lib/capybara/spec/session/has_text_spec.rb @@ -166,12 +166,14 @@ it 'should be true if the text occurs the given number of times' do @session.visit('/with_count') expect(@session).to have_text('count', count: 2) + expect(@session).to have_text('count').exactly(2).times end it 'should be false if the text occurs a different number of times than the given' do @session.visit('/with_count') expect(@session).not_to have_text('count', count: 0) expect(@session).not_to have_text('count', count: 1) + expect(@session).not_to have_text('count').once expect(@session).not_to have_text(/count/, count: 3) end @@ -186,12 +188,14 @@ it 'should be true when text occurs same or fewer times than given' do @session.visit('/with_count') expect(@session).to have_text('count', maximum: 2) + expect(@session).to have_text('count').at_most(2).times expect(@session).to have_text(/count/, maximum: 3) end it 'should be false when text occurs more times than given' do @session.visit('/with_count') expect(@session).not_to have_text('count', maximum: 1) + expect(@session).not_to have_text('count').at_most(1).times expect(@session).not_to have_text('count', maximum: 0) end @@ -206,12 +210,14 @@ it 'should be true when text occurs same or more times than given' do @session.visit('/with_count') expect(@session).to have_text('count', minimum: 2) + expect(@session).to have_text('count').at_least(2).times expect(@session).to have_text(/count/, minimum: 0) end it 'should be false when text occurs fewer times than given' do @session.visit('/with_count') expect(@session).not_to have_text('count', minimum: 3) + expect(@session).not_to have_text('count').at_least(3).times end it 'should coerce minimum to an integer' do