module Cucumber::Glue::ProtoWorld

Defines the basic API methods availlable in all Cucumber step definitions.

You can, and probably should, extend this API with your own methods that make sense in your domain. For more on that, see {Cucumber::Glue::Dsl#World}

Constants

AnsiEscapes

Defines aliases for ANSI coloured output. Default colours can be overridden by defining a GHERKIN_COLORS variable in your shell, very much like how you can tweak the familiar POSIX command ls with $LSCOLORS: linux-sxs.org/housekeeping/lscolors.html

The colours that you can change are:

undefined

defaults to yellow

pending

defaults to yellow

pending_arg

defaults to yellow,bold

executing

defaults to grey

executing_arg

defaults to grey,bold

failed

defaults to red

failed_arg

defaults to red,bold

passed

defaults to green

passed_arg

defaults to green,bold

outline

defaults to cyan

outline_arg

defaults to cyan,bold

skipped

defaults to cyan

skipped_arg

defaults to cyan,bold

comment

defaults to grey

tag

defaults to cyan

For instance, if your shell has a black background and a green font (like the “Homebrew” settings for OS X’ Terminal.app), you may want to override passed steps to be white instead of green. Examples:

export GHERKIN_COLORS="passed=white"
export GHERKIN_COLORS="passed=white,bold:passed_arg=white,bold,underline"

(If you’re on Windows, use SET instead of export). To see what colours and effects are available, just run this in your shell:

ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Term::ANSIColor.attributes"

Although not listed, you can also use grey

Public Class Methods

extended(object) click to toggle source
# File lib/cucumber/glue/proto_world.rb, line 132
def self.extended(object)
  # wrap the dynamically generated module so that we can document the methods
  # for yardoc, which doesn't like define_method.
  object.extend(ProtoWorld)
end
for(runtime, language) click to toggle source

Dynamially generate the API module, closuring the dependencies

# File lib/cucumber/glue/proto_world.rb, line 130
def self.for(runtime, language) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
  Module.new do # rubocop:disable Metrics/BlockLength
    def self.extended(object)
      # wrap the dynamically generated module so that we can document the methods
      # for yardoc, which doesn't like define_method.
      object.extend(ProtoWorld)
    end

    # TODO: pass these in when building the module, instead of mutating them later
    # Extend the World with user-defined modules
    def add_modules!(world_modules, namespaced_world_modules)
      add_world_modules!(world_modules)
      add_namespaced_modules!(namespaced_world_modules)
    end

    define_method(:step) do |name, raw_multiline_arg = nil|
      location = Core::Test::Location.of_caller
      runtime.invoke_dynamic_step(name, MultilineArgument.from(raw_multiline_arg, location))
    end

    define_method(:steps) do |steps_text|
      location = Core::Test::Location.of_caller
      runtime.invoke_dynamic_steps(steps_text, language, location)
    end

    define_method(:ask) do |question, timeout_seconds = 60|
      runtime.ask(question, timeout_seconds)
    end

    define_method(:attach) do |file, media_type|
      runtime.attach(file, media_type)
    end

    # Prints the list of modules that are included in the World
    def inspect
      modules = [self.class]
      (class << self; self; end).instance_eval do
        modules += included_modules
      end
      modules << stringify_namespaced_modules
      format('#<%<modules>s:0x%<object_id>x>', modules: modules.join('+'), object_id: object_id)
    end

    private

    # @private
    def add_world_modules!(modules)
      modules.each do |world_module|
        extend(world_module)
      end
    end

    # @private
    def add_namespaced_modules!(modules)
      @__namespaced_modules = modules
      modules.each do |namespace, world_modules|
        world_modules.each do |world_module|
          variable_name = "@__#{namespace}_world"

          inner_world = if self.class.respond_to?(namespace)
                          instance_variable_get(variable_name)
                        else
                          Object.new
                        end
          instance_variable_set(variable_name,
                                inner_world.extend(world_module))
          self.class.send(:define_method, namespace) do
            instance_variable_get(variable_name)
          end
        end
      end
    end

    # @private
    def stringify_namespaced_modules
      @__namespaced_modules.map { |k, v| "#{v.join(',')} (as #{k})" }.join('+')
    end
  end
end

Public Instance Methods

add_modules!(world_modules, namespaced_world_modules) click to toggle source

TODO: pass these in when building the module, instead of mutating them later Extend the World with user-defined modules

# File lib/cucumber/glue/proto_world.rb, line 140
def add_modules!(world_modules, namespaced_world_modules)
  add_world_modules!(world_modules)
  add_namespaced_modules!(namespaced_world_modules)
end
add_namespaced_modules!(modules) click to toggle source

@private

# File lib/cucumber/glue/proto_world.rb, line 183
def add_namespaced_modules!(modules)
  @__namespaced_modules = modules
  modules.each do |namespace, world_modules|
    world_modules.each do |world_module|
      variable_name = "@__#{namespace}_world"

      inner_world = if self.class.respond_to?(namespace)
                      instance_variable_get(variable_name)
                    else
                      Object.new
                    end
      instance_variable_set(variable_name,
                            inner_world.extend(world_module))
      self.class.send(:define_method, namespace) do
        instance_variable_get(variable_name)
      end
    end
  end
end
add_world_modules!(modules) click to toggle source

@private

# File lib/cucumber/glue/proto_world.rb, line 176
def add_world_modules!(modules)
  modules.each do |world_module|
    extend(world_module)
  end
end
ask(question, timeout_seconds = 60) click to toggle source

Pause the tests and ask the operator for input

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 77
def ask(question, timeout_seconds = 60)
  super
end
attach(file, media_type = nil) click to toggle source

Attach a file to the output @param file [string|io] the file to attach.

It can be a string containing the file content itself,
the file path, or an IO ready to be read.

@param media_type [string] the media type. If file is a valid path,

media_type can be ommitted, it will then be inferred from the file name.
Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 91
def attach(file, media_type = nil)
  return super unless File.file?(file)

  content = File.read(file, mode: 'rb')
  media_type = MIME::Types.type_for(file).first if media_type.nil?

  super(content, media_type.to_s)
rescue StandardError
  super
end
inspect() click to toggle source

Prints the list of modules that are included in the World

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 120
def inspect
  super
end
log(*messages) click to toggle source
# File lib/cucumber/glue/proto_world.rb, line 81
def log(*messages)
  messages.each { |message| attach(message.to_s.dup, 'text/x.cucumber.log+plain') }
end
pending(message = 'TODO') { || ... } click to toggle source

Mark the matched step as pending.

# File lib/cucumber/glue/proto_world.rb, line 103
def pending(message = 'TODO')
  raise Pending, message unless block_given?

  begin
    yield
  rescue Exception # rubocop:disable Lint/RescueException
    raise Pending, message
  end
  raise Pending, "Expected pending '#{message}' to fail. No Error was raised. No longer pending?"
end
skip_this_scenario(message = 'Scenario skipped') click to toggle source

Skips this step and the remaining steps in the scenario

# File lib/cucumber/glue/proto_world.rb, line 115
def skip_this_scenario(message = 'Scenario skipped')
  raise Core::Test::Result::Skipped, message
end
step(name, raw_multiline_arg = nil) click to toggle source

Run a single Gherkin step @example Call another step

step "I am logged in"

@example Call a step with quotes in the name

step %{the user "Dave" is logged in}

@example Passing a table

step "the following users exist:", table(%{
  | name  | email           |
  | Matt  | matt@matt.com   |
  | Aslak | aslak@aslak.com |
})

@example Passing a multiline string

step "the email should contain:", "Dear sir,\nYou've won a prize!\n"

@param [String] name The name of the step @param [String,Cucumber::Test::DocString,Cucumber::Ast::Table] multiline_argument

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 30
def step(name, raw_multiline_arg = nil)
  super
end
steps(steps_text) click to toggle source

Run a snippet of Gherkin @example

steps %{
  Given the user "Susan" exists
  And I am logged in as "Susan"
}

@param [String] steps_text The Gherkin snippet to run

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 41
def steps(steps_text)
  super
end
stringify_namespaced_modules() click to toggle source

@private

# File lib/cucumber/glue/proto_world.rb, line 204
def stringify_namespaced_modules
  @__namespaced_modules.map { |k, v| "#{v.join(',')} (as #{k})" }.join('+')
end
table(text_or_table) click to toggle source

Parse Gherkin into a {Cucumber::Ast::Table} object.

Useful in conjunction with the step method. @example Create a table

users = table(%{
  | name  | email           |
  | Matt  | matt@matt.com   |
  | Aslak | aslak@aslak.com |
})

@param [String] text_or_table The Gherkin string that represents the table Returns a Cucumber::MultilineArgument::DataTable for text_or_table, which can either be a String:

table(%{
  | account | description | amount |
  | INT-100 | Taxi        | 114    |
  | CUC-101 | Peeler      | 22     |
})

or a 2D Array:

table([
  %w{ account description amount },
  %w{ INT-100 Taxi        114    },
  %w{ CUC-101 Peeler      22     }
])
# File lib/cucumber/glue/proto_world.rb, line 72
def table(text_or_table)
  MultilineArgument::DataTable.from(text_or_table)
end
to_s() click to toggle source

see {#inspect}

# File lib/cucumber/glue/proto_world.rb, line 125
def to_s
  inspect
end