class Lopata::ScenarioBuilder

Context for scenario creation.

Attributes

common_metadata[R]

@private

diagonals[R]

@private

group[RW]

@private

options[R]

@private

shared_step[RW]

@private

title[R]

@private

Public Class Methods

define(title, metadata = {}, &block) click to toggle source

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
define_step_method(name) click to toggle source

@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
new(title, metadata = {}) click to toggle source

@private

# File lib/lopata/scenario_builder.rb, line 30
def initialize(title, metadata = {})
  @title, @common_metadata = title, metadata
  @diagonals = []
  @options = []
end

Public Instance Methods

add_step(method_name, *args, condition: nil, metadata: {}, &block) click to toggle source

@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
build() click to toggle source

@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
combine(source_combinations, rest_options) click to toggle source

@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
diagonal(metadata_key, variants) click to toggle source

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
let(method_name, &block) click to toggle source

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
metadata(hash) click to toggle source

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
option(metadata_key, variants) click to toggle source

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
option_combinations() click to toggle source

@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
skip?(option_set) click to toggle source

@private

# File lib/lopata/scenario_builder.rb, line 141
def skip?(option_set)
  @skip_when && @skip_when.call(option_set)
end
skip_when(&block) click to toggle source

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
steps() click to toggle source

@private

# File lib/lopata/scenario_builder.rb, line 296
def steps
  @steps ||= []
end
steps_with_hooks() click to toggle source

@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
world() click to toggle source

@private

# File lib/lopata/scenario_builder.rb, line 339
def world
  Lopata.world
end