chemistrykit 3.7.0 → 3.8.0

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.
@@ -9,6 +9,8 @@ require 'chemistrykit/cli/beaker'
9
9
  require 'chemistrykit/cli/helpers/formula_loader'
10
10
  require 'chemistrykit/catalyst'
11
11
  require 'chemistrykit/formula/base'
12
+ require 'chemistrykit/formula/formula_lab'
13
+ require 'chemistrykit/chemist/repository/csv_chemist_repository'
12
14
  require 'selenium_connect'
13
15
  require 'chemistrykit/configuration'
14
16
  require 'parallel_tests'
@@ -60,7 +62,7 @@ module ChemistryKit
60
62
  method_option :params, type: :hash
61
63
  method_option :tag, type: :array
62
64
  method_option :config, default: 'config.yaml', aliases: '-c', desc: 'Supply alternative config file.'
63
- # TODO there should be a facility to simply pass a path to this command
65
+ # TODO: there should be a facility to simply pass a path to this command
64
66
  method_option :beakers, aliases: '-b', type: :array
65
67
  # This is set if the thread is being run in parallel so as not to trigger recursive concurency
66
68
  method_option :parallel, default: false
@@ -70,7 +72,7 @@ module ChemistryKit
70
72
 
71
73
  def brew
72
74
  config = load_config options['config']
73
- # TODO perhaps the params should be rolled into the available
75
+ # TODO: perhaps the params should be rolled into the available
74
76
  # config object injected into the system?
75
77
  pass_params if options['params']
76
78
 
@@ -116,13 +118,9 @@ module ChemistryKit
116
118
  protected
117
119
 
118
120
  def override_configs(options, config)
119
- # TODO expand this to allow for more overrides as needed
120
- if options['results_file']
121
- config.log.results_file = options['results_file']
122
- end
123
- if options['retry']
124
- config.retries_on_failure = options['retry'].to_i
125
- end
121
+ # TODO: expand this to allow for more overrides as needed
122
+ config.log.results_file = options['results_file'] if options['results_file']
123
+ config.retries_on_failure = options['retry'].to_i if options['retry']
126
124
  config
127
125
  end
128
126
 
@@ -188,6 +186,13 @@ module ChemistryKit
188
186
  @sc = SeleniumConnect.start configuration
189
187
  @job = @sc.create_job # create a new job
190
188
  @driver = @job.start name: test_name
189
+
190
+ # TODO: this is messy, and could be refactored out into a static on the lab
191
+ chemist_data_paths = Dir.glob(File.join(Dir.getwd, 'chemists', '*.csv'))
192
+ repo = ChemistryKit::Chemist::Repository::CsvChemistRepository.new chemist_data_paths
193
+ # make the formula lab available
194
+ @formula_lab = ChemistryKit::Formula::FormulaLab.new @driver, repo, File.join(Dir.getwd, 'formulas')
195
+
191
196
  example.run
192
197
  end
193
198
  c.after(:each) do
@@ -48,7 +48,7 @@ module ChemistryKit
48
48
  end
49
49
 
50
50
  def self.initialize_with_yaml(file)
51
- self.new symbolize_keys YAML.load_file file
51
+ new symbolize_keys YAML.load_file file
52
52
  end
53
53
 
54
54
  private
@@ -56,7 +56,7 @@ module ChemistryKit
56
56
  def populate_with_hash(hash)
57
57
  hash.each do |key, value|
58
58
  begin
59
- self.send "#{key}=", value unless value.nil?
59
+ send "#{key}=", value unless value.nil?
60
60
  rescue NoMethodError
61
61
  raise ArgumentError.new "The config key: \"#{key}\" is unknown!"
62
62
  end
@@ -0,0 +1,10 @@
1
+ # Encoding: utf-8
2
+
3
+ module ChemistryKit
4
+ module Formula
5
+ # Mixin to provide formulas with methods related to having a chemist (user)
6
+ module ChemistAware
7
+ attr_accessor :chemist
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,99 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'find'
4
+
5
+ module ChemistryKit
6
+ module Formula
7
+ # Factory class to assemble page objects with users
8
+ class FormulaLab
9
+
10
+ attr_reader :formula
11
+
12
+ def initialize(driver, chemist_repository, formulas_dir)
13
+ @driver = driver
14
+ @chemist_repository = chemist_repository
15
+ raise ArgumentError, "Formula directory \"#{formulas_dir}\" does not exist!" unless File.directory?(formulas_dir)
16
+ @formulas_dir = formulas_dir
17
+ end
18
+
19
+ def using(formula_key)
20
+ @formula = formula_key
21
+ self
22
+ end
23
+
24
+ def mix(formula_key = nil)
25
+ @formula = formula_key ||= formula
26
+ raise ArgumentError, 'A formula key must be defined!' unless @formula
27
+ formula_file = find_formula_file
28
+ class_name = get_class_name formula_file
29
+ formula = constantize(class_name).new(@driver)
30
+ if formula.singleton_class.include?(ChemistryKit::Formula::ChemistAware)
31
+ raise RuntimeError, "Trying to mix a formula: \"#{formula_key}\" that requires a user, but no user set!" unless @chemist
32
+ formula.chemist = @chemist
33
+ end
34
+ formula
35
+ end
36
+
37
+ def with(key)
38
+ @chemist = @chemist_repository.load_chemist_by_key key
39
+ self
40
+ end
41
+
42
+ def with_random(type)
43
+ @chemist = @chemist_repository.load_random_chemist_of_type type
44
+ self
45
+ end
46
+
47
+ def with_first(type)
48
+ @chemist = @chemist_repository.load_first_chemist_of_type type
49
+ self
50
+ end
51
+
52
+ private
53
+
54
+ def find_formula_file
55
+ Find.find(@formulas_dir) do |path|
56
+ return path if path =~ /.*#{@formula}\.rb$/
57
+ end
58
+ end
59
+
60
+ # TODO: try to resolve this backreff thing
61
+ # rubocop:disable AvoidPerlBackrefs
62
+ def get_class_name(formula_file)
63
+ string = formula_file.match(/(#{@formulas_dir.split('/').last}.*#{@formula})\.rb$/)[1]
64
+ string = string.sub(/^[a-z\d]*/) { $&.capitalize }
65
+ string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
66
+ end
67
+ # rubocop:enable AvoidPerlBackrefs
68
+
69
+ # "borrowed" from http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-constantize
70
+ # TODO: this could be simplified, refactored out, or just use the activestate module some how
71
+ def constantize(camel_cased_word)
72
+ names = camel_cased_word.split('::')
73
+ names.shift if names.empty? || names.first.empty?
74
+
75
+ names.reduce(Object) do |constant, name|
76
+ if constant == Object
77
+ constant.const_get(name)
78
+ else
79
+ candidate = constant.const_get(name)
80
+ next candidate if constant.const_defined?(name, false)
81
+ next candidate unless Object.const_defined?(name)
82
+
83
+ # Go down the ancestors to check it it's owned
84
+ # directly before we reach Object or the end of ancestors.
85
+ constant = constant.ancestors.reduce do |const, ancestor|
86
+ break const if ancestor == Object
87
+ break ancestor if ancestor.const_defined?(name, false)
88
+ const
89
+ end
90
+
91
+ # owner is in Object, so raise
92
+ constant.const_get(name, false)
93
+ end
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -46,7 +46,7 @@ module ParallelTests
46
46
  end
47
47
 
48
48
  def runtime_log
49
- # TODO This needs to do something.
49
+ # TODO: This needs to do something.
50
50
  File.join(Dir.getwd, 'evidence', 'parallel_runtime_rspec.log')
51
51
  end
52
52
 
@@ -0,0 +1 @@
1
+ key,type
@@ -1,6 +1,8 @@
1
1
  module Formulas
2
2
  class <%= name.capitalize %> < Formula
3
3
 
4
+ # Uncomment out the below to provide a chemist for your formula
5
+ # include ChemistryKit::Formula::ChemistAware
4
6
 
5
7
 
6
8
  end
@@ -0,0 +1,59 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'chemistrykit/formula/formula_lab'
5
+ require 'chemistrykit/chemist/repository/csv_chemist_repository'
6
+
7
+ describe ChemistryKit::Formula::FormulaLab do
8
+
9
+ VALID_CHEMIST_KEY = 'admin1'
10
+ VALID_CHEMIST_TYPE = 'admin'
11
+
12
+ VALID_BASIC_FORMULA_KEY = 'basic_formula'
13
+ VALID_CHEMIST_FORMULA_KEY = 'chemist_formula'
14
+
15
+ before(:each) do
16
+ @stub_driver = double 'Selenium::WebDriver::Driver'
17
+ chemists_path = File.join(Dir.pwd, 'spec', 'support', 'chemists.csv')
18
+ @repo = ChemistryKit::Chemist::Repository::CsvChemistRepository.new chemists_path
19
+ formulas_dir = File.join(Dir.pwd, 'spec', 'support', 'formulas')
20
+ @lab = ChemistryKit::Formula::FormulaLab.new @stub_driver, @repo, formulas_dir
21
+ end
22
+
23
+ it 'should mix a formula without a chemist' do
24
+ formula = @lab.mix(VALID_BASIC_FORMULA_KEY)
25
+ formula.should be_an_instance_of Formulas::SubModule::BasicFormula
26
+ end
27
+
28
+ it 'should mix a formula with a chemist the standard way' do
29
+ formula = @lab.using(VALID_CHEMIST_FORMULA_KEY).with(VALID_CHEMIST_KEY).mix
30
+ formula.should be_an_instance_of Formulas::SubModule::ChemistFormula
31
+ formula.chemist.key.should eq VALID_CHEMIST_KEY
32
+ end
33
+
34
+ it 'should raise an error if trying to mix a formula that requires a user, without setting one' do
35
+ expect do
36
+ @lab.using(VALID_CHEMIST_FORMULA_KEY).mix
37
+ end.to raise_error RuntimeError, "Trying to mix a formula: \"#{VALID_CHEMIST_FORMULA_KEY}\" that requires a user, but no user set!"
38
+ end
39
+
40
+ it 'should mix a formula in the oposite way' do
41
+ formula = @lab.with(VALID_CHEMIST_KEY).mix(VALID_CHEMIST_FORMULA_KEY)
42
+ formula.should be_an_instance_of Formulas::SubModule::ChemistFormula
43
+ formula.chemist.key.should eq VALID_CHEMIST_KEY
44
+ end
45
+
46
+ it 'should mix a formula with a typed chemist' do
47
+ formula = @lab.with_first(VALID_CHEMIST_TYPE).mix(VALID_CHEMIST_FORMULA_KEY)
48
+ formula.should be_an_instance_of Formulas::SubModule::ChemistFormula
49
+ formula.chemist.key.should eq VALID_CHEMIST_KEY
50
+ end
51
+
52
+ it 'should mix a formula with a random chemist of a type' do
53
+ formula = @lab.with_random('random').mix(VALID_CHEMIST_FORMULA_KEY)
54
+ formula.should be_an_instance_of Formulas::SubModule::ChemistFormula
55
+ key = formula.chemist.key
56
+ (key == 'ran1' || key == 'ran2').should be_true
57
+ end
58
+
59
+ end
data/spec/spec_helper.rb CHANGED
@@ -19,6 +19,9 @@ require_relative '../lib/chemistrykit/formula/base'
19
19
  require_relative '../lib/chemistrykit/catalyst'
20
20
  require_relative '../lib/chemistrykit/configuration'
21
21
 
22
+ require_relative '../spec/support/formulas/sub_module/basic_formula'
23
+ require_relative '../spec/support/formulas/sub_module/chemist_formula'
24
+
22
25
  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
23
26
  SimpleCov::Formatter::HTMLFormatter,
24
27
  Coveralls::SimpleCov::Formatter
@@ -0,0 +1,3 @@
1
+ Key,Email,Name,Password
2
+ admin1,admin@email.com,Mr. Admin,abc123$
3
+ normal1,normal@email.com,Ms. Normal,test123%
@@ -0,0 +1,6 @@
1
+ Key,Type,Email,Name,Password
2
+ admin1,admin,admin@email.com,Mr. Admin,abc123$
3
+ normal1,normal,normal@email.com,Ms. Normal,test123%
4
+ ran1,random,normal@email.com,Ms. Normal,test123%
5
+ ran2,random,normal@email.com,Ms. Normal,test123%
6
+ uuid_chemist,normal,normal{{UUID}}@email.com,Mr. uuid,test123#
@@ -0,0 +1 @@
1
+ key,type
@@ -0,0 +1,13 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'chemistrykit/formula/base'
4
+
5
+ module Formulas
6
+ module SubModule
7
+ class BasicFormula < ChemistryKit::Formula::Base
8
+ def open(url)
9
+ @driver.get url
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'chemistrykit/formula/base'
4
+ require 'chemistrykit/formula/chemist_aware'
5
+
6
+ module Formulas
7
+ module SubModule
8
+ class ChemistFormula < ChemistryKit::Formula::Base
9
+ include ChemistryKit::Formula::ChemistAware
10
+ def open(url)
11
+ @driver.get url
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ Type,Email,Name,Password
2
+ admin,admin@email.com,Mr. Admin,abc123$
3
+ normal,normal@email.com,Ms. Normal,test123%
@@ -0,0 +1,2 @@
1
+ Key,Type,Name,Passion
2
+ cowboy1,cowboy,Billy the Kid,Wrasslin
@@ -0,0 +1,99 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'chemistrykit/chemist/repository/csv_chemist_repository'
5
+
6
+ describe ChemistryKit::Chemist::Repository::CsvChemistRepository do
7
+
8
+ VALID_CHEMIST_CSV = 'chemists.csv'
9
+ VALID_DEFAULT_CSV = 'default_chemists.csv'
10
+ BAD_CHEMIST_CSV = 'bad_chemists.csv'
11
+ KEYLESS_CHEMIST_CSV = 'keyless_chemists.csv'
12
+ INVALID_CHEMIST_CSV = 'file_does_not_exist.csv'
13
+ VALID_USER_TYPE = 'admin'
14
+ VALID_USER_KEY = 'admin1'
15
+ INVALID_USER_TYPE = 'no_type'
16
+
17
+ before(:each) do
18
+ csv_file = File.join(Dir.pwd, 'spec', 'support', VALID_CHEMIST_CSV)
19
+ @repo = ChemistryKit::Chemist::Repository::CsvChemistRepository.new(csv_file)
20
+ end
21
+
22
+ it 'should be instantiated with a csv file path' do
23
+ @repo.should be_an_instance_of ChemistryKit::Chemist::Repository::CsvChemistRepository
24
+ end
25
+
26
+ it 'should raise and error if the file does not exist' do
27
+ expect do
28
+ csv_file = File.join(Dir.pwd, 'spec', 'support', INVALID_CHEMIST_CSV)
29
+ ChemistryKit::Chemist::Repository::CsvChemistRepository.new(csv_file)
30
+ end.to raise_error ArgumentError, 'Supplied file does not exist!'
31
+ end
32
+
33
+ it 'should load a random by type identifier' do
34
+ chemist = @repo.load_first_chemist_of_type VALID_USER_TYPE
35
+ chemist.type.should eq VALID_USER_TYPE
36
+ end
37
+
38
+ it 'should load a random by specific key' do
39
+ chemist = @repo.load_chemist_by_key VALID_USER_KEY
40
+ chemist.key.should eq VALID_USER_KEY
41
+ end
42
+
43
+ it 'should load a random chemist by type' do
44
+ chemist = @repo.load_random_chemist_of_type 'random'
45
+ (chemist.key == 'ran1' || chemist.key == 'ran2').should be_true
46
+ end
47
+
48
+ it 'should set all the parameters defined in the csv file' do
49
+ chemist = @repo.load_first_chemist_of_type VALID_USER_TYPE
50
+ chemist.name.should eq 'Mr. Admin'
51
+ chemist.email.should eq 'admin@email.com'
52
+ chemist.password.should eq 'abc123$'
53
+ end
54
+
55
+ it 'should rais and error if the chemist is not found' do
56
+ expect do
57
+ @repo.load_first_chemist_of_type INVALID_USER_TYPE
58
+ end.to raise_error ArgumentError, 'Chemist for type "no_type" not found!'
59
+ end
60
+
61
+ it 'should raise and error if there is no type heading in the csv file' do
62
+ csv_file = File.join(Dir.pwd, 'spec', 'support', BAD_CHEMIST_CSV)
63
+ expect do
64
+ ChemistryKit::Chemist::Repository::CsvChemistRepository.new(csv_file)
65
+ end.to raise_error ArgumentError, 'You must define a type field!'
66
+ end
67
+
68
+ it 'should raise and error if there is no key heading in the csv file' do
69
+ csv_file = File.join(Dir.pwd, 'spec', 'support', KEYLESS_CHEMIST_CSV)
70
+ expect do
71
+ ChemistryKit::Chemist::Repository::CsvChemistRepository.new(csv_file)
72
+ end.to raise_error ArgumentError, 'You must define a key field!'
73
+ end
74
+
75
+ it 'can search more than one csv file' do
76
+ files = []
77
+ files.push File.join(Dir.pwd, 'spec', 'support', VALID_CHEMIST_CSV)
78
+ files.push File.join(Dir.pwd, 'spec', 'support', 'other_chemists.csv')
79
+ repo = ChemistryKit::Chemist::Repository::CsvChemistRepository.new(files)
80
+
81
+ chemist = repo.load_first_chemist_of_type 'cowboy'
82
+ chemist.passion.should eq 'Wrasslin'
83
+
84
+ chemist = repo.load_first_chemist_of_type 'normal'
85
+ chemist.email = 'normal@email.com'
86
+ end
87
+
88
+ it 'should replace the {{UUID}} token with a uuid on runtime if found in a parameter' do
89
+ chemist = @repo.load_chemist_by_key 'uuid_chemist'
90
+ # the {{UUID}} token was placed in the email parameter
91
+ expect(chemist.email).to match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
92
+ end
93
+
94
+ it 'should not raise any error if there were no modifications to the default chemists file' do
95
+ csv_file = File.join(Dir.pwd, 'spec', 'support', VALID_DEFAULT_CSV)
96
+ repo = ChemistryKit::Chemist::Repository::CsvChemistRepository.new(csv_file)
97
+ repo.should be_an_instance_of ChemistryKit::Chemist::Repository::CsvChemistRepository
98
+ end
99
+ end
@@ -0,0 +1,43 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'chemistrykit/chemist'
5
+
6
+ describe ChemistryKit::Chemist do
7
+
8
+ VALID_KEY = 'specific_admin'
9
+ VALID_TYPE = 'admin'
10
+ VALID_VALUE = 'my value'
11
+
12
+ before(:each) do
13
+ @chemist = ChemistryKit::Chemist.new(VALID_KEY, VALID_TYPE)
14
+ end
15
+
16
+ it 'must have at least a key and type' do
17
+ @chemist.key.should eq VALID_KEY
18
+ @chemist.type.should eq VALID_TYPE
19
+ end
20
+
21
+ it 'should be able to set and get arbitrary data' do
22
+ @chemist.my_key = VALID_VALUE
23
+ @chemist.my_key.should eq VALID_VALUE
24
+ end
25
+
26
+ it 'should be able to get a hash of its data' do
27
+ @chemist.my_key = VALID_VALUE
28
+ @chemist.data.should eq my_key: VALID_VALUE
29
+ end
30
+
31
+ it 'should not be able to override the other instance variables' do
32
+ @chemist.type = 'other'
33
+ @chemist.type.should eq VALID_TYPE
34
+ @chemist.data.include?(:type).should be_false
35
+ end
36
+
37
+ it 'should be able to be populated with a hash of arbitrary data' do
38
+ dataset = { name: 'cool dude', email: 'fun@gmail.com', password: 'Oa8w*#)asd' }
39
+ @chemist.data = dataset
40
+ @chemist.name.should eq 'cool dude'
41
+ @chemist.email.should eq 'fun@gmail.com'
42
+ end
43
+ end