Create RSpec matchers for negatable predicate methods
Problem
As noted in the documentation, there are cases where using not_to
in an expect
statement can be unintentionally inefficient because when the expect
statement passes, the framework executes the positive predicate method (e.g., has_file?
), waits 10 seconds for it to fail, then negates the result.
One solution to this problem is to use a negative predicate method instead (e.g., has_no_file?
). For example expect(project).to have_no_file(name)
. The problem with this solution is that it is awkward phrasing, and we have to remember to write it that way rather than the more familiar option of using not_to
.
Proposal
Create custom RSpec matchers for negatable predicate methods. For example, in gitlab-org/gitlab!46302 (merged) a negatable have_file
matcher is defined:
RSpec::Matchers.define :have_file do |file|
match do |actual|
expect(actual.has_file?(file)).to be true
end
match_when_negated do |actual|
expect(actual.has_no_file?(file)).to be true
end
end
When it's used in a test, such as:
Page::Project::Show.perform do |project|
expect(project).not_to have_file(file_name)
end
...instead of executing the page object's has_file?
method, it uses the match_when_negated
block to execute has_no_file?
, and is therefore the same as expect(project).to have_no_file(file_name)
, but reads more naturally, and avoids the problem of having to use negative predicate methods when we're more familiar with using not_to
.
Tasks
-
Create custom matchers (e.g., for has_no_element?
andhas_no_text?
) -
Update the docs: https://docs.gitlab.com/ee/development/testing_guide/end_to_end/best_practices.html#ensure-expect-checks-for-negation-efficiently