Class: MiniAutobot::TestCase

Inherits:
Minitest::Test
  • Object
show all
Includes:
Utils::AssertionHelper, Utils::DataGeneratorHelper, Utils::Loggable, Utils::PageObjectHelper
Defined in:
lib/mini_autobot/test_case.rb

Overview

An MiniAutobot-specific test case container, which extends the default ones, adds convenience helper methods, and manages page objects automatically.

Direct Known Subclasses

Console

Defined Under Namespace

Classes: TestAlreadyDefined

Constant Summary collapse

@@selected_methods =
[]
@@runnables_count =
0
@@regression_suite =
Array.new
@@serials =
Array.new
@@test_suite_data =
if File.exist?(MiniAutobot.root.join("config/mini_autobot/test_suite.yml"))
  YAML.load_file(MiniAutobot.root.join("config/mini_autobot/test_suite.yml"))
else
  default = {"regression"=>{"tag_to_exclude"=>:non_regression}}
  if MiniAutobot.root != MiniAutobot.gem_root
    # Only necessary to notify gem user, not gem developer
    puts "config/mini_autobot/test_suite.yml doesn't exist, using default:\n#{default}"
    puts "It's recommended to have this config file as it'll avoid problem when using tapout"
  end
  default
end

Constants included from Utils::DataGeneratorHelper

Utils::DataGeneratorHelper::NPA, Utils::DataGeneratorHelper::NXX

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from Utils::PageObjectHelper

#connector_is_saucelabs?, #current_page, #is_element_present?, #is_element_present_and_displayed?, #json_save_to_ever_failed, #page, #print_sauce_link, #put_value, #read_yml, #retry_with_count, #take_screenshot, #teardown, #update_sauce_session_name, #update_sauce_session_status, #wait_for_attribute_to_have_value, #wait_for_element_to_be_present, #wait_for_element_to_display, #with_url_change_wait

Methods included from Utils::Loggable

#logger

Methods included from Utils::DataGeneratorHelper

#generate_date, #generate_digits, #generate_email, #generate_first_name, #generate_last_name, #generate_number, #generate_password, #generate_phone_number, #generate_test_email, #generate_unique_id

Methods included from Utils::AssertionHelper

#assert_element_absent, #assert_element_present

Class Attribute Details

.optionsHash

Returns test case options.

Returns:

  • (Hash)

    test case options



36
37
38
# File 'lib/mini_autobot/test_case.rb', line 36

def options
  @options
end

Class Method Details

.exclude_by_tag?(suite, tags) ⇒ Boolean

Parameters:

  • suite (String)

    type of test suite

  • tags (Array)

    an array of tags a test has

Returns:

  • (Boolean)


217
218
219
220
221
222
223
224
# File 'lib/mini_autobot/test_case.rb', line 217

def exclude_by_tag?(suite, tags)
  tag_to_exclude = @@test_suite_data[suite]['tag_to_exclude']
  if tags.include? tag_to_exclude
    true
  else
    false
  end
end

.filter_methods(methods, selected) ⇒ Object

Filter methods in a runnable based on our tag selection



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/mini_autobot/test_case.rb', line 118

def filter_methods(methods, selected)
  # If no tags are selected, run all tests
  if selected.nil? || selected.empty?
    return methods
  end

  selected_methods = methods.select do |method|
    # If the method's tags match any of the tag sets, allow it to run
    selected.any? do |tag_set|
      # Retrieve the tags for that method
      method_options = self.options[method.to_sym] rescue nil
      tags           = method_options[:tags]       rescue nil

      # If the method's tags match ALL of the tags in the tag set, allow
      # it to run; in the event of a problem, allow the test to run
      tag_set.all? do |tag|
        if tag =~ %r/^!/
          !tags.include?(tag[%r/^!(.*)/,1].to_sym) || nil
        else
          tags.include?(tag.to_sym) || nil
        end rescue true
      end
    end
  end

  selected_methods
end

.remove_testsTestCase

Explicitly remove all tests from the current class. This will also remove inherited test cases.

Returns:



42
43
44
45
46
47
48
# File 'lib/mini_autobot/test_case.rb', line 42

def remove_tests
  klass = class <<self; self; end
  public_instance_methods.grep(/^test_/).each do |method|
    klass.send(:undef_method, method.to_sym)
  end
  self
end

.run_in_order!TestCase

Call this at the top of your test case class in order to run all tests in alphabetical order

Examples:

class SomeName < TestCase
  run_in_order!

  test :feature_search_01 { ... }
  test :feature_search_02 { ... }
end

Returns:



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mini_autobot/test_case.rb', line 61

def run_in_order!
  # `self` is the class, so we want to reopen the metaclass instead, and
  # redefine the methods there
  class <<self
    undef_method :test_order if method_defined? :test_order
    define_method :test_order do
      :alpha
    end
  end

  # Be nice and return the class back
  self
end

.runnable_methodsEnumerable<Symbol>

Filter out anything not matching our tag selection, if any.

If it’s parallel run, only add filtered methods from each runnable to a list of to run methods, instead of running them one by one right away, and finally when all runnable methods are traversed, call parallel to run that list of methods.

Returns:

  • (Enumerable<Symbol>)

    the methods marked runnable



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/mini_autobot/test_case.rb', line 83

def runnable_methods
  methods  = super
  selected = MiniAutobot.settings.tags

  filtered_methods = filter_methods(methods, selected)

  if MiniAutobot.settings.parallel
    unless filtered_methods.empty?
      if selected.nil? || selected.empty?
        @@selected_methods = @@regression_suite
      else
        methods_to_add = filtered_methods.map { |method| method.to_sym if @@regression_suite.include?(method.to_sym) }
        @@selected_methods += methods_to_add
      end
    end

    @@runnables_count += 1
    mini_autobot_runnables = Minitest::Runnable.runnables - [Minitest::Test, Minitest::Unit::TestCase]

    if @@runnables_count == mini_autobot_runnables.size
      parallel = Parallel.new(MiniAutobot.settings.parallel, @@selected_methods)
      parallel.clean_result!
      parallel.run_in_parallel!
      parallel.remove_redundant_tap if MiniAutobot.settings.rerun_failure
      parallel.aggregate_tap_results
      exit
    end

    return [] # no test will run
  else
    filtered_methods
  end
end

.setup(&block) ⇒ void

This method returns an undefined value.

Install a setup method that runs before every test.



149
150
151
152
153
154
# File 'lib/mini_autobot/test_case.rb', line 149

def setup(&block)
  define_method(:setup) do
    super()
    instance_eval(&block)
  end
end

.teardown(&block) ⇒ void

This method returns an undefined value.

Install a teardown method that runs after every test.



159
160
161
162
163
164
# File 'lib/mini_autobot/test_case.rb', line 159

def teardown(&block)
  define_method(:teardown) do
    super()
    instance_eval(&block)
  end
end

.test(name, **opts, &block) ⇒ void

This method returns an undefined value.

Defines a test case.

It can take the following options:

  • ‘tags`: An array of any number of tags associated with the test case.

    When not specified, the test will always be run even when only
    certain tags are run. When specified but an empty array, the
    test will only be run if all tags are set to run. When the array
    contains one or more tags, then the test will only be run if at
    least one tag matches.
    
  • ‘serial`: An arbitrary string that is used to refer to all a specific

    test case. For example, this can be used to store the serial
    number for the test case.
    

Parameters:

  • name (String, Symbol)

    an arbitrary but unique name for the test, preferably unique across all test classes, but not required

  • opts (Hash)
  • block (Proc)

    the testing logic



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/mini_autobot/test_case.rb', line 185

def test(name, **opts, &block)
  # Ensure that the test isn't already defined to prevent tests from being
  # swallowed silently
  method_name = test_name(name)
  check_not_defined!(method_name)

  # Add an additional tag, which is unique for each test class, to all tests
  # To allow user to run tests with option '-t class_name_of_the_test' without
  # duplicate run for all tests in NameOfTheTest. The namespace of the class
  # is ignored here.
  opts[:tags] << ('class_'+ self.name.demodulize.underscore).to_sym

  # Flunk unless a logic block was provided
  if block_given?
    self.options ||= {}
    self.options[method_name.to_sym] = opts.deep_symbolize_keys
    define_method(method_name, &block)
  else
    flunk "No implementation was provided for test '#{method_name}' in #{self}"
  end

  # add all tests to @@regression_suite
  # excluding the ones with tags in tags_to_exclude defined in config
  unless exclude_by_tag?('regression', opts[:tags])
    @@regression_suite << method_name
    @@serials << opts[:serial]
  end
end