lopata 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70e042bc80bb14342ec6b0f516df0934007677e8dd98ba04f2d65034ca6acbce
4
- data.tar.gz: 5afff5a8553b777f02b0ee838f304d0d660afdc60042113423b52f08e91342db
3
+ metadata.gz: 51ff4a162c7617388f8856b342449e1475f2438d8a44a6c58c6168373b144969
4
+ data.tar.gz: 10580190d2a63826f971d1730523eacc34ed818b634329da1635db07d2627d27
5
5
  SHA512:
6
- metadata.gz: 0f87e65d52c3bf6a15c85bfd5f900a48a576f256be20264a6df2360f8633694e88267f7cbd348325822b927538c5ad4407a55bd0ce3837c6ef630d685eec9074
7
- data.tar.gz: 2d4c9fe43e2283e210e6c30e882941f99975e9e2b62a00d9a23b7f59208e02726c66b9c72bb2d612e117bd79c82f9fb3aa88e711ed4d3022226d9137f27b76e0
6
+ metadata.gz: 76f4fffc7d6755eb63d45a3297177c25b2e947c101dfad38b7a39e8bb474f00e3874d3b3fcf939a81d3ad550cc7d18335ac998104f0b0436db239d1f4688a0f5
7
+ data.tar.gz: '086e6cb580e94035e78607daa4a5ba6a5caf2211e37bc0e5cd9aa7cb1e2579fc22889e6fb90e17e6b4f290016a70d76f86d1d93d307d19e964b7584a3bee0451'
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Lopata - functional acceptance testing
1
+ # Lopata
2
2
 
3
- Motivation: use RSpec for functional testing.
3
+ Functional acceptance testing using Ruby.
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,3 +20,7 @@ Run tests:
20
20
 
21
21
  cd <project-name>
22
22
  lopata
23
+
24
+ ## Documentation
25
+
26
+ See [features description](https://github.com/avolochnev/lopata/tree/master/features) for documentation.
data/exe/lopata CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'bundler/setup'
3
- require_relative '../lib/lopata/runner'
3
+ require 'lopata/runner'
4
4
 
5
5
  # use default command with arguments if given command is unknown.
6
6
  argv = ARGV.dup
@@ -1,11 +1,14 @@
1
1
  require 'lopata/id'
2
- require 'lopata/config'
2
+ require 'lopata/configuration'
3
+ require 'lopata/environment'
3
4
  require 'lopata/scenario_builder'
4
5
  require 'lopata/scenario'
5
6
  require 'lopata/step'
6
7
  require 'lopata/shared_step'
7
8
 
8
9
  module Lopata
10
+ # Define the scenario.
11
+ # @see Lopata::ScenarioBuilder.define
9
12
  def self.define(*args, &block)
10
13
  Lopata::ScenarioBuilder.define(*args, &block)
11
14
  end
@@ -14,11 +17,57 @@ module Lopata
14
17
  def self.xdefine(*args, &block)
15
18
  end
16
19
 
20
+ # Register the shared step
21
+ #
22
+ # @example
23
+ # Lopata.shared_step 'test user' do
24
+ # setup { @user = create(:user) }
25
+ # end
26
+ #
27
+ # Shared step may be used in scenarios by name:
28
+ # @example
29
+ # Lopata.define 'user' do
30
+ # setup 'test user'
31
+ #
32
+ # it 'exists' do
33
+ # expect(@user).to_not be_nil
34
+ # end
35
+ # end
36
+ # @param name [String] shared step unique name
37
+ # @param block shared step action sequence definition
17
38
  def self.shared_step(name, &block)
18
39
  Lopata::SharedStep.register(name, &block)
19
40
  end
20
41
 
42
+ # Yields the global configuration to a block.
43
+ # @yield [Lopata::Configuration] global configuration
44
+ #
45
+ # @example
46
+ # Lopata.configure do |config|
47
+ # config.before_scenario 'setup test user'
48
+ # end
49
+ # @see Lopata::Configuration
21
50
  def self.configure(&block)
22
- yield Lopata::Config
51
+ yield Lopata.configuration
52
+ end
53
+
54
+ # Returns global configuration object.
55
+ # @return [Lopata::Configuration]
56
+ # @see Lopata.configure
57
+ def self.configuration
58
+ @configuration ||= Lopata::Configuration.new
59
+ end
60
+
61
+ # @private
62
+ # Internal container for global non-configuration data.
63
+ def self.world
64
+ @world ||= Lopata::World.new
65
+ end
66
+
67
+ # Return global environment object
68
+ # @return [Lopata::Environment]
69
+ # @see Lopata::Environment
70
+ def self.environment
71
+ Lopata.configuration.environment
23
72
  end
24
73
  end
@@ -1,25 +1,85 @@
1
1
  module Lopata
2
+ # Helpers for ActiveRecord usage in tests.
3
+ #
4
+ # Make helpers available in scenarios by
5
+ #
6
+ # require 'lopata/active_record'
7
+ #
8
+ # @example
9
+ #
10
+ # # Configure db connection at config/environments/qa.yml like rails:
11
+ # # db:
12
+ # # adapter: postgresql
13
+ # # host: your.database.host
14
+ # # username: username
15
+ # # password: password
16
+ # # database: database
17
+ # require 'active_record'
18
+ # require 'lopata/active_record'
19
+ #
20
+ # class User < ActiveRecord::Base; end
21
+ #
22
+ # Lopata.define 'User creation' do
23
+ # setup do
24
+ # @user = User.create!(username: 'testuser')
25
+ # end
26
+ # # Remove user from database after scenario
27
+ # cleanup :user
28
+ #
29
+ # it 'works' do
30
+ # expect(@user).to_not be_nil
31
+ # end
32
+ # end
33
+ #
2
34
  module ActiveRecord
3
- # To be included in Lopata::Scenario
35
+ # To be included in Lopata::Scenario. The methods may be used in runtime.
4
36
  module Methods
37
+ # Destroy ActiveRecord objects.
38
+ #
39
+ # Does nothing if 'keep' mode is enabled:
40
+ #
41
+ # Lopata.configure do |c|
42
+ # c.keep = true
43
+ # end
44
+ #
45
+ # @param objects [Array<ActiveRecord::Base, Array<ActiveRecord::Base>, nil>] to be destroyed
46
+ # @see Lopata::Configuration#keep
5
47
  def cleanup(*objects)
6
- return if Lopata::Config.ops[:keep]
48
+ return if Lopata.configuration.keep
7
49
  objects.flatten.compact.each do |o|
8
50
  begin
9
51
  o.reload.destroy!
10
52
  rescue ::ActiveRecord::RecordNotFound
11
- # Already destroyed
53
+ # Already destroyed - skip
54
+ rescue ::ActiveRecord::InvalidForeignKey
55
+ # Possible async job created new relationships (e.g. history records). Try again once.
56
+ o.reload.destroy!
12
57
  end
13
58
  end
14
59
  end
15
60
 
61
+ # Reload ActiveRecord objects
62
+ #
63
+ # @example
64
+ #
65
+ # # use in steps
66
+ # reload @a, @b
67
+ # # instead of
68
+ # @a.reload; @b.reload
69
+ #
70
+ # @param objects [Array<ActiveRecord::Base, Array<ActiveRecord::Base>, nil>] to be reloaded
16
71
  def reload(*objects)
17
- objects.flatten.each(&:reload)
72
+ objects.flatten.compact.each(&:reload)
18
73
  end
19
74
  end
20
75
 
21
- # To be included in Lopata::ScenarioBuilder
76
+ # To be included in Lopata::ScenarioBuilder. The methods may be used in build time.
22
77
  module DSL
78
+ # Mark instance variables to call #destroy at teardown phase of scenario or context running.
79
+ #
80
+ # Does nothing if 'keep' mode is enabled.
81
+ #
82
+ # @param vars [Array<Symbol, String>] instance variable names to be destroyed on teardown phase.
23
83
  def cleanup(*vars, &block)
24
84
  unless vars.empty?
25
85
  teardown do
@@ -32,5 +92,8 @@ module Lopata
32
92
  end
33
93
  end
34
94
 
95
+ params = Lopata.environment['db']
96
+ ActiveRecord::Base.establish_connection(params) if params
97
+
35
98
  Lopata::Scenario.include Lopata::ActiveRecord::Methods
36
99
  Lopata::ScenarioBuilder.include Lopata::ActiveRecord::DSL
@@ -1,4 +1,5 @@
1
1
  module Lopata
2
+ # @private
2
3
  class Condition
3
4
  attr_reader :condition, :positive
4
5
  def initialize(condition, positive: true)
@@ -18,7 +19,7 @@ module Lopata
18
19
  when Hash
19
20
  condition.keys.all? { |k| metadata[k] == condition[k] }
20
21
  when Array
21
- condition.map { |key| metadata[key] }.none?(&:nil?)
22
+ condition.map { |key| metadata[key] }.all?
22
23
  else
23
24
  metadata[condition]
24
25
  end
@@ -0,0 +1,126 @@
1
+ module Lopata
2
+ # Stores runtime configuration information
3
+ #
4
+ # @see Lopata.configure
5
+ # @see Lopata.configuration
6
+ class Configuration
7
+ # Build an object to store runtime configuration options and set defaults
8
+ def initialize
9
+ @before_start_hooks = []
10
+ @before_scenario_steps = []
11
+ @after_scenario_steps = []
12
+ @observers = [Lopata::Observers::ConsoleOutputObserver.new]
13
+ @role_descriptions = {}
14
+ @env = :qa
15
+ end
16
+
17
+ # Add the hook to be called before scenarios running
18
+ # The block will be called after framework initialization and before scenarios parsing.
19
+ # It usually allow to require and initialize the libraries used for project testing.
20
+ #
21
+ # @example
22
+ # Lopata.configure do |c|
23
+ # c.before_start do
24
+ # require 'active_record'
25
+ # end
26
+ # end
27
+ def before_start(&block)
28
+ @before_start_hooks << block
29
+ end
30
+
31
+ # @private
32
+ def run_before_start_hooks
33
+ @before_start_hooks.each(&:call)
34
+ end
35
+
36
+ # Defines 'before scenario' steps.
37
+ # Given steps will be runned before each scenario in context of scenario.
38
+ # It may be shared step names, and|or block.
39
+ #
40
+ # @example
41
+ # Lopata.configure do |c|
42
+ # c.before_scenario 'setup test user'
43
+ # end
44
+ #
45
+ # @param steps [Array<String>] name of shared steps
46
+ # @param block [Proc] block of code
47
+ def before_scenario(*steps, &block)
48
+ before_scenario_steps.append(*steps) unless steps.empty?
49
+ before_scenario_steps.append(block) if block_given?
50
+ end
51
+
52
+ # Defines 'after scenario' steps.
53
+ # Given steps will be runned after each scenario in context of scenario.
54
+ # It may be shared step names, and|or block.
55
+ #
56
+ # @example
57
+ # Lopata.configure do |c|
58
+ # c.after_scenario 'cleanup test user'
59
+ # end
60
+ #
61
+ # @param steps [Array<String>] name of shared steps
62
+ # @param block [Proc] block of code
63
+ def after_scenario(*steps, &block)
64
+ after_scenario_steps.append(*steps) unless steps.empty?
65
+ after_scenario_steps.append(block) if block_given?
66
+ end
67
+
68
+ # @private
69
+ attr_reader :before_scenario_steps, :after_scenario_steps
70
+
71
+ # Add an observer to the set Lopata to be used for this run.
72
+ #
73
+ # @param observer [Lopata::Observers::BaseObserver] a observer instance.
74
+ #
75
+ # @see Lopata::Observers::BaseObserver
76
+ def add_observer(observer)
77
+ @observers << observer
78
+ end
79
+
80
+ # @private
81
+ attr_reader :observers
82
+
83
+ # @private
84
+ def filters
85
+ @filters ||= []
86
+ end
87
+
88
+ # @private
89
+ attr_accessor :web_logging_params
90
+
91
+ # @private
92
+ def init_lopata_logging(url, project_code, build_number)
93
+ require 'lopata/observers/web_logger'
94
+ self.web_logging_params = { url: url, project_code: project_code, build_number: build_number }
95
+ add_observer Lopata::Observers::WebLogger.new
96
+ end
97
+
98
+ # @return [Hash{Symbol => String}] map or role codes to role name.
99
+ # @see Lopata::Role
100
+ attr_accessor :role_descriptions
101
+
102
+ # @return [Symbol,nil] user role to be used in scenario if not specified
103
+ # @see Lopata::Role
104
+ attr_accessor :default_role
105
+
106
+ # @return [Symbol] environment code.
107
+ # Default is :qa
108
+ # @see Lopata::Environment
109
+ attr_accessor :env
110
+
111
+ # @return [Boolean] keep generated test data after scenarios running.
112
+ # Default is false
113
+ # Set to true for keeping generated data.
114
+ # Use 'lopata --keep' modifier to set keep mode on running.
115
+ # @see Lopata::ActiveRecord::Methods#cleanup
116
+ attr_accessor :keep
117
+
118
+ # @private
119
+ attr_accessor :environment
120
+
121
+ # @private
122
+ def load_environment
123
+ self.environment = Lopata::Environment.new(env)
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,36 @@
1
+ module Lopata
2
+ # Settings of test enviromnet the scenarios to be runned.
3
+ #
4
+ # Lopata allows to define different environments the scenarios to be runned on.
5
+ # Set environment name via command line 'lopata -e stage' or via configuration:
6
+ #
7
+ # Lopata.configure do |c|
8
+ # c.env = :stage
9
+ # end
10
+ #
11
+ # The environment params are loaded from './config/environments/<env>.yml'.
12
+ class Environment
13
+ # Loads environment configuration for given env
14
+ # @param env [Symbol] environment key
15
+ # Loads golobl configured environment if not given.
16
+ # @see Lopata::Configuration#env
17
+ def initialize(env = Lopata.configuration.env)
18
+ require 'yaml'
19
+ @config = {}
20
+ config_filename = "./config/environments/#{Lopata.configuration.env}.yml"
21
+ @config = YAML::load(File.open(config_filename)) if File.exists?(config_filename)
22
+ end
23
+
24
+ # Access to environment settings
25
+ # @param key [Symbol] environment configuration key is set on yml configuration.
26
+ def [](key)
27
+ @config[key]
28
+ end
29
+
30
+ %w{url}.each do |opt|
31
+ define_method opt do
32
+ @config[opt]
33
+ end
34
+ end
35
+ end
36
+ end
@@ -33,4 +33,4 @@ Lopata.configure do |c|
33
33
  c.after_scenario { cleanup @created_objects }
34
34
  end
35
35
 
36
- ::FactoryBot.find_definitions unless Lopata::Config.readonly
36
+ ::FactoryBot.find_definitions
@@ -11,10 +11,8 @@ module Lopata
11
11
  def create_root_files
12
12
  template 'Lopatafile', "#{name}/Lopatafile"
13
13
  template 'Gemfile', "#{name}/Gemfile"
14
- template '.rspec', "#{name}/.rspec"
15
14
  template 'config/environments/qa.yml', "#{name}/config/environments/qa.yml"
16
15
  template 'config/initializers/capybara.rb', "#{name}/config/initializers/capybara.rb"
17
- template 'spec/spec_helper.rb', "#{name}/spec/spec_helper.rb"
18
16
  end
19
17
 
20
18
  def init_dirs
@@ -1,7 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
  gem 'selenium-webdriver'
3
- gem 'rspec', :require => 'spec'
4
- gem 'rake'
5
3
  gem 'activerecord', '~> 6.0.2'
6
4
  gem 'capybara', '~> 3.11.1'
7
5
  gem 'thor'
@@ -1,5 +1,4 @@
1
1
  url: http://yourapp.com
2
- name: QA
3
2
  # db:
4
3
  # adapter: postgresql
5
4
  # host: localhost
@@ -1,7 +1,11 @@
1
1
  module Lopata
2
2
  module Observers
3
+ # @private
3
4
  # Based on RSpec::Core::BacktraceFormatter
5
+ #
6
+ # Provides ability to format backtrace and find source code by file and line number.
4
7
  class BacktraceFormatter
8
+ # @private
5
9
  attr_accessor :exclusion_patterns, :inclusion_patterns
6
10
 
7
11
  def initialize
@@ -14,6 +18,10 @@ module Lopata
14
18
  inclusion_patterns << Regexp.new(Dir.getwd)
15
19
  end
16
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.
17
25
  def format(backtrace)
18
26
  return [] unless backtrace
19
27
  return backtrace if backtrace.empty?
@@ -28,6 +36,12 @@ module Lopata
28
36
  end
29
37
  end
30
38
 
39
+
40
+ # Extracts error message from excetion
41
+ #
42
+ # @param exeption [Exception]
43
+ # @param include_backtrace [Boolean] whether to add formatted backtrace to output
44
+ # @return [String] error message from excetion, incuding source code line.
31
45
  def error_message(exception, include_backtrace: false)
32
46
  backtrace = format(exception.backtrace)
33
47
  source_line = extract_source_line(backtrace.first)