summaryrefslogtreecommitdiff
path: root/qa/spec
diff options
context:
space:
mode:
Diffstat (limited to 'qa/spec')
-rw-r--r--qa/spec/spec_helper.rb5
-rw-r--r--qa/spec/specs/helpers/context_selector_spec.rb6
-rw-r--r--qa/spec/support/matchers/eventually_matcher.rb132
3 files changed, 138 insertions, 5 deletions
diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb
index 0c9643c830b..f4bfd57504e 100644
--- a/qa/spec/spec_helper.rb
+++ b/qa/spec/spec_helper.rb
@@ -4,6 +4,7 @@ require_relative '../qa'
require 'rspec/retry'
require 'rspec-parameterized'
require 'active_support/core_ext/hash'
+require 'active_support/core_ext/object/blank'
if ENV['CI'] && QA::Runtime::Env.knapsack? && !ENV['NO_KNAPSACK']
require 'knapsack'
@@ -11,8 +12,8 @@ if ENV['CI'] && QA::Runtime::Env.knapsack? && !ENV['NO_KNAPSACK']
end
QA::Runtime::Browser.configure!
-
-QA::Runtime::Scenario.from_env(QA::Runtime::Env.runtime_scenario_attributes) if QA::Runtime::Env.runtime_scenario_attributes
+QA::Runtime::AllureReport.configure!
+QA::Runtime::Scenario.from_env(QA::Runtime::Env.runtime_scenario_attributes)
Dir[::File.join(__dir__, "support/helpers/*.rb")].sort.each { |f| require f }
Dir[::File.join(__dir__, "support/matchers/*.rb")].sort.each { |f| require f }
diff --git a/qa/spec/specs/helpers/context_selector_spec.rb b/qa/spec/specs/helpers/context_selector_spec.rb
index 16b6c6601b1..7792d33dcf9 100644
--- a/qa/spec/specs/helpers/context_selector_spec.rb
+++ b/qa/spec/specs/helpers/context_selector_spec.rb
@@ -189,9 +189,9 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
it 'runs on default branch pipelines' do
group = describe_successfully do
- it('runs on master pipeline given a single pipeline', only: { pipeline: :master }) {}
- it('runs in master given an array of pipelines', only: { pipeline: [:canary, :master] }) {}
- it('does not run in non-default pipelines', only: { pipeline: [:nightly, :not_nightly, :not_master] }) {}
+ it('runs on main pipeline given a single pipeline', only: { pipeline: :main }) {}
+ it('runs in main given an array of pipelines', only: { pipeline: [:canary, :main] }) {}
+ it('does not run in non-default pipelines', only: { pipeline: [:nightly, :not_nightly, :not_main] }) {}
end
aggregate_failures do
diff --git a/qa/spec/support/matchers/eventually_matcher.rb b/qa/spec/support/matchers/eventually_matcher.rb
new file mode 100644
index 00000000000..3f0afd6fb54
--- /dev/null
+++ b/qa/spec/support/matchers/eventually_matcher.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+# Rspec matcher with build in retry logic
+#
+# USAGE:
+#
+# Basic
+# expect { Something.that.takes.time.to_appear }.to eventually_eq(expected_result)
+# expect { Something.that.takes.time.to_appear }.not_to eventually_eq(expected_result)
+#
+# With duration and attempts override
+# expect { Something.that.takes.time.to_appear }.to eventually_eq(expected_result).within(duration: 10, attempts: 5)
+
+module Matchers
+ %w[
+ eq
+ be
+ include
+ be_truthy
+ be_falsey
+ be_empty
+ ].each do |op|
+ RSpec::Matchers.define(:"eventually_#{op}") do |*expected|
+ chain(:within) do |options = {}|
+ @duration = options[:duration]
+ @attempts = options[:attempts]
+ end
+
+ def supports_block_expectations?
+ true
+ end
+
+ match { |actual| wait_and_check(actual, :default_expectation) }
+
+ match_when_negated { |actual| wait_and_check(actual, :when_negated_expectation) }
+
+ description do
+ "eventually #{operator_msg} #{expected.inspect}"
+ end
+
+ failure_message do
+ "#{e}:\nexpected to #{description}, last attempt was #{@result.nil? ? 'nil' : @result}"
+ end
+
+ failure_message_when_negated do
+ "#{e}:\nexpected not to #{description}, last attempt was #{@result.nil? ? 'nil' : @result}"
+ end
+
+ # Execute rspec expectation within retrier
+ #
+ # @param [Proc] actual
+ # @param [Symbol] expectation_name
+ # @return [Boolean]
+ def wait_and_check(actual, expectation_name)
+ QA::Support::Retrier.retry_until(
+ max_attempts: @attempts,
+ max_duration: @duration,
+ sleep_interval: 0.5
+ ) do
+ public_send(expectation_name, actual)
+ rescue RSpec::Expectations::ExpectationNotMetError, QA::Resource::ApiFabricator::ResourceNotFoundError
+ false
+ end
+ rescue QA::Support::Repeater::RetriesExceededError, QA::Support::Repeater::WaitExceededError => e
+ @e = e
+ false
+ end
+
+ # Execute rspec expectation
+ #
+ # @param [Proc] actual
+ # @return [void]
+ def default_expectation(actual)
+ expect(result(&actual)).to public_send(*expectation_args)
+ end
+
+ # Execute negated rspec expectation
+ #
+ # @param [Proc] actual
+ # @return [void]
+ def when_negated_expectation(actual)
+ expect(result(&actual)).not_to public_send(*expectation_args)
+ end
+
+ # Result of actual block
+ #
+ # @return [Object]
+ def result
+ @result = yield
+ end
+
+ # Error message placeholder to indicate waiter did not fail properly
+ # This message should not appear under normal circumstances since it should
+ # always be assigned from repeater
+ #
+ # @return [String]
+ def e
+ @e ||= 'Waiter did not fail!'
+ end
+
+ # Operator message
+ #
+ # @return [String]
+ def operator_msg
+ case operator
+ when 'eq' then 'equal'
+ else operator
+ end
+ end
+
+ # Expect operator
+ #
+ # @return [String]
+ def operator
+ @operator ||= name.to_s.match(/eventually_(.+?)$/).to_a[1].to_s
+ end
+
+ # Expectation args
+ #
+ # @return [String, Array]
+ def expectation_args
+ if operator.include?('truthy') || operator.include?('falsey') || operator.include?('empty')
+ operator
+ elsif operator == "include" && expected.is_a?(Array)
+ [operator, *expected]
+ else
+ [operator, expected]
+ end
+ end
+ end
+ end
+end