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 commandls
with $LSCOLORS: linux-sxs.org/housekeeping/lscolors.htmlThe 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
# 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
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
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
@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
@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
Pause the tests and ask the operator for input
# File lib/cucumber/glue/proto_world.rb, line 77 def ask(question, timeout_seconds = 60) super end
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.
# 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
Prints the list of modules that are included in the World
# File lib/cucumber/glue/proto_world.rb, line 120 def inspect super end
# 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
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
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
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
# File lib/cucumber/glue/proto_world.rb, line 30 def step(name, raw_multiline_arg = nil) super end
@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
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
see {#inspect}
# File lib/cucumber/glue/proto_world.rb, line 125 def to_s inspect end