class Lopata::ScenarioBuilder
Context for scenario creation.
Attributes
@private
@private
@private
@private
@private
Public Class Methods
Defines one or more scenarios.
@example
Lopata.define 'scenario' do setup 'test user' action 'login' verify 'home page displayed' end
Given block will be calculated in context of the ScenarioBuilder
@param title [String] scenario unique title @param metadata [Hash] metadata to be used within the scenario @param block [Block] the scenario definition @see Lopata.define
# File lib/lopata/scenario_builder.rb, line 23 def self.define(title, metadata = {}, &block) builder = new(title, metadata) builder.instance_exec &block builder.build end
@private @macro [attach] define_step_method
@!scope instance @method $1
# File lib/lopata/scenario_builder.rb, line 153 def self.define_step_method(name) name_if = "%s_if" % name name_unless = "%s_unless" % name define_method name, ->(*args, **metadata, &block) { add_step(name, *args, metadata: metadata, &block) } define_method name_if, ->(condition, *args, **metadata, &block) { add_step(name, *args, metadata: metadata, condition: Lopata::Condition.new(condition), &block) } define_method name_unless, ->(condition, *args, **metadata, &block) { add_step(name, *args, condition: Lopata::Condition.new(condition, positive: false), metadata: metadata, &block) } end
@private
# File lib/lopata/scenario_builder.rb, line 30 def initialize(title, metadata = {}) @title, @common_metadata = title, metadata @diagonals = [] @options = [] end
Public Instance Methods
@private
# File lib/lopata/scenario_builder.rb, line 283 def add_step(method_name, *args, condition: nil, metadata: {}, &block) step_class = case method_name when /^(setup|action|teardown|verify)/ then Lopata::ActionStep when /^(context)/ then Lopata::GroupStep else Lopata::Step end step = step_class.new(method_name, *args, condition: condition, shared_step: shared_step, &block) step.metadata = metadata steps << step end
@private
# File lib/lopata/scenario_builder.rb, line 37 def build filters = Lopata.configuration.filters option_combinations.each do |option_set| metadata = common_metadata.merge(option_set.metadata) scenario = Lopata::Scenario::Execution.new(title, option_set.title, metadata) unless filters.empty? next unless filters.all? { |f| f[scenario] } end steps_with_hooks.each do |step| next if step.condition && !step.condition.match?(scenario) step.execution_steps(scenario).each { |s| scenario.steps << s } end world.scenarios << scenario end end
@private
# File lib/lopata/scenario_builder.rb, line 326 def combine(source_combinations, rest_options) return source_combinations if rest_options.empty? combinations = [] current_option = rest_options.shift source_combinations.each do |source_variants| current_option.level_variants.each do |v| combinations << (source_variants + OptionSet.new(v)) end end combine(combinations, rest_options) end
Define diagonal for the scenario.
The scenario will be generated for all the variants of the diagonal. Each variant of diagonal will be selected for at least one scenario. It may be included in more then one scenario when other diagonal or option has more variants.
@param metadata_key [Symbol] the key to access diagonal data via metadata. @param variants [Hash{String => Object}] variants for the diagonal.
Keys are titles of the variant, values are metadata values.
@example
Lopata.define 'scenario' do option :one, 'one' => 1, 'two' => 2 diagonal :two, 'two' => 2, 'three' => 3 diagonal :three, 'three' => 3, 'four' => 4, 'five' => 5 # will generate 3 scenarios: # - 'scenario one two three' # - 'scenario two three four' # - 'scenario one two five' end
@see option
# File lib/lopata/scenario_builder.rb, line 105 def diagonal(metadata_key, variants) @diagonals << Diagonal.new(metadata_key, variants) end
Define runtime method for the scenario.
@note
The method to be called via #method_missing, so it wont override already defined methods.
@example
let(:square) { |num| num * num } it 'calculated' do expect(square(4)).to eq 16 end
# File lib/lopata/scenario_builder.rb, line 274 def let(method_name, &block) steps << Lopata::Step.new(:let) do execution.let(method_name, &block) end end
Define additional metadata for the scenario
@example
Lopata.define 'scenario' do metadata key: 'value' it 'metadata available' do expect(metadata[:key]).to eq 'value' end end
# File lib/lopata/scenario_builder.rb, line 118 def metadata(hash) raise 'metadata expected to be a Hash' unless hash.is_a?(Hash) @common_metadata ||= {} @common_metadata.merge! hash end
Define option for the scenario.
The scenario will be generated for all the options. If more then one option given, the scenarios for all options combinations will be generated.
@param metadata_key [Symbol] the key to access option data via metadata. @param variants [Hash{String => Object}] variants for the option
Keys are titles of the variant, values are metadata values.
@example
Lopata.define 'scenario' do option :one, 'one' => 1, 'two' => 2 option :two, 'two' => 2, 'three' => 3 # will generate 4 scenarios: # - 'scenario one two' # - 'scenario one three' # - 'scenario two two' # - 'scenario two three' end
@see diagonal
# File lib/lopata/scenario_builder.rb, line 79 def option(metadata_key, variants) @options << Option.new(metadata_key, variants) end
@private
# File lib/lopata/scenario_builder.rb, line 317 def option_combinations combinations = combine([OptionSet.new], options + diagonals) while !diagonals.all?(&:complete?) combinations << OptionSet.new(*(options + diagonals).map(&:next_variant)) end combinations.reject { |option_set| skip?(option_set) } end
@private
# File lib/lopata/scenario_builder.rb, line 141 def skip?(option_set) @skip_when && @skip_when.call(option_set) end
Skip scenario for given variants combination
@example
Lopata.define 'multiple options' do option :one, 'one' => 1, 'two' => 2 option :two, 'two' => 2, 'three' => 3 skip_when { |opt| opt.metadata[:one] == opt.metadata[:two] } it 'not equal' do expect(one).to_not eq two end end
# File lib/lopata/scenario_builder.rb, line 136 def skip_when(&block) @skip_when = block end
@private
# File lib/lopata/scenario_builder.rb, line 296 def steps @steps ||= [] end
@private
# File lib/lopata/scenario_builder.rb, line 301 def steps_with_hooks s = [] unless Lopata.configuration.before_scenario_steps.empty? s << Lopata::ActionStep.new(:setup, *Lopata.configuration.before_scenario_steps) end s += steps unless Lopata.configuration.after_scenario_steps.empty? s << Lopata::ActionStep.new(:teardown, *Lopata.configuration.after_scenario_steps) end s end
@private
# File lib/lopata/scenario_builder.rb, line 339 def world Lopata.world end