lopata 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/lib/lopata.rb +2 -1
- data/lib/lopata/active_record.rb +37 -0
- data/lib/lopata/factory_bot.rb +51 -15
- data/lib/lopata/generators/app.rb +2 -0
- data/lib/lopata/id.rb +1 -0
- data/lib/lopata/loader.rb +2 -0
- data/lib/lopata/observers.rb +1 -0
- data/lib/lopata/observers/backtrace_formatter.rb +1 -1
- data/lib/lopata/observers/base_observer.rb +2 -2
- data/lib/lopata/observers/web_logger.rb +4 -0
- data/lib/lopata/role.rb +45 -0
- data/lib/lopata/runner.rb +8 -2
- data/lib/lopata/scenario.rb +19 -0
- data/lib/lopata/scenario_builder.rb +241 -16
- data/lib/lopata/shared_step.rb +2 -0
- data/lib/lopata/step.rb +5 -1
- data/lib/lopata/version.rb +2 -1
- data/lib/lopata/world.rb +5 -11
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f4b4814d88cd3b9da3a34159e3c1c977d05cbb0504d3dc0b2ab8034044dfbf0
|
4
|
+
data.tar.gz: 378e5a3c346c64cb4430577dcfab31cfefd54a2c8e8ee30046609cf10e1bdba4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff0498d9c9b665d52f5a8d1e65cdc6dc9078f0df1cd4f7fd831393af04ee564a5cf9a9f55305bd4423ff92062cdb7fd4a728bb2be657f196f91447faddffa941
|
7
|
+
data.tar.gz: 063a3914c5e5dd088ad56e37ea527c540e8dc82f0d56e7dca4564e61699541000e4d801a80898b2d89eb6719cfd4d1a887d3884a52335f0e6339ffc9a91569fb
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private
|
data/lib/lopata.rb
CHANGED
@@ -6,6 +6,7 @@ require 'lopata/scenario'
|
|
6
6
|
require 'lopata/step'
|
7
7
|
require 'lopata/shared_step'
|
8
8
|
|
9
|
+
# Namespace for all Lopata code.
|
9
10
|
module Lopata
|
10
11
|
# Define the scenario.
|
11
12
|
# @see Lopata::ScenarioBuilder.define
|
@@ -34,7 +35,7 @@ module Lopata
|
|
34
35
|
# end
|
35
36
|
# end
|
36
37
|
# @param name [String] shared step unique name
|
37
|
-
# @param block shared step action sequence definition
|
38
|
+
# @param block [Block] shared step action sequence definition
|
38
39
|
def self.shared_step(name, &block)
|
39
40
|
Lopata::SharedStep.register(name, &block)
|
40
41
|
end
|
data/lib/lopata/active_record.rb
CHANGED
@@ -71,6 +71,39 @@ module Lopata
|
|
71
71
|
def reload(*objects)
|
72
72
|
objects.flatten.compact.each(&:reload)
|
73
73
|
end
|
74
|
+
|
75
|
+
# Marks object to be destroyed at the end of scenario
|
76
|
+
#
|
77
|
+
# @param object [ActiveRecord::Base] the object to be destoryed at the end of scenario
|
78
|
+
# @return the given object, so chains can be build
|
79
|
+
def cleanup_later(object)
|
80
|
+
return nil unless object
|
81
|
+
@created_objects ||= []
|
82
|
+
@created_objects << object
|
83
|
+
object
|
84
|
+
end
|
85
|
+
|
86
|
+
# Find ActiveRecord object of given class by params.
|
87
|
+
# Marks the returned object to be destroyed at the end of scenario.
|
88
|
+
#
|
89
|
+
# @example
|
90
|
+
# action do
|
91
|
+
# # UI actions creating the user
|
92
|
+
# @user = find_created(User, username: 'testuser')
|
93
|
+
# end
|
94
|
+
# it 'created' do
|
95
|
+
# expect(@user).to_not be_nil
|
96
|
+
# end
|
97
|
+
# # No cleanup needed
|
98
|
+
# # cleanup :user
|
99
|
+
#
|
100
|
+
# @param cls [Class] active record model class
|
101
|
+
# @param params [Hash] options for record finding
|
102
|
+
# @return [ActiveRecord::Base, nil] the object or nil if not found
|
103
|
+
# @see #cleanup_later called on the hood
|
104
|
+
def find_created(cls, params)
|
105
|
+
cleanup_later cls.where(params).take
|
106
|
+
end
|
74
107
|
end
|
75
108
|
|
76
109
|
# To be included in Lopata::ScenarioBuilder. The methods may be used in build time.
|
@@ -92,6 +125,10 @@ module Lopata
|
|
92
125
|
end
|
93
126
|
end
|
94
127
|
|
128
|
+
Lopata.configure do |c|
|
129
|
+
c.after_scenario { cleanup @created_objects }
|
130
|
+
end
|
131
|
+
|
95
132
|
params = Lopata.environment['db']
|
96
133
|
ActiveRecord::Base.establish_connection(params) if params
|
97
134
|
|
data/lib/lopata/factory_bot.rb
CHANGED
@@ -1,23 +1,63 @@
|
|
1
1
|
require_relative 'active_record'
|
2
2
|
|
3
3
|
module Lopata
|
4
|
+
# Helpers for FactoryBot usage in tests.
|
5
|
+
#
|
6
|
+
# Make helpers available in scenarios by
|
7
|
+
#
|
8
|
+
# require 'lopata/factory_bot'
|
9
|
+
#
|
10
|
+
# Automatically adds ActiveRecord helpers.
|
11
|
+
# @see Lopata::ActiveRecord
|
12
|
+
#
|
13
|
+
# Allows to create ActiveRecord object by FactoryBot definitions.
|
14
|
+
# All the objects created by FactoryBot helpers will be destroyed automatically
|
15
|
+
# at the end of scenario.
|
16
|
+
# @see Lopata::ActiveRecord::Methods#cleanup
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
#
|
20
|
+
# # Configure db connection at config/environments/qa.yml like rails:
|
21
|
+
# # db:
|
22
|
+
# # adapter: postgresql
|
23
|
+
# # host: your.database.host
|
24
|
+
# # username: username
|
25
|
+
# # password: password
|
26
|
+
# # database: database
|
27
|
+
# require 'active_record'
|
28
|
+
# require 'factory_bot'
|
29
|
+
# require 'lopata/facotory_bot'
|
30
|
+
#
|
31
|
+
# class User < ActiveRecord::Base; end
|
32
|
+
#
|
33
|
+
# FactoryBot.define do
|
34
|
+
# factory :user do
|
35
|
+
# username { 'testuser' }
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# Lopata.define 'User creation' do
|
40
|
+
# setup do
|
41
|
+
# @user = create(:user)
|
42
|
+
# end
|
43
|
+
# # No cleanup needed - @user will be destroyed automatically
|
44
|
+
# # cleanup :user
|
45
|
+
#
|
46
|
+
# it 'works' do
|
47
|
+
# expect(@user).to_not be_nil
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
4
51
|
module FactoryBot
|
5
52
|
# To be included in Lopata::Scenario
|
6
53
|
module Methods
|
54
|
+
# Wrapper for FactoryBot#create
|
55
|
+
# Calls the FactoryBot#create with given paramters and returns it result.
|
56
|
+
# Additionally store the created object for destroying at the end of scenario.
|
57
|
+
# @see Lopata::ActiveRecord::Methods#cleanup
|
7
58
|
def create(*params)
|
8
59
|
cleanup_later ::FactoryBot.create(*params)
|
9
60
|
end
|
10
|
-
|
11
|
-
def find_created(cls, params)
|
12
|
-
cleanup_later cls.where(params).take
|
13
|
-
end
|
14
|
-
|
15
|
-
def cleanup_later(object)
|
16
|
-
return nil unless object
|
17
|
-
@created_objects ||= []
|
18
|
-
@created_objects << object
|
19
|
-
object
|
20
|
-
end
|
21
61
|
end
|
22
62
|
|
23
63
|
# To be included in Lopata::ScenarioBuilder
|
@@ -29,8 +69,4 @@ end
|
|
29
69
|
Lopata::Scenario.include Lopata::FactoryBot::Methods
|
30
70
|
Lopata::ScenarioBuilder.include Lopata::FactoryBot::DSL
|
31
71
|
|
32
|
-
Lopata.configure do |c|
|
33
|
-
c.after_scenario { cleanup @created_objects }
|
34
|
-
end
|
35
|
-
|
36
72
|
::FactoryBot.find_definitions
|
data/lib/lopata/id.rb
CHANGED
data/lib/lopata/loader.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# @private
|
1
2
|
module Lopata::Loader
|
2
3
|
extend self
|
3
4
|
|
@@ -20,6 +21,7 @@ module Lopata::Loader
|
|
20
21
|
Dir["scenarios/**/*.rb"].each { |f| load File.expand_path(f) }
|
21
22
|
end
|
22
23
|
|
24
|
+
# Loads all shared steps from predefined paths
|
23
25
|
def load_shared_steps
|
24
26
|
Dir["shared_steps/**/*rb"].each { |f| load File.expand_path(f) }
|
25
27
|
end
|
data/lib/lopata/observers.rb
CHANGED
@@ -39,7 +39,7 @@ module Lopata
|
|
39
39
|
|
40
40
|
# Extracts error message from excetion
|
41
41
|
#
|
42
|
-
# @param
|
42
|
+
# @param exception [Exception]
|
43
43
|
# @param include_backtrace [Boolean] whether to add formatted backtrace to output
|
44
44
|
# @return [String] error message from excetion, incuding source code line.
|
45
45
|
def error_message(exception, include_backtrace: false)
|
@@ -21,12 +21,12 @@ module Lopata
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# Called before single scenario execution.
|
24
|
-
# @param
|
24
|
+
# @param scenario [Lopata::Scenario::Execution]
|
25
25
|
def scenario_started(scenario)
|
26
26
|
end
|
27
27
|
|
28
28
|
# Called after single scenario execution.
|
29
|
-
# @param
|
29
|
+
# @param scenario [Lopata::Scenario::Execution]
|
30
30
|
def scenario_finished(scenario)
|
31
31
|
end
|
32
32
|
end
|
data/lib/lopata/role.rb
CHANGED
@@ -1,9 +1,33 @@
|
|
1
1
|
module Lopata
|
2
|
+
# Adds ability to run scenarios by given user roles
|
3
|
+
#
|
4
|
+
# @example Usage
|
5
|
+
# require 'lopata/role'
|
6
|
+
# Lopata.configure do |c|
|
7
|
+
# c.role_descriptions = {
|
8
|
+
# user: 'User',
|
9
|
+
# admin: 'Admin'
|
10
|
+
# }
|
11
|
+
# c.default_role = :user
|
12
|
+
# c.before_scenaro 'setup user'
|
13
|
+
# end
|
14
|
+
# Lopata.shared_step 'setup user' do
|
15
|
+
# setup { @user = User.create(role: current_role) if current_role }
|
16
|
+
# cleanup :user
|
17
|
+
# end
|
18
|
+
# Lopata.define 'login' do
|
19
|
+
# # will generate 2 scenarios, one for :user and one for :admin
|
20
|
+
# as :user, :admin
|
21
|
+
# action 'login'
|
22
|
+
# # verify the user is logged in
|
23
|
+
# end
|
24
|
+
#
|
2
25
|
# @see Lopata::Configuration#role_descriptions
|
3
26
|
# @see Lopata::Configuration#default_role
|
4
27
|
module Role
|
5
28
|
# To be included in Lopata::Scenario
|
6
29
|
module Methods
|
30
|
+
# @return [Symbol, nil] user role for current scenario or nil, if scenario is running without user.
|
7
31
|
def current_role
|
8
32
|
metadata[:as]
|
9
33
|
end
|
@@ -11,30 +35,50 @@ module Lopata
|
|
11
35
|
|
12
36
|
# To be included in Lopata::ScenarioBuilder
|
13
37
|
module DSL
|
38
|
+
# Enumerate the roles the scenario to be runned under.
|
39
|
+
# If not invoked the default role only will be used.
|
40
|
+
#
|
41
|
+
# The scenario should be set to use the role via before_scenario step using #current_role param.
|
42
|
+
#
|
43
|
+
# @param args [Array<Symbol>] list of roles the scenario to be runned with.
|
44
|
+
# @param block [Block] the block to calculate role from scenario metadata.
|
14
45
|
def as(*args, &block)
|
15
46
|
@roles = args.flatten
|
16
47
|
@roles << Lopata::ScenarioBuilder::CalculatedValue.new(&block) if block_given?
|
17
48
|
@role_options = nil
|
18
49
|
end
|
19
50
|
|
51
|
+
# @private
|
20
52
|
def role_options
|
21
53
|
@role_options ||= build_role_options
|
22
54
|
end
|
23
55
|
|
56
|
+
# Marks scenario to be runned without user.
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# Lopata.define 'scenario withou user' do
|
60
|
+
# without_user
|
61
|
+
# it 'does not define the user' do
|
62
|
+
# expect(current_role).to be_nil
|
63
|
+
# end
|
64
|
+
# end
|
24
65
|
def without_user
|
25
66
|
@without_user = true
|
26
67
|
end
|
27
68
|
|
69
|
+
# @private
|
28
70
|
def build_role_options
|
29
71
|
return [] unless roles
|
30
72
|
[Lopata::ScenarioBuilder::Diagonal.new(:as, roles.map { |r| [Lopata.configuration.role_descriptions[r], r] })]
|
31
73
|
end
|
32
74
|
|
75
|
+
# @private
|
33
76
|
def roles
|
34
77
|
return false if @without_user
|
35
78
|
@roles ||= [Lopata.configuration.default_role].compact
|
36
79
|
end
|
37
80
|
|
81
|
+
# @private
|
38
82
|
def diagonals
|
39
83
|
super + role_options
|
40
84
|
end
|
@@ -43,4 +87,5 @@ module Lopata
|
|
43
87
|
end
|
44
88
|
|
45
89
|
Lopata::Scenario.include Lopata::Role::Methods
|
90
|
+
# Prepend the module to overload #diagonals method
|
46
91
|
Lopata::ScenarioBuilder.prepend Lopata::Role::DSL
|
data/lib/lopata/runner.rb
CHANGED
@@ -7,6 +7,7 @@ require_relative 'observers'
|
|
7
7
|
require_relative 'condition'
|
8
8
|
|
9
9
|
module Lopata
|
10
|
+
# @private
|
10
11
|
class Runner < Thor
|
11
12
|
desc 'test', 'Run tests'
|
12
13
|
option :env, default: :qa, aliases: 'e'
|
@@ -14,13 +15,14 @@ module Lopata
|
|
14
15
|
option :keep, type: :boolean, aliases: 'k'
|
15
16
|
option :text, aliases: 't'
|
16
17
|
def test(*args)
|
18
|
+
trap_interrupt
|
17
19
|
configure_from_options
|
18
20
|
Lopata::Loader.load_shared_steps
|
19
21
|
Lopata::Loader.load_scenarios(*args)
|
20
22
|
world = Lopata.world
|
21
|
-
world.
|
23
|
+
world.notify_observers(:started, world)
|
22
24
|
world.scenarios.each { |s| s.run }
|
23
|
-
world.
|
25
|
+
world.notify_observers(:finished, world)
|
24
26
|
end
|
25
27
|
|
26
28
|
default_task :test
|
@@ -51,6 +53,10 @@ module Lopata
|
|
51
53
|
to_rerun = Lopata::Client.new.to_rerun
|
52
54
|
Lopata.configuration.filters << -> (scenario) { to_rerun.include?(scenario.title) }
|
53
55
|
end
|
56
|
+
|
57
|
+
def trap_interrupt
|
58
|
+
trap('INT') { exit!(1) }
|
59
|
+
end
|
54
60
|
end
|
55
61
|
end
|
56
62
|
end
|
data/lib/lopata/scenario.rb
CHANGED
@@ -1,25 +1,41 @@
|
|
1
1
|
require 'rspec/expectations'
|
2
2
|
|
3
|
+
# Scenario runtime class.
|
4
|
+
#
|
5
|
+
# All the scenarios are running in context of separate Lopata::Scenario object.
|
6
|
+
#
|
3
7
|
class Lopata::Scenario
|
4
8
|
include RSpec::Matchers
|
5
9
|
|
10
|
+
# @private
|
6
11
|
attr_reader :execution
|
7
12
|
|
13
|
+
# @private
|
8
14
|
def initialize(execution)
|
9
15
|
@execution = execution
|
10
16
|
end
|
11
17
|
|
12
18
|
# Marks current step as pending
|
19
|
+
# @example
|
20
|
+
# it 'pending step' do
|
21
|
+
# pending
|
22
|
+
# expect(1).to eq 2
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Pending steps wont be failed
|
13
26
|
def pending(message = nil)
|
14
27
|
execution.current_step.pending!(message)
|
15
28
|
end
|
16
29
|
|
30
|
+
# @return [Hash] metadata available for current step
|
31
|
+
# @note The metadata keys also availalbe as methods (via method_missing)
|
17
32
|
def metadata
|
18
33
|
execution.metadata
|
19
34
|
end
|
20
35
|
|
21
36
|
private
|
22
37
|
|
38
|
+
# @private
|
23
39
|
def method_missing(method, *args, &block)
|
24
40
|
if execution.let_methods.include?(method)
|
25
41
|
instance_exec(*args, &execution.let_methods[method])
|
@@ -30,10 +46,13 @@ class Lopata::Scenario
|
|
30
46
|
end
|
31
47
|
end
|
32
48
|
|
49
|
+
# @private
|
33
50
|
def respond_to_missing?(method, *)
|
34
51
|
execution.let_methods.include?(method) or metadata.keys.include?(method) or super
|
35
52
|
end
|
36
53
|
|
54
|
+
# @private
|
55
|
+
# Scenario execution and live-cycle information
|
37
56
|
class Execution
|
38
57
|
attr_reader :scenario, :status, :steps, :title, :current_step
|
39
58
|
|
@@ -1,19 +1,39 @@
|
|
1
|
+
# Context for scenario creation.
|
1
2
|
class Lopata::ScenarioBuilder
|
3
|
+
# @private
|
2
4
|
attr_reader :title, :common_metadata, :options, :diagonals
|
5
|
+
# @private
|
3
6
|
attr_accessor :shared_step, :group
|
4
7
|
|
8
|
+
# Defines one or more scenarios.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# Lopata.define 'scenario' do
|
12
|
+
# setup 'test user'
|
13
|
+
# action 'login'
|
14
|
+
# verify 'home page displayed'
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Given block will be calculated in context of the ScenarioBuilder
|
18
|
+
#
|
19
|
+
# @param title [String] scenario unique title
|
20
|
+
# @param metadata [Hash] metadata to be used within the scenario
|
21
|
+
# @param block [Block] the scenario definition
|
22
|
+
# @see Lopata.define
|
5
23
|
def self.define(title, metadata = {}, &block)
|
6
24
|
builder = new(title, metadata)
|
7
25
|
builder.instance_exec &block
|
8
26
|
builder.build
|
9
27
|
end
|
10
28
|
|
29
|
+
# @private
|
11
30
|
def initialize(title, metadata = {})
|
12
31
|
@title, @common_metadata = title, metadata
|
13
32
|
@diagonals = []
|
14
33
|
@options = []
|
15
34
|
end
|
16
35
|
|
36
|
+
# @private
|
17
37
|
def build
|
18
38
|
filters = Lopata.configuration.filters
|
19
39
|
option_combinations.each do |option_set|
|
@@ -33,21 +53,104 @@ class Lopata::ScenarioBuilder
|
|
33
53
|
end
|
34
54
|
end
|
35
55
|
|
56
|
+
# @!group Defining variants
|
57
|
+
|
58
|
+
# Define option for the scenario.
|
59
|
+
#
|
60
|
+
# The scenario will be generated for all the options.
|
61
|
+
# If more then one option given, the scenarios for all options combinations will be generated.
|
62
|
+
#
|
63
|
+
# @param metadata_key [Symbol] the key to access option data via metadata.
|
64
|
+
# @param variants [Hash{String => Object}] variants for the option
|
65
|
+
# Keys are titles of the variant, values are metadata values.
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# Lopata.define 'scenario' do
|
69
|
+
# option :one, 'one' => 1, 'two' => 2
|
70
|
+
# option :two, 'two' => 2, 'three' => 3
|
71
|
+
# # will generate 4 scenarios:
|
72
|
+
# # - 'scenario one two'
|
73
|
+
# # - 'scenario one three'
|
74
|
+
# # - 'scenario two two'
|
75
|
+
# # - 'scenario two three'
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# @see #diagonal
|
79
|
+
def option(metadata_key, variants)
|
80
|
+
@options << Option.new(metadata_key, variants)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Define diagonal for the scenario.
|
84
|
+
#
|
85
|
+
# The scenario will be generated for all the variants of the diagonal.
|
86
|
+
# Each variant of diagonal will be selected for at least one scenario.
|
87
|
+
# It may be included in more then one scenario when other diagonal or option has more variants.
|
88
|
+
#
|
89
|
+
# @param metadata_key [Symbol] the key to access diagonal data via metadata.
|
90
|
+
# @param variants [Hash{String => Object}] variants for the diagonal.
|
91
|
+
# Keys are titles of the variant, values are metadata values.
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# Lopata.define 'scenario' do
|
95
|
+
# option :one, 'one' => 1, 'two' => 2
|
96
|
+
# diagonal :two, 'two' => 2, 'three' => 3
|
97
|
+
# diagonal :three, 'three' => 3, 'four' => 4, 'five' => 5
|
98
|
+
# # will generate 3 scenarios:
|
99
|
+
# # - 'scenario one two three'
|
100
|
+
# # - 'scenario two three four'
|
101
|
+
# # - 'scenario one two five'
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# @see #option
|
105
|
+
def diagonal(metadata_key, variants)
|
106
|
+
@diagonals << Diagonal.new(metadata_key, variants)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Define additional metadata for the scenario
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# Lopata.define 'scenario' do
|
113
|
+
# metadata key: 'value'
|
114
|
+
# it 'metadata available' do
|
115
|
+
# expect(metadata[:key]).to eq 'value'
|
116
|
+
# end
|
117
|
+
# end
|
36
118
|
def metadata(hash)
|
37
119
|
raise 'metadata expected to be a Hash' unless hash.is_a?(Hash)
|
38
120
|
@common_metadata ||= {}
|
39
121
|
@common_metadata.merge! hash
|
40
122
|
end
|
41
123
|
|
124
|
+
# Skip scenario for given variants combination
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# Lopata.define 'multiple options' do
|
128
|
+
# option :one, 'one' => 1, 'two' => 2
|
129
|
+
# option :two, 'two' => 2, 'three' => 3
|
130
|
+
# skip_when { |opt| opt.metadata[:one] == opt.metadata[:two] }
|
131
|
+
# it 'not equal' do
|
132
|
+
# expect(one).to_not eq two
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
#
|
42
136
|
def skip_when(&block)
|
43
137
|
@skip_when = block
|
44
138
|
end
|
45
139
|
|
140
|
+
# @private
|
46
141
|
def skip?(option_set)
|
47
142
|
@skip_when && @skip_when.call(option_set)
|
48
143
|
end
|
49
144
|
|
50
|
-
|
145
|
+
# @!endgroup
|
146
|
+
|
147
|
+
# @!group Defining Steps
|
148
|
+
|
149
|
+
# @private
|
150
|
+
# @macro [attach] define_step_method
|
151
|
+
# @!scope instance
|
152
|
+
# @method $1
|
153
|
+
def self.define_step_method(name)
|
51
154
|
name_if = "%s_if" % name
|
52
155
|
name_unless = "%s_unless" % name
|
53
156
|
define_method name, ->(*args, **metadata, &block) { add_step(name, *args, metadata: metadata, &block) }
|
@@ -59,6 +162,124 @@ class Lopata::ScenarioBuilder
|
|
59
162
|
}
|
60
163
|
end
|
61
164
|
|
165
|
+
# Define setup step.
|
166
|
+
# @example
|
167
|
+
# setup do
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# # setup from named shared step
|
171
|
+
# setup 'create user'
|
172
|
+
#
|
173
|
+
# # setup with both shared step and code block
|
174
|
+
# setup 'create user' do
|
175
|
+
# @user.update(admin: true)
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
# Setup step used for set test data.
|
179
|
+
# @overload setup(*steps, &block)
|
180
|
+
# @param steps [Array<String, Symbol, Proc>] the steps to be runned as a part of setup.
|
181
|
+
# String - name of shared step to be called.
|
182
|
+
# Symbol - metadata key, referenced to shared step name.
|
183
|
+
# Proc - in-place step implementation.
|
184
|
+
# @param block [Block] The implementation of the step.
|
185
|
+
define_step_method :setup
|
186
|
+
|
187
|
+
# Define action step.
|
188
|
+
# @example
|
189
|
+
# action do
|
190
|
+
# end
|
191
|
+
#
|
192
|
+
# # action from named shared step
|
193
|
+
# action 'login'
|
194
|
+
#
|
195
|
+
# # setup with both shared step and code block
|
196
|
+
# action 'login', 'go dashboard' do
|
197
|
+
# @user.update(admin: true)
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# Action step is used for emulate user or external system action
|
201
|
+
#
|
202
|
+
# @overload action(*steps, &block)
|
203
|
+
# @param steps [Array<String, Symbol, Proc>] the steps to be runned as a part of action.
|
204
|
+
# String - name of shared step to be called.
|
205
|
+
# Symbol - metadata key, referenced to shared step name.
|
206
|
+
# Proc - in-place step implementation.
|
207
|
+
# @param block [Block] The implementation of the step.
|
208
|
+
define_step_method :action
|
209
|
+
|
210
|
+
# Define teardown step.
|
211
|
+
# @example
|
212
|
+
# setup { @user = User.create! }
|
213
|
+
# teardown { @user.destroy }
|
214
|
+
# Teardown step will be called at the end of scenario running.
|
215
|
+
# But it suggested to be decared right after setup or action step which require teardown.
|
216
|
+
#
|
217
|
+
# @overload teardown(*steps, &block)
|
218
|
+
# @param steps [Array<String, Symbol, Proc>] the steps to be runned as a part of teardown.
|
219
|
+
# String - name of shared step to be called.
|
220
|
+
# Symbol - metadata key, referenced to shared step name.
|
221
|
+
# Proc - in-place step implementation.
|
222
|
+
# @param block [Block] The implementation of the step.
|
223
|
+
define_step_method :teardown
|
224
|
+
|
225
|
+
# Define verify steps.
|
226
|
+
# @example
|
227
|
+
# verify 'home page displayed' # call shared step.
|
228
|
+
# Usually for validation shared steps inclusion
|
229
|
+
#
|
230
|
+
# @overload verify(*steps, &block)
|
231
|
+
# @param steps [Array<String, Symbol, Proc>] the steps to be runned as a part of verification.
|
232
|
+
# String - name of shared step to be called.
|
233
|
+
# Symbol - metadata key, referenced to shared step name.
|
234
|
+
# Proc - in-place step implementation.
|
235
|
+
# @param block [Block] The implementation of the step.
|
236
|
+
define_step_method :verify
|
237
|
+
|
238
|
+
# Define group of steps.
|
239
|
+
# The metadata for the group may be overriden
|
240
|
+
# @example
|
241
|
+
# context 'the task', task: :created do
|
242
|
+
# verify 'task setup'
|
243
|
+
# it 'created' do
|
244
|
+
# expect(metadata[:task]).to eq :created
|
245
|
+
# end
|
246
|
+
# end
|
247
|
+
# Teardown steps within group will be called at the end of the group, not scenario
|
248
|
+
# @overload context(title, **metadata, &block)
|
249
|
+
# @param title [String] context title
|
250
|
+
# @param metadata [Hash] the step additional metadata
|
251
|
+
# @param block [Block] The implementation of the step.
|
252
|
+
define_step_method :context
|
253
|
+
|
254
|
+
# Define single validation step.
|
255
|
+
# @example
|
256
|
+
# it 'works' do
|
257
|
+
# expect(1).to eq 1
|
258
|
+
# end
|
259
|
+
# @overload it(title, &block)
|
260
|
+
# @param title [String] validation title
|
261
|
+
# @param block [Block] The implementation of the step.
|
262
|
+
define_step_method :it
|
263
|
+
|
264
|
+
# Define runtime method for the scenario.
|
265
|
+
#
|
266
|
+
# @note
|
267
|
+
# The method to be called via #method_missing, so it wont override already defined methods.
|
268
|
+
#
|
269
|
+
# @example
|
270
|
+
# let(:square) { |num| num * num }
|
271
|
+
# it 'calculated' do
|
272
|
+
# expect(square(4)).to eq 16
|
273
|
+
# end
|
274
|
+
def let(method_name, &block)
|
275
|
+
steps << Lopata::Step.new(:let) do
|
276
|
+
execution.let(method_name, &block)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# @!endgroup
|
281
|
+
|
282
|
+
# @private
|
62
283
|
def add_step(method_name, *args, condition: nil, metadata: {}, &block)
|
63
284
|
step_class =
|
64
285
|
case method_name
|
@@ -71,10 +292,12 @@ class Lopata::ScenarioBuilder
|
|
71
292
|
steps << step
|
72
293
|
end
|
73
294
|
|
295
|
+
# @private
|
74
296
|
def steps
|
75
297
|
@steps ||= []
|
76
298
|
end
|
77
299
|
|
300
|
+
# @private
|
78
301
|
def steps_with_hooks
|
79
302
|
s = []
|
80
303
|
unless Lopata.configuration.before_scenario_steps.empty?
|
@@ -90,20 +313,7 @@ class Lopata::ScenarioBuilder
|
|
90
313
|
s
|
91
314
|
end
|
92
315
|
|
93
|
-
|
94
|
-
steps << Lopata::Step.new(:let) do
|
95
|
-
execution.let(method_name, &block)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def option(metadata_key, variants)
|
100
|
-
@options << Option.new(metadata_key, variants)
|
101
|
-
end
|
102
|
-
|
103
|
-
def diagonal(metadata_key, variants)
|
104
|
-
@diagonals << Diagonal.new(metadata_key, variants)
|
105
|
-
end
|
106
|
-
|
316
|
+
# @private
|
107
317
|
def option_combinations
|
108
318
|
combinations = combine([OptionSet.new], options + diagonals)
|
109
319
|
while !diagonals.all?(&:complete?)
|
@@ -112,6 +322,7 @@ class Lopata::ScenarioBuilder
|
|
112
322
|
combinations.reject { |option_set| skip?(option_set) }
|
113
323
|
end
|
114
324
|
|
325
|
+
# @private
|
115
326
|
def combine(source_combinations, rest_options)
|
116
327
|
return source_combinations if rest_options.empty?
|
117
328
|
combinations = []
|
@@ -124,40 +335,50 @@ class Lopata::ScenarioBuilder
|
|
124
335
|
combine(combinations, rest_options)
|
125
336
|
end
|
126
337
|
|
338
|
+
# @private
|
127
339
|
def world
|
128
340
|
Lopata.world
|
129
341
|
end
|
130
342
|
|
131
|
-
#
|
343
|
+
# Set of options for scenario
|
132
344
|
class OptionSet
|
345
|
+
# @private
|
133
346
|
attr_reader :variants
|
347
|
+
|
348
|
+
# @private
|
134
349
|
def initialize(*variants)
|
135
350
|
@variants = {}
|
136
351
|
variants.compact.each { |v| self << v }
|
137
352
|
end
|
138
353
|
|
354
|
+
# @private
|
139
355
|
def +(other_set)
|
140
356
|
self.class.new(*@variants.values).tap do |sum|
|
141
357
|
other_set.each { |v| sum << v }
|
142
358
|
end
|
143
359
|
end
|
144
360
|
|
361
|
+
# @private
|
145
362
|
def <<(variant)
|
146
363
|
@variants[variant.key] = variant
|
147
364
|
end
|
148
365
|
|
366
|
+
# @private
|
149
367
|
def [](key)
|
150
368
|
@variants[key]
|
151
369
|
end
|
152
370
|
|
371
|
+
# @private
|
153
372
|
def each(&block)
|
154
373
|
@variants.values.each(&block)
|
155
374
|
end
|
156
375
|
|
376
|
+
# @private
|
157
377
|
def title
|
158
378
|
@variants.values.map(&:title).compact.join(' ')
|
159
379
|
end
|
160
380
|
|
381
|
+
# @return [Hash{Symbol => Object}] metadata for this option set
|
161
382
|
def metadata
|
162
383
|
@variants.values.inject({}) do |metadata, variant|
|
163
384
|
metadata.merge(variant.metadata(self))
|
@@ -165,6 +386,7 @@ class Lopata::ScenarioBuilder
|
|
165
386
|
end
|
166
387
|
end
|
167
388
|
|
389
|
+
# @private
|
168
390
|
class Variant
|
169
391
|
attr_reader :key, :title, :value, :option
|
170
392
|
|
@@ -213,6 +435,7 @@ class Lopata::ScenarioBuilder
|
|
213
435
|
end
|
214
436
|
end
|
215
437
|
|
438
|
+
# @private
|
216
439
|
class CalculatedValue
|
217
440
|
def initialize(&block)
|
218
441
|
@proc = block
|
@@ -223,6 +446,7 @@ class Lopata::ScenarioBuilder
|
|
223
446
|
end
|
224
447
|
end
|
225
448
|
|
449
|
+
# @private
|
226
450
|
class Option
|
227
451
|
attr_reader :variants, :key
|
228
452
|
def initialize(key, variants)
|
@@ -258,6 +482,7 @@ class Lopata::ScenarioBuilder
|
|
258
482
|
end
|
259
483
|
end
|
260
484
|
|
485
|
+
# @private
|
261
486
|
class Diagonal < Option
|
262
487
|
def level_variants
|
263
488
|
[next_variant]
|
data/lib/lopata/shared_step.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
module Lopata
|
2
|
+
# @private
|
2
3
|
class SharedStep
|
3
4
|
attr_reader :name, :block
|
4
5
|
|
5
6
|
class NotFound < StandardError; end
|
6
7
|
|
8
|
+
|
7
9
|
def self.register(name, &block)
|
8
10
|
raise ArgumentError, "Comma is not allowed in shared step name: '%s'" % name if name =~ /,/
|
9
11
|
registry[name] = new(name, &block)
|
data/lib/lopata/step.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Lopata
|
2
|
+
# @private
|
2
3
|
class Step
|
3
4
|
attr_reader :block, :args, :condition, :method_name, :shared_step
|
4
5
|
# metadata overrien by the step.
|
@@ -26,7 +27,8 @@ module Lopata
|
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
#
|
30
|
+
# @private
|
31
|
+
# Used for action, setup, teardown, verify
|
30
32
|
class ActionStep < Step
|
31
33
|
def execution_steps(scenario, groups: [])
|
32
34
|
steps = []
|
@@ -66,6 +68,7 @@ module Lopata
|
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
71
|
+
# @private
|
69
72
|
# Used for context
|
70
73
|
class GroupStep < Step
|
71
74
|
|
@@ -94,6 +97,7 @@ module Lopata
|
|
94
97
|
end
|
95
98
|
end
|
96
99
|
|
100
|
+
#@private
|
97
101
|
class StepExecution
|
98
102
|
attr_reader :step, :status, :exception, :block, :pending_message, :groups
|
99
103
|
extend Forwardable
|
data/lib/lopata/version.rb
CHANGED
data/lib/lopata/world.rb
CHANGED
@@ -1,21 +1,15 @@
|
|
1
|
+
# Container for gobal non-configuration data
|
1
2
|
class Lopata::World
|
3
|
+
# Scenarios are selected for current run
|
4
|
+
# @return [Array<Lopata::Scenario::Execution>]
|
2
5
|
attr_reader :scenarios
|
3
6
|
|
7
|
+
# @private
|
4
8
|
def initialize
|
5
9
|
@scenarios = []
|
6
10
|
end
|
7
11
|
|
8
|
-
|
9
|
-
notify_observers(:started, self)
|
10
|
-
end
|
11
|
-
|
12
|
-
# Called at the end of test running.
|
13
|
-
#
|
14
|
-
# Notifies observers about testing finish
|
15
|
-
def finish
|
16
|
-
notify_observers(:finished, self)
|
17
|
-
end
|
18
|
-
|
12
|
+
# @private
|
19
13
|
def notify_observers(event, context)
|
20
14
|
observers.each do |observer|
|
21
15
|
observer.send event, context
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lopata
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Volochnev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -87,6 +87,7 @@ executables:
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
+
- ".yardopts"
|
90
91
|
- README.md
|
91
92
|
- exe/lopata
|
92
93
|
- lib/lopata.rb
|
@@ -137,5 +138,5 @@ requirements: []
|
|
137
138
|
rubygems_version: 3.0.3
|
138
139
|
signing_key:
|
139
140
|
specification_version: 4
|
140
|
-
summary: lopata-0.1.
|
141
|
+
summary: lopata-0.1.7
|
141
142
|
test_files: []
|