chemistrykit 3.7.0 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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