lopata 0.1.13 → 0.1.14
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/README.md +25 -25
- data/exe/lopata +11 -11
- data/lib/lopata.rb +74 -74
- data/lib/lopata/active_record.rb +135 -135
- data/lib/lopata/condition.rb +30 -30
- data/lib/lopata/configuration.rb +125 -125
- data/lib/lopata/environment.rb +35 -35
- data/lib/lopata/factory_bot.rb +72 -72
- data/lib/lopata/generators/app.rb +42 -42
- data/lib/lopata/generators/templates/Gemfile +7 -7
- data/lib/lopata/generators/templates/Lopatafile +20 -20
- data/lib/lopata/generators/templates/config/environments/qa.yml +7 -7
- data/lib/lopata/generators/templates/config/initializers/capybara.rb +1 -1
- data/lib/lopata/id.rb +22 -22
- data/lib/lopata/loader.rb +31 -31
- data/lib/lopata/observers.rb +4 -4
- data/lib/lopata/observers/backtrace_formatter.rb +103 -103
- data/lib/lopata/observers/base_observer.rb +33 -33
- data/lib/lopata/observers/console_output_observer.rb +100 -100
- data/lib/lopata/observers/web_logger.rb +130 -130
- data/lib/lopata/role.rb +109 -109
- data/lib/lopata/runner.rb +67 -67
- data/lib/lopata/scenario.rb +136 -136
- data/lib/lopata/scenario_builder.rb +497 -497
- data/lib/lopata/shared_step.rb +38 -38
- data/lib/lopata/step.rb +191 -191
- data/lib/lopata/version.rb +6 -6
- data/lib/lopata/world.rb +24 -24
- metadata +4 -4
data/lib/lopata/shared_step.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
module Lopata
|
2
|
-
# @private
|
3
|
-
class SharedStep
|
4
|
-
attr_reader :name, :block
|
5
|
-
|
6
|
-
class NotFound < StandardError; end
|
7
|
-
|
8
|
-
|
9
|
-
def self.register(name, &block)
|
10
|
-
raise ArgumentError, "Comma is not allowed in shared step name: '%s'" % name if name =~ /,/
|
11
|
-
registry[name] = new(name, &block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.find(name)
|
15
|
-
registry[name] or raise NotFound, "Shared step '%s' not found" % name
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize(name, &block)
|
19
|
-
@name, @block = name, block
|
20
|
-
end
|
21
|
-
|
22
|
-
def steps
|
23
|
-
@steps ||= build_steps
|
24
|
-
end
|
25
|
-
|
26
|
-
def build_steps
|
27
|
-
builder = Lopata::ScenarioBuilder.new(name)
|
28
|
-
builder.shared_step = self
|
29
|
-
builder.instance_exec(&block)
|
30
|
-
builder.steps
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def self.registry
|
36
|
-
@shared_steps ||= {}
|
37
|
-
end
|
38
|
-
end
|
1
|
+
module Lopata
|
2
|
+
# @private
|
3
|
+
class SharedStep
|
4
|
+
attr_reader :name, :block
|
5
|
+
|
6
|
+
class NotFound < StandardError; end
|
7
|
+
|
8
|
+
|
9
|
+
def self.register(name, &block)
|
10
|
+
raise ArgumentError, "Comma is not allowed in shared step name: '%s'" % name if name =~ /,/
|
11
|
+
registry[name] = new(name, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.find(name)
|
15
|
+
registry[name] or raise NotFound, "Shared step '%s' not found" % name
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(name, &block)
|
19
|
+
@name, @block = name, block
|
20
|
+
end
|
21
|
+
|
22
|
+
def steps
|
23
|
+
@steps ||= build_steps
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_steps
|
27
|
+
builder = Lopata::ScenarioBuilder.new(name)
|
28
|
+
builder.shared_step = self
|
29
|
+
builder.instance_exec(&block)
|
30
|
+
builder.steps
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def self.registry
|
36
|
+
@shared_steps ||= {}
|
37
|
+
end
|
38
|
+
end
|
39
39
|
end
|
data/lib/lopata/step.rb
CHANGED
@@ -1,191 +1,191 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
|
-
module Lopata
|
4
|
-
# @private
|
5
|
-
class Step
|
6
|
-
attr_reader :block, :args, :condition, :method_name, :shared_step
|
7
|
-
# metadata overrien by the step.
|
8
|
-
attr_accessor :metadata
|
9
|
-
|
10
|
-
def initialize(method_name, *args, condition: nil, shared_step: nil, &block)
|
11
|
-
@method_name = method_name
|
12
|
-
@args = args
|
13
|
-
@block = block
|
14
|
-
@shared_step = shared_step
|
15
|
-
@condition = condition
|
16
|
-
initialized! if defined? initialized!
|
17
|
-
end
|
18
|
-
|
19
|
-
def title
|
20
|
-
base_title = args.first
|
21
|
-
base_title ||= shared_step && "#{method_name.capitalize} #{shared_step.name}" || "Untitled #{method_name}"
|
22
|
-
base_title
|
23
|
-
end
|
24
|
-
|
25
|
-
def execution_steps(scenario, groups: [])
|
26
|
-
return [] if condition && !condition.match?(scenario)
|
27
|
-
return [] unless block
|
28
|
-
[StepExecution.new(self, groups, &block)]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# @private
|
33
|
-
# Used for action, setup, teardown, verify
|
34
|
-
class ActionStep < Step
|
35
|
-
def execution_steps(scenario, groups: [])
|
36
|
-
steps = []
|
37
|
-
return steps if condition && !condition.match?(scenario)
|
38
|
-
convert_args(scenario).each do |step|
|
39
|
-
if step.is_a?(String)
|
40
|
-
Lopata::SharedStep.find(step).steps.each do |shared_step|
|
41
|
-
next if shared_step.condition && !shared_step.condition.match?(scenario)
|
42
|
-
steps += shared_step.execution_steps(scenario, groups: groups)
|
43
|
-
end
|
44
|
-
elsif step.is_a?(Proc)
|
45
|
-
steps << StepExecution.new(self, groups, &step)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
steps << StepExecution.new(self, groups, &block) if block
|
49
|
-
steps.reject { |s| !s.block }
|
50
|
-
end
|
51
|
-
|
52
|
-
def separate_args(args)
|
53
|
-
args.map { |a| a.is_a?(String) && a =~ /,/ ? a.split(',').map(&:strip) : a }.flatten
|
54
|
-
end
|
55
|
-
|
56
|
-
def convert_args(scenario)
|
57
|
-
flat_args = separate_args(args.flatten)
|
58
|
-
flat_args.map do |arg|
|
59
|
-
case arg
|
60
|
-
# trait symbols as link to metadata.
|
61
|
-
when Symbol then scenario.metadata[arg]
|
62
|
-
else
|
63
|
-
arg
|
64
|
-
end
|
65
|
-
end.flatten
|
66
|
-
end
|
67
|
-
|
68
|
-
def title
|
69
|
-
shared_step && "#{method_name.capitalize} #{shared_step.name}" || "Untitled #{method_name}"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# @private
|
74
|
-
# Used for context
|
75
|
-
class GroupStep < Step
|
76
|
-
|
77
|
-
def execution_steps(scenario, groups: [])
|
78
|
-
steps = []
|
79
|
-
return steps if condition && !condition.match?(scenario)
|
80
|
-
@steps.each do |step|
|
81
|
-
steps += step.execution_steps(scenario, groups: groups + [self])
|
82
|
-
end
|
83
|
-
steps.reject! { |s| !s.block }
|
84
|
-
steps.reject { |s| s.teardown_group?(self) } + steps.select { |s| s.teardown_group?(self) }
|
85
|
-
end
|
86
|
-
|
87
|
-
def let_methods
|
88
|
-
@let_methods ||= {}
|
89
|
-
end
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
# Group step's block is a block in context of builder, not scenario. So hide the @block to not be used in scenario.
|
94
|
-
def initialized!
|
95
|
-
builder = Lopata::ScenarioBuilder.new(title)
|
96
|
-
builder.instance_exec(&@block)
|
97
|
-
@steps = builder.steps
|
98
|
-
@block = nil
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
#@private
|
103
|
-
class StepExecution
|
104
|
-
attr_reader :step, :status, :exception, :block, :pending_message, :groups
|
105
|
-
extend Forwardable
|
106
|
-
def_delegators :step, :method_name
|
107
|
-
|
108
|
-
class PendingStepFixedError < StandardError; end
|
109
|
-
|
110
|
-
def initialize(step, groups, &block)
|
111
|
-
@step = step
|
112
|
-
@status = :not_runned
|
113
|
-
@exception = nil
|
114
|
-
@block = block
|
115
|
-
@groups = groups
|
116
|
-
end
|
117
|
-
|
118
|
-
def title
|
119
|
-
group_title = groups.map { |g| "#{g.title}: " }.join
|
120
|
-
"#{group_title}#{step.title}"
|
121
|
-
end
|
122
|
-
|
123
|
-
def run(scenario)
|
124
|
-
@status = :running
|
125
|
-
begin
|
126
|
-
run_step(scenario)
|
127
|
-
if pending?
|
128
|
-
@status = :failed
|
129
|
-
raise PendingStepFixedError, 'Expected step to fail since it is pending, but it passed.'
|
130
|
-
else
|
131
|
-
@status = :passed
|
132
|
-
end
|
133
|
-
rescue Exception => e
|
134
|
-
@status = :failed unless pending?
|
135
|
-
@exception = e
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def run_step(scenario)
|
140
|
-
return unless block
|
141
|
-
scenario.instance_exec(&block)
|
142
|
-
end
|
143
|
-
|
144
|
-
def failed?
|
145
|
-
status == :failed
|
146
|
-
end
|
147
|
-
|
148
|
-
def passed?
|
149
|
-
status == :passed
|
150
|
-
end
|
151
|
-
|
152
|
-
def skipped?
|
153
|
-
status == :skipped
|
154
|
-
end
|
155
|
-
|
156
|
-
def skip!
|
157
|
-
@status = :skipped
|
158
|
-
end
|
159
|
-
|
160
|
-
def pending?
|
161
|
-
status == :pending
|
162
|
-
end
|
163
|
-
|
164
|
-
def pending!(message = nil)
|
165
|
-
@status = :pending
|
166
|
-
@pending_message = message
|
167
|
-
end
|
168
|
-
|
169
|
-
def teardown?
|
170
|
-
%i{ teardown cleanup }.include?(method_name)
|
171
|
-
end
|
172
|
-
|
173
|
-
def teardown_group?(group = nil)
|
174
|
-
teardown? && self.groups.last == group
|
175
|
-
end
|
176
|
-
|
177
|
-
def skip_rest_on_failure?
|
178
|
-
%i{ setup action }.include?(method_name)
|
179
|
-
end
|
180
|
-
|
181
|
-
# Step metadata is a combination of metadata given for step and all contexts (groups) the step included
|
182
|
-
def metadata
|
183
|
-
(groups + [step]).compact.inject({}) { |merged, part| merged.merge(part.metadata) }
|
184
|
-
end
|
185
|
-
|
186
|
-
# Step methods is a combination of let_methods for all contexts (group) the step included
|
187
|
-
def let_methods
|
188
|
-
(groups).compact.inject({}) { |merged, part| merged.merge(part.let_methods) }
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Lopata
|
4
|
+
# @private
|
5
|
+
class Step
|
6
|
+
attr_reader :block, :args, :condition, :method_name, :shared_step
|
7
|
+
# metadata overrien by the step.
|
8
|
+
attr_accessor :metadata
|
9
|
+
|
10
|
+
def initialize(method_name, *args, condition: nil, shared_step: nil, &block)
|
11
|
+
@method_name = method_name
|
12
|
+
@args = args
|
13
|
+
@block = block
|
14
|
+
@shared_step = shared_step
|
15
|
+
@condition = condition
|
16
|
+
initialized! if defined? initialized!
|
17
|
+
end
|
18
|
+
|
19
|
+
def title
|
20
|
+
base_title = args.first
|
21
|
+
base_title ||= shared_step && "#{method_name.capitalize} #{shared_step.name}" || "Untitled #{method_name}"
|
22
|
+
base_title
|
23
|
+
end
|
24
|
+
|
25
|
+
def execution_steps(scenario, groups: [])
|
26
|
+
return [] if condition && !condition.match?(scenario)
|
27
|
+
return [] unless block
|
28
|
+
[StepExecution.new(self, groups, &block)]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @private
|
33
|
+
# Used for action, setup, teardown, verify
|
34
|
+
class ActionStep < Step
|
35
|
+
def execution_steps(scenario, groups: [])
|
36
|
+
steps = []
|
37
|
+
return steps if condition && !condition.match?(scenario)
|
38
|
+
convert_args(scenario).each do |step|
|
39
|
+
if step.is_a?(String)
|
40
|
+
Lopata::SharedStep.find(step).steps.each do |shared_step|
|
41
|
+
next if shared_step.condition && !shared_step.condition.match?(scenario)
|
42
|
+
steps += shared_step.execution_steps(scenario, groups: groups)
|
43
|
+
end
|
44
|
+
elsif step.is_a?(Proc)
|
45
|
+
steps << StepExecution.new(self, groups, &step)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
steps << StepExecution.new(self, groups, &block) if block
|
49
|
+
steps.reject { |s| !s.block }
|
50
|
+
end
|
51
|
+
|
52
|
+
def separate_args(args)
|
53
|
+
args.map { |a| a.is_a?(String) && a =~ /,/ ? a.split(',').map(&:strip) : a }.flatten
|
54
|
+
end
|
55
|
+
|
56
|
+
def convert_args(scenario)
|
57
|
+
flat_args = separate_args(args.flatten)
|
58
|
+
flat_args.map do |arg|
|
59
|
+
case arg
|
60
|
+
# trait symbols as link to metadata.
|
61
|
+
when Symbol then scenario.metadata[arg]
|
62
|
+
else
|
63
|
+
arg
|
64
|
+
end
|
65
|
+
end.flatten
|
66
|
+
end
|
67
|
+
|
68
|
+
def title
|
69
|
+
shared_step && "#{method_name.capitalize} #{shared_step.name}" || "Untitled #{method_name}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @private
|
74
|
+
# Used for context
|
75
|
+
class GroupStep < Step
|
76
|
+
|
77
|
+
def execution_steps(scenario, groups: [])
|
78
|
+
steps = []
|
79
|
+
return steps if condition && !condition.match?(scenario)
|
80
|
+
@steps.each do |step|
|
81
|
+
steps += step.execution_steps(scenario, groups: groups + [self])
|
82
|
+
end
|
83
|
+
steps.reject! { |s| !s.block }
|
84
|
+
steps.reject { |s| s.teardown_group?(self) } + steps.select { |s| s.teardown_group?(self) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def let_methods
|
88
|
+
@let_methods ||= {}
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# Group step's block is a block in context of builder, not scenario. So hide the @block to not be used in scenario.
|
94
|
+
def initialized!
|
95
|
+
builder = Lopata::ScenarioBuilder.new(title)
|
96
|
+
builder.instance_exec(&@block)
|
97
|
+
@steps = builder.steps
|
98
|
+
@block = nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#@private
|
103
|
+
class StepExecution
|
104
|
+
attr_reader :step, :status, :exception, :block, :pending_message, :groups
|
105
|
+
extend Forwardable
|
106
|
+
def_delegators :step, :method_name
|
107
|
+
|
108
|
+
class PendingStepFixedError < StandardError; end
|
109
|
+
|
110
|
+
def initialize(step, groups, &block)
|
111
|
+
@step = step
|
112
|
+
@status = :not_runned
|
113
|
+
@exception = nil
|
114
|
+
@block = block
|
115
|
+
@groups = groups
|
116
|
+
end
|
117
|
+
|
118
|
+
def title
|
119
|
+
group_title = groups.map { |g| "#{g.title}: " }.join
|
120
|
+
"#{group_title}#{step.title}"
|
121
|
+
end
|
122
|
+
|
123
|
+
def run(scenario)
|
124
|
+
@status = :running
|
125
|
+
begin
|
126
|
+
run_step(scenario)
|
127
|
+
if pending?
|
128
|
+
@status = :failed
|
129
|
+
raise PendingStepFixedError, 'Expected step to fail since it is pending, but it passed.'
|
130
|
+
else
|
131
|
+
@status = :passed
|
132
|
+
end
|
133
|
+
rescue Exception => e
|
134
|
+
@status = :failed unless pending?
|
135
|
+
@exception = e
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def run_step(scenario)
|
140
|
+
return unless block
|
141
|
+
scenario.instance_exec(&block)
|
142
|
+
end
|
143
|
+
|
144
|
+
def failed?
|
145
|
+
status == :failed
|
146
|
+
end
|
147
|
+
|
148
|
+
def passed?
|
149
|
+
status == :passed
|
150
|
+
end
|
151
|
+
|
152
|
+
def skipped?
|
153
|
+
status == :skipped
|
154
|
+
end
|
155
|
+
|
156
|
+
def skip!
|
157
|
+
@status = :skipped
|
158
|
+
end
|
159
|
+
|
160
|
+
def pending?
|
161
|
+
status == :pending
|
162
|
+
end
|
163
|
+
|
164
|
+
def pending!(message = nil)
|
165
|
+
@status = :pending
|
166
|
+
@pending_message = message
|
167
|
+
end
|
168
|
+
|
169
|
+
def teardown?
|
170
|
+
%i{ teardown cleanup }.include?(method_name)
|
171
|
+
end
|
172
|
+
|
173
|
+
def teardown_group?(group = nil)
|
174
|
+
teardown? && self.groups.last == group
|
175
|
+
end
|
176
|
+
|
177
|
+
def skip_rest_on_failure?
|
178
|
+
%i{ setup action }.include?(method_name)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Step metadata is a combination of metadata given for step and all contexts (groups) the step included
|
182
|
+
def metadata
|
183
|
+
(groups + [step]).compact.inject({}) { |merged, part| merged.merge(part.metadata) }
|
184
|
+
end
|
185
|
+
|
186
|
+
# Step methods is a combination of let_methods for all contexts (group) the step included
|
187
|
+
def let_methods
|
188
|
+
(groups).compact.inject({}) { |merged, part| merged.merge(part.let_methods) }
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|