# frozen_string_literal: truerequire'cucumber/gherkin/formatter/ansi_escapes'require'cucumber/core/test/data_table'require'cucumber/deprecate'require'mini_mime'moduleCucumbermoduleGlue# Defines the basic API methods available 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}moduleProtoWorld# 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] raw_multiline_argdefstep(name,raw_multiline_arg=nil)superend# 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 rundefsteps(steps_text)superend# 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 }# ])#deftable(text_or_table)MultilineArgument::DataTable.from(text_or_table)end# Pause the tests and ask the operator for inputdefask(question,timeout_seconds=60)superenddeflog(*messages)messages.each{|message|attach(message.to_s.dup,'text/x.cucumber.log+plain')}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 omitted, it will then be inferred from the file name.# @param filename [string] the name of the file you wish to specify.# This is only needed in situations where you want to rename a PDF download e.t.c. - In most situations# you should not need to pass a filenamedefattach(file,media_type=nil,filename=nil)returnsuperunlessFile.file?(file)content=File.read(file,mode: 'rb')media_type=MiniMime.lookup_by_filename(file)&.content_typeifmedia_type.nil?super(content,media_type.to_s,filename)rescueStandardErrorsuperend# Mark the matched step as pending.defpending(message='TODO')raisePending,messageunlessblock_given?yieldrescueExceptionraisePending,messageend# Skips this step and the remaining steps in the scenariodefskip_this_scenario(message='Scenario skipped')raiseCore::Test::Result::Skipped,messageend# Prints the list of modules that are included in the Worlddefinspectsuperend# see {#inspect}defto_sinspectend# Dynamically generate the API module, closuring the dependenciesdefself.for(runtime,language)Module.newdodefself.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 modulesdefadd_modules!(world_modules,namespaced_world_modules)add_world_modules!(world_modules)ifworld_modules.any?add_namespaced_modules!(namespaced_world_modules)ifnamespaced_world_modules.any?enddefine_method(:step)do|name,raw_multiline_arg=nil|location=Core::Test::Location.of_callerruntime.invoke_dynamic_step(name,MultilineArgument.from(raw_multiline_arg,location))enddefine_method(:steps)do|steps_text|location=Core::Test::Location.of_callerruntime.invoke_dynamic_steps(steps_text,language,location)enddefine_method(:ask)do|question,timeout_seconds=60|runtime.ask(question,timeout_seconds)enddefine_method(:attach)do|file,media_type,filename|runtime.attach(file,media_type,filename)end# Prints the list of modules that are included in the Worlddefinspectmodules=[self.class](class<<self;self;end).instance_evaldomodules+=included_modulesendmodules<<stringify_namespaced_modulesformat('#<%<modules>s:0x%<object_id>x>',modules: modules.join('+'),object_id: object_id)endprivatedefadd_world_modules!(modules)modules.eachdo|world_module|extend(world_module)endenddefadd_namespaced_modules!(modules)@__namespaced_modules=modulesmodules.eachdo|namespace,world_modules|world_modules.eachdo|world_module|variable_name="@__#{namespace}_world"inner_world=instance_variable_get(variable_name)||Object.newinstance_variable_set(variable_name,inner_world.extend(world_module))self.class.send(:define_method,namespace)doinstance_variable_get(variable_name)endendendenddefstringify_namespaced_modulesreturn''if@__namespaced_modules.nil?@__namespaced_modules.map{|k,v|"#{v.join(',')} (as #{k})"}.join('+')endendendAnsiEscapes=Cucumber::Gherkin::Formatter::AnsiEscapesendendend