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
@@ -1,43 +1,43 @@
|
|
1
|
-
module Lopata
|
2
|
-
# @private
|
3
|
-
module Generators
|
4
|
-
# @private
|
5
|
-
class App < Thor::Group
|
6
|
-
include Thor::Actions
|
7
|
-
argument :name
|
8
|
-
|
9
|
-
def self.source_root
|
10
|
-
File.join(File.dirname(__FILE__), 'templates')
|
11
|
-
end
|
12
|
-
|
13
|
-
def create_root_files
|
14
|
-
template 'Lopatafile', "#{name}/Lopatafile"
|
15
|
-
template 'Gemfile', "#{name}/Gemfile"
|
16
|
-
template 'config/environments/qa.yml', "#{name}/config/environments/qa.yml"
|
17
|
-
template 'config/initializers/capybara.rb', "#{name}/config/initializers/capybara.rb"
|
18
|
-
end
|
19
|
-
|
20
|
-
def init_dirs
|
21
|
-
%w{models services pages}.each do |dir|
|
22
|
-
empty_directory "#{name}/app/#{dir}"
|
23
|
-
end
|
24
|
-
|
25
|
-
%w{scenarios shared_steps config/initializers}.each do |dir|
|
26
|
-
empty_directory "#{name}/#{dir}"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def bundle
|
31
|
-
Dir.chdir name do
|
32
|
-
_bundle_command = Gem.bin_path('bundler', 'bundle')
|
33
|
-
|
34
|
-
require 'bundler'
|
35
|
-
Bundler.with_clean_env do
|
36
|
-
output = `"#{Gem.ruby}" "#{_bundle_command}"`
|
37
|
-
print output # unless options[:quiet]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
1
|
+
module Lopata
|
2
|
+
# @private
|
3
|
+
module Generators
|
4
|
+
# @private
|
5
|
+
class App < Thor::Group
|
6
|
+
include Thor::Actions
|
7
|
+
argument :name
|
8
|
+
|
9
|
+
def self.source_root
|
10
|
+
File.join(File.dirname(__FILE__), 'templates')
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_root_files
|
14
|
+
template 'Lopatafile', "#{name}/Lopatafile"
|
15
|
+
template 'Gemfile', "#{name}/Gemfile"
|
16
|
+
template 'config/environments/qa.yml', "#{name}/config/environments/qa.yml"
|
17
|
+
template 'config/initializers/capybara.rb', "#{name}/config/initializers/capybara.rb"
|
18
|
+
end
|
19
|
+
|
20
|
+
def init_dirs
|
21
|
+
%w{models services pages}.each do |dir|
|
22
|
+
empty_directory "#{name}/app/#{dir}"
|
23
|
+
end
|
24
|
+
|
25
|
+
%w{scenarios shared_steps config/initializers}.each do |dir|
|
26
|
+
empty_directory "#{name}/#{dir}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def bundle
|
31
|
+
Dir.chdir name do
|
32
|
+
_bundle_command = Gem.bin_path('bundler', 'bundle')
|
33
|
+
|
34
|
+
require 'bundler'
|
35
|
+
Bundler.with_clean_env do
|
36
|
+
output = `"#{Gem.ruby}" "#{_bundle_command}"`
|
37
|
+
print output # unless options[:quiet]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
43
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
gem 'selenium-webdriver'
|
3
|
-
gem 'activerecord', '~> 6.0.2'
|
4
|
-
gem 'capybara', '~> 3.11.1'
|
5
|
-
gem 'thor'
|
6
|
-
<% require "lopata/version" %>
|
7
|
-
gem 'lopata', '<%= Lopata::Version::STRING %>'
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
gem 'selenium-webdriver'
|
3
|
+
gem 'activerecord', '~> 6.0.2'
|
4
|
+
gem 'capybara', '~> 3.11.1'
|
5
|
+
gem 'thor'
|
6
|
+
<% require "lopata/version" %>
|
7
|
+
gem 'lopata', '<%= Lopata::Version::STRING %>'
|
@@ -1,20 +1,20 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
Encoding.default_external = Encoding::UTF_8
|
3
|
-
Encoding.default_internal = Encoding::UTF_8
|
4
|
-
|
5
|
-
require 'rubygems'
|
6
|
-
require 'bundler/setup'
|
7
|
-
require 'active_support/all'
|
8
|
-
require 'capybara'
|
9
|
-
require 'capybara/dsl'
|
10
|
-
require 'selenium/webdriver'
|
11
|
-
require 'fileutils'
|
12
|
-
require 'active_support'
|
13
|
-
require 'active_record'
|
14
|
-
require 'lopata'
|
15
|
-
|
16
|
-
relative_load_paths = %w[app/pages app/services app/models]
|
17
|
-
ActiveSupport::Dependencies.autoload_paths += relative_load_paths
|
18
|
-
|
19
|
-
Dir["./config/initializers/*.rb"].each { |f| require f }
|
20
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
Encoding.default_external = Encoding::UTF_8
|
3
|
+
Encoding.default_internal = Encoding::UTF_8
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'bundler/setup'
|
7
|
+
require 'active_support/all'
|
8
|
+
require 'capybara'
|
9
|
+
require 'capybara/dsl'
|
10
|
+
require 'selenium/webdriver'
|
11
|
+
require 'fileutils'
|
12
|
+
require 'active_support'
|
13
|
+
require 'active_record'
|
14
|
+
require 'lopata'
|
15
|
+
|
16
|
+
relative_load_paths = %w[app/pages app/services app/models]
|
17
|
+
ActiveSupport::Dependencies.autoload_paths += relative_load_paths
|
18
|
+
|
19
|
+
Dir["./config/initializers/*.rb"].each { |f| require f }
|
20
|
+
|
@@ -1,7 +1,7 @@
|
|
1
|
-
url: http://yourapp.com
|
2
|
-
# db:
|
3
|
-
# adapter: postgresql
|
4
|
-
# host: localhost
|
5
|
-
# username: username
|
6
|
-
# password: password
|
7
|
-
# database: database
|
1
|
+
url: http://yourapp.com
|
2
|
+
# db:
|
3
|
+
# adapter: postgresql
|
4
|
+
# host: localhost
|
5
|
+
# username: username
|
6
|
+
# password: password
|
7
|
+
# database: database
|
@@ -1 +1 @@
|
|
1
|
-
Capybara.default_driver = :selenium if defined? Capybara
|
1
|
+
Capybara.default_driver = :selenium if defined? Capybara
|
data/lib/lopata/id.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
module Lopata
|
2
|
-
# @private
|
3
|
-
module Id
|
4
|
-
extend self
|
5
|
-
|
6
|
-
def next(prefix = nil)
|
7
|
-
id = "%d_%d" % [timestamp, seq_num]
|
8
|
-
id = "%s_%s" % [prefix, id] if prefix
|
9
|
-
id
|
10
|
-
end
|
11
|
-
|
12
|
-
def timestamp
|
13
|
-
@timestamp ||= Time.now.strftime("%Y%m%d%H%M%S")
|
14
|
-
end
|
15
|
-
|
16
|
-
def seq_num
|
17
|
-
@seq_num ||= 0
|
18
|
-
@seq_num += 1
|
19
|
-
@seq_num
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
1
|
+
module Lopata
|
2
|
+
# @private
|
3
|
+
module Id
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def next(prefix = nil)
|
7
|
+
id = "%d_%d" % [timestamp, seq_num]
|
8
|
+
id = "%s_%s" % [prefix, id] if prefix
|
9
|
+
id
|
10
|
+
end
|
11
|
+
|
12
|
+
def timestamp
|
13
|
+
@timestamp ||= Time.now.strftime("%Y%m%d%H%M%S")
|
14
|
+
end
|
15
|
+
|
16
|
+
def seq_num
|
17
|
+
@seq_num ||= 0
|
18
|
+
@seq_num += 1
|
19
|
+
@seq_num
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/lopata/loader.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
|
-
# @private
|
2
|
-
module Lopata::Loader
|
3
|
-
extend self
|
4
|
-
|
5
|
-
# Loads scenarios for running in current session
|
6
|
-
#
|
7
|
-
# @param args [Array<String>] files to be load.
|
8
|
-
# Mask (e. g. 'scenarios/**/*.rb') is can be passed as well.
|
9
|
-
# All files from default location to be loaded if empty.
|
10
|
-
def load_scenarios(*args)
|
11
|
-
if args.empty?
|
12
|
-
load_all_scenarios
|
13
|
-
else
|
14
|
-
args.each(&method(:load_by_mask))
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Loads all scenarios from predefined paths
|
19
|
-
def load_all_scenarios
|
20
|
-
load_by_mask "scenarios/**/*.rb"
|
21
|
-
end
|
22
|
-
|
23
|
-
# Loads all shared steps from predefined paths
|
24
|
-
def load_shared_steps
|
25
|
-
load_by_mask "shared_steps/**/*rb"
|
26
|
-
end
|
27
|
-
|
28
|
-
# @private
|
29
|
-
def load_by_mask(mask)
|
30
|
-
Dir[mask].each { |f| load File.expand_path(f) }
|
31
|
-
end
|
1
|
+
# @private
|
2
|
+
module Lopata::Loader
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# Loads scenarios for running in current session
|
6
|
+
#
|
7
|
+
# @param args [Array<String>] files to be load.
|
8
|
+
# Mask (e. g. 'scenarios/**/*.rb') is can be passed as well.
|
9
|
+
# All files from default location to be loaded if empty.
|
10
|
+
def load_scenarios(*args)
|
11
|
+
if args.empty?
|
12
|
+
load_all_scenarios
|
13
|
+
else
|
14
|
+
args.each(&method(:load_by_mask))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Loads all scenarios from predefined paths
|
19
|
+
def load_all_scenarios
|
20
|
+
load_by_mask "scenarios/**/*.rb"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Loads all shared steps from predefined paths
|
24
|
+
def load_shared_steps
|
25
|
+
load_by_mask "shared_steps/**/*rb"
|
26
|
+
end
|
27
|
+
|
28
|
+
# @private
|
29
|
+
def load_by_mask(mask)
|
30
|
+
Dir[mask].each { |f| load File.expand_path(f) }
|
31
|
+
end
|
32
32
|
end
|
data/lib/lopata/observers.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# @private
|
2
|
-
module Lopata::Observers
|
3
|
-
autoload :BaseObserver, 'lopata/observers/base_observer.rb'
|
4
|
-
autoload :ConsoleOutputObserver, 'lopata/observers/console_output_observer.rb'
|
1
|
+
# @private
|
2
|
+
module Lopata::Observers
|
3
|
+
autoload :BaseObserver, 'lopata/observers/base_observer.rb'
|
4
|
+
autoload :ConsoleOutputObserver, 'lopata/observers/console_output_observer.rb'
|
5
5
|
end
|
@@ -1,103 +1,103 @@
|
|
1
|
-
module Lopata
|
2
|
-
module Observers
|
3
|
-
# @private
|
4
|
-
# Based on RSpec::Core::BacktraceFormatter
|
5
|
-
#
|
6
|
-
# Provides ability to format backtrace and find source code by file and line number.
|
7
|
-
class BacktraceFormatter
|
8
|
-
# @private
|
9
|
-
attr_accessor :exclusion_patterns, :inclusion_patterns
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
patterns = %w[ /lib\d*/ruby/ bin/ exe/lopata /lib/bundler/ /exe/bundle /\.rvm/ ]
|
13
|
-
patterns.map! { |s| Regexp.new(s.gsub("/", File::SEPARATOR)) }
|
14
|
-
|
15
|
-
@exclusion_patterns = [Regexp.union(*patterns)]
|
16
|
-
@inclusion_patterns = []
|
17
|
-
|
18
|
-
inclusion_patterns << Regexp.new(Dir.getwd)
|
19
|
-
end
|
20
|
-
|
21
|
-
# Filter backtrace.
|
22
|
-
#
|
23
|
-
# @param backtrace [Array<String>] exception backtrace
|
24
|
-
# @return [Array<String>] backtrace lines except ruby libraries, gems and executable files.
|
25
|
-
def format(backtrace)
|
26
|
-
return [] unless backtrace
|
27
|
-
return backtrace if backtrace.empty?
|
28
|
-
|
29
|
-
backtrace.map { |l| backtrace_line(l) }.compact.
|
30
|
-
tap do |filtered|
|
31
|
-
if filtered.empty?
|
32
|
-
filtered.concat backtrace
|
33
|
-
filtered << ""
|
34
|
-
filtered << " Showing full backtrace because every line was filtered out."
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
# Extracts error message from excetion
|
41
|
-
#
|
42
|
-
# @param exception [Exception]
|
43
|
-
# @param include_backtrace [Boolean] whether to add formatted backtrace to output
|
44
|
-
# @return [String] error message from excetion, incuding source code line.
|
45
|
-
def error_message(exception, include_backtrace: false)
|
46
|
-
backtrace = format(exception.backtrace)
|
47
|
-
source_line = extract_source_line(backtrace.first)
|
48
|
-
msg = ''
|
49
|
-
msg << "\n#{source_line}\n" if source_line
|
50
|
-
msg << "#{exception.class.name}: " unless exception.class.name =~ /RSpec/
|
51
|
-
msg << exception.message if exception.message
|
52
|
-
msg << "\n#{backtrace.join("\n")}\n" if include_backtrace
|
53
|
-
msg
|
54
|
-
end
|
55
|
-
|
56
|
-
def extract_source_line(backtrace_line)
|
57
|
-
file_and_line_number = backtrace_line.match(/(.+?):(\d+)(|:\d+)/)
|
58
|
-
return nil unless file_and_line_number
|
59
|
-
file_path, line_number = file_and_line_number[1..2]
|
60
|
-
return nil unless File.exist?(file_path)
|
61
|
-
lines = File.read(file_path).split("\n")
|
62
|
-
lines[line_number.to_i - 1]
|
63
|
-
end
|
64
|
-
|
65
|
-
def backtrace_line(line)
|
66
|
-
relative_path(line) unless exclude?(line)
|
67
|
-
end
|
68
|
-
|
69
|
-
def exclude?(line)
|
70
|
-
matches?(exclusion_patterns, line) && !matches?(inclusion_patterns, line)
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def matches?(patterns, line)
|
76
|
-
patterns.any? { |p| line =~ p }
|
77
|
-
end
|
78
|
-
|
79
|
-
# Matches strings either at the beginning of the input or prefixed with a
|
80
|
-
# whitespace, containing the current path, either postfixed with the
|
81
|
-
# separator, or at the end of the string. Match groups are the character
|
82
|
-
# before and the character after the string if any.
|
83
|
-
#
|
84
|
-
# http://rubular.com/r/fT0gmX6VJX
|
85
|
-
# http://rubular.com/r/duOrD4i3wb
|
86
|
-
# http://rubular.com/r/sbAMHFrOx1
|
87
|
-
def relative_path_regex
|
88
|
-
@relative_path_regex ||= /(\A|\s)#{File.expand_path('.')}(#{File::SEPARATOR}|\s|\Z)/
|
89
|
-
end
|
90
|
-
|
91
|
-
# @param line [String] current code line
|
92
|
-
# @return [String] relative path to line
|
93
|
-
def relative_path(line)
|
94
|
-
line = line.sub(relative_path_regex, "\\1.\\2".freeze)
|
95
|
-
line = line.sub(/\A([^:]+:\d+)$/, '\\1'.freeze)
|
96
|
-
return nil if line == '-e:1'.freeze
|
97
|
-
line
|
98
|
-
rescue SecurityError
|
99
|
-
nil
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
1
|
+
module Lopata
|
2
|
+
module Observers
|
3
|
+
# @private
|
4
|
+
# Based on RSpec::Core::BacktraceFormatter
|
5
|
+
#
|
6
|
+
# Provides ability to format backtrace and find source code by file and line number.
|
7
|
+
class BacktraceFormatter
|
8
|
+
# @private
|
9
|
+
attr_accessor :exclusion_patterns, :inclusion_patterns
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
patterns = %w[ /lib\d*/ruby/ bin/ exe/lopata /lib/bundler/ /exe/bundle /\.rvm/ /rvm/ ]
|
13
|
+
patterns.map! { |s| Regexp.new(s.gsub("/", File::SEPARATOR)) }
|
14
|
+
|
15
|
+
@exclusion_patterns = [Regexp.union(*patterns)]
|
16
|
+
@inclusion_patterns = []
|
17
|
+
|
18
|
+
inclusion_patterns << Regexp.new(Dir.getwd)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Filter backtrace.
|
22
|
+
#
|
23
|
+
# @param backtrace [Array<String>] exception backtrace
|
24
|
+
# @return [Array<String>] backtrace lines except ruby libraries, gems and executable files.
|
25
|
+
def format(backtrace)
|
26
|
+
return [] unless backtrace
|
27
|
+
return backtrace if backtrace.empty?
|
28
|
+
|
29
|
+
backtrace.map { |l| backtrace_line(l) }.compact.
|
30
|
+
tap do |filtered|
|
31
|
+
if filtered.empty?
|
32
|
+
filtered.concat backtrace
|
33
|
+
filtered << ""
|
34
|
+
filtered << " Showing full backtrace because every line was filtered out."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Extracts error message from excetion
|
41
|
+
#
|
42
|
+
# @param exception [Exception]
|
43
|
+
# @param include_backtrace [Boolean] whether to add formatted backtrace to output
|
44
|
+
# @return [String] error message from excetion, incuding source code line.
|
45
|
+
def error_message(exception, include_backtrace: false)
|
46
|
+
backtrace = format(exception.backtrace)
|
47
|
+
source_line = extract_source_line(backtrace.first)
|
48
|
+
msg = ''
|
49
|
+
msg << "\n#{source_line}\n" if source_line
|
50
|
+
msg << "#{exception.class.name}: " unless exception.class.name =~ /RSpec/
|
51
|
+
msg << exception.message if exception.message
|
52
|
+
msg << "\n#{backtrace.join("\n")}\n" if include_backtrace
|
53
|
+
msg
|
54
|
+
end
|
55
|
+
|
56
|
+
def extract_source_line(backtrace_line)
|
57
|
+
file_and_line_number = backtrace_line.match(/(.+?):(\d+)(|:\d+)/)
|
58
|
+
return nil unless file_and_line_number
|
59
|
+
file_path, line_number = file_and_line_number[1..2]
|
60
|
+
return nil unless File.exist?(file_path)
|
61
|
+
lines = File.read(file_path).split("\n")
|
62
|
+
lines[line_number.to_i - 1]
|
63
|
+
end
|
64
|
+
|
65
|
+
def backtrace_line(line)
|
66
|
+
relative_path(line) unless exclude?(line)
|
67
|
+
end
|
68
|
+
|
69
|
+
def exclude?(line)
|
70
|
+
matches?(exclusion_patterns, line) && !matches?(inclusion_patterns, line)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def matches?(patterns, line)
|
76
|
+
patterns.any? { |p| line =~ p }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Matches strings either at the beginning of the input or prefixed with a
|
80
|
+
# whitespace, containing the current path, either postfixed with the
|
81
|
+
# separator, or at the end of the string. Match groups are the character
|
82
|
+
# before and the character after the string if any.
|
83
|
+
#
|
84
|
+
# http://rubular.com/r/fT0gmX6VJX
|
85
|
+
# http://rubular.com/r/duOrD4i3wb
|
86
|
+
# http://rubular.com/r/sbAMHFrOx1
|
87
|
+
def relative_path_regex
|
88
|
+
@relative_path_regex ||= /(\A|\s)#{File.expand_path('.')}(#{File::SEPARATOR}|\s|\Z)/
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param line [String] current code line
|
92
|
+
# @return [String] relative path to line
|
93
|
+
def relative_path(line)
|
94
|
+
line = line.sub(relative_path_regex, "\\1.\\2".freeze)
|
95
|
+
line = line.sub(/\A([^:]+:\d+)$/, '\\1'.freeze)
|
96
|
+
return nil if line == '-e:1'.freeze
|
97
|
+
line
|
98
|
+
rescue SecurityError
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|