effective_test_bot 0.4.3 → 0.4.4
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 +3 -0
- data/lib/effective_test_bot.rb +28 -0
- data/lib/effective_test_bot/engine.rb +9 -7
- data/lib/effective_test_bot/version.rb +1 -1
- data/lib/generators/effective_test_bot/install_generator.rb +2 -1
- data/lib/generators/templates/effective_test_bot.rb +30 -0
- data/lib/generators/templates/test_helper.rb +5 -0
- data/lib/tasks/effective_test_bot_tasks.rake +14 -5
- data/test/concerns/test_botable/crud_dsl.rb +2 -1
- data/test/concerns/test_botable/devise_dsl.rb +1 -1
- data/test/concerns/test_botable/member_dsl.rb +1 -1
- data/test/concerns/test_botable/page_dsl.rb +1 -1
- data/test/concerns/test_botable/redirect_dsl.rb +1 -1
- data/test/concerns/test_botable/wizard_dsl.rb +1 -1
- data/test/support/effective_test_bot_assertions.rb +14 -4
- data/test/support/effective_test_bot_form_filler.rb +239 -0
- data/test/support/effective_test_bot_form_helper.rb +45 -153
- data/test/support/effective_test_bot_screenshots_helper.rb +145 -0
- data/test/support/effective_test_bot_test_helper.rb +2 -1
- data/test/test_bot/integration/application_test.rb +3 -2
- data/test/test_bot/integration/environment_test.rb +9 -13
- data/test/test_botable/base_test.rb +11 -9
- data/test/test_botable/crud_test.rb +30 -12
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71be7587c07b84fa1b7e452dc469eeb560a1ce47
|
4
|
+
data.tar.gz: 063be9eb1dfc317f6dc01d0a8c199d411953c5f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1318c1e88b31a9d2bba44d2262862206c765c6864e8b9bf5d4b6456f90ae7d5fa552960974d4cdbbf83994c42aa1517cb6ffb31d1e6d86ad8960e0f4e38988d4
|
7
|
+
data.tar.gz: 80f617274e4f72d8885926c84fcdf8f19e51d576dcceb3b8914ee9e26a2c54dd32365f8641e04ab7c344f7ba218e25c4375f9a42fdb78f08002c7913a8ee68ae
|
data/README.md
CHANGED
data/lib/effective_test_bot.rb
CHANGED
@@ -4,6 +4,9 @@ require "effective_test_bot/version"
|
|
4
4
|
module EffectiveTestBot
|
5
5
|
mattr_accessor :except
|
6
6
|
mattr_accessor :only
|
7
|
+
mattr_accessor :screenshots
|
8
|
+
mattr_accessor :autosave_animated_gif_on_failure
|
9
|
+
mattr_accessor :tour_mode
|
7
10
|
|
8
11
|
def self.setup
|
9
12
|
yield self
|
@@ -38,6 +41,31 @@ module EffectiveTestBot
|
|
38
41
|
false # Don't skip this test
|
39
42
|
end
|
40
43
|
|
44
|
+
# If you call rake test:bot TOUR=false, then disable screenshots too
|
45
|
+
def self.screenshots?
|
46
|
+
screenshots == true
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.autosave_animated_gif_on_failure?
|
50
|
+
screenshots && autosave_animated_gif_on_failure
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.tour_mode?
|
54
|
+
if ENV['TOUR'].present?
|
55
|
+
['true', 'verbose', 'debug'].include?(ENV['TOUR'].to_s.downcase)
|
56
|
+
else
|
57
|
+
screenshots && (tour_mode != false)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.tour_mode_verbose?
|
62
|
+
if ENV['TOUR'].present?
|
63
|
+
['verbose', 'debug'].include?(ENV['TOUR'].to_s.downcase)
|
64
|
+
else
|
65
|
+
screenshots && ['verbose', 'debug'].include?(tour_mode.to_s)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
41
69
|
private
|
42
70
|
|
43
71
|
def self.onlies
|
@@ -14,6 +14,14 @@ module EffectiveTestBot
|
|
14
14
|
|
15
15
|
initializer 'effective_test_bot.test_suite' do |app|
|
16
16
|
Rails.application.config.to_prepare do
|
17
|
+
# test/support/
|
18
|
+
ActionDispatch::IntegrationTest.include EffectiveTestBotAssertions
|
19
|
+
ActionDispatch::IntegrationTest.include EffectiveTestBotFormHelper
|
20
|
+
ActionDispatch::IntegrationTest.include EffectiveTestBotFormFiller
|
21
|
+
ActionDispatch::IntegrationTest.include EffectiveTestBotLoginHelper
|
22
|
+
ActionDispatch::IntegrationTest.include EffectiveTestBotScreenshotsHelper
|
23
|
+
ActionDispatch::IntegrationTest.include EffectiveTestBotTestHelper
|
24
|
+
|
17
25
|
# test/test_botable/
|
18
26
|
ActionDispatch::IntegrationTest.include BaseTest
|
19
27
|
ActionDispatch::IntegrationTest.include CrudTest
|
@@ -31,12 +39,6 @@ module EffectiveTestBot
|
|
31
39
|
ActionDispatch::IntegrationTest.include TestBotable::PageDsl
|
32
40
|
ActionDispatch::IntegrationTest.include TestBotable::RedirectDsl
|
33
41
|
ActionDispatch::IntegrationTest.include TestBotable::WizardDsl
|
34
|
-
|
35
|
-
# test/support/
|
36
|
-
ActionDispatch::IntegrationTest.include EffectiveTestBotAssertions
|
37
|
-
ActionDispatch::IntegrationTest.include EffectiveTestBotFormHelper
|
38
|
-
ActionDispatch::IntegrationTest.include EffectiveTestBotLoginHelper
|
39
|
-
ActionDispatch::IntegrationTest.include EffectiveTestBotTestHelper
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
@@ -53,7 +55,7 @@ module EffectiveTestBot
|
|
53
55
|
assign_test_bot_unpermitted_params_header(exception)
|
54
56
|
end
|
55
57
|
|
56
|
-
rescue_from
|
58
|
+
rescue_from StandardError do |exception|
|
57
59
|
assign_test_bot_exceptions_header(exception)
|
58
60
|
render status: 500, text: "<html><body><h1>Uncaught Exception</h1><p>#{exception.message}</p><p>#{exception.backtrace.first(20).join('<br>')}</p></body></html>"
|
59
61
|
end
|
@@ -41,7 +41,8 @@ module EffectiveTestBot
|
|
41
41
|
|
42
42
|
def thank_you
|
43
43
|
puts "Thanks for using EffectiveTestBot"
|
44
|
-
puts "
|
44
|
+
puts "First make sure your test environment is correctly configured by running 'rake test:bot:environment'"
|
45
|
+
puts "Run tests with 'rake test:bot'"
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
@@ -2,5 +2,35 @@
|
|
2
2
|
|
3
3
|
if Rails.env.test?
|
4
4
|
EffectiveTestBot.setup do |config|
|
5
|
+
|
6
|
+
# Exclude the following tests or assertions from being run.
|
7
|
+
# config.except = [
|
8
|
+
# 'widgets'
|
9
|
+
# 'posts#create_invalid'
|
10
|
+
# 'posts#index page_title'
|
11
|
+
# 'no_unpermitted_params'
|
12
|
+
# ]
|
13
|
+
|
14
|
+
# Run only the following tests. Doesn't work with individual assertions>
|
15
|
+
# config.only = [
|
16
|
+
# 'posts', 'events#index'
|
17
|
+
# ]
|
18
|
+
|
19
|
+
# Should capybara generate a series of *.png screenshots as it goes through the test?
|
20
|
+
# Disabling screenshots will also disable animated_gifs and touring
|
21
|
+
config.screenshots = true
|
22
|
+
|
23
|
+
# Save on failure to /tmp/ directory
|
24
|
+
config.autosave_animated_gif_on_failure = true
|
25
|
+
|
26
|
+
# Take the tour!
|
27
|
+
# Generate an animated gif for each test
|
28
|
+
# Saved to an appropriate /test/tour/* directory
|
29
|
+
# You can override this default by setting an ENV or calling
|
30
|
+
# `rake test:bot TOUR=true` or `rake test:bot TEST=posts TOUR=verbose`
|
31
|
+
#
|
32
|
+
# Valid values are true / false / :verbose
|
33
|
+
config.tour_mode = false
|
34
|
+
|
5
35
|
end
|
6
36
|
end
|
@@ -48,6 +48,11 @@ Capybara::Webkit.configure { |config| config.allow_unknown_urls }
|
|
48
48
|
|
49
49
|
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
50
50
|
|
51
|
+
# These two lines are needed as of minitest-reporters 1.1.2
|
52
|
+
Rails.backtrace_cleaner.remove_silencers!
|
53
|
+
Rails.backtrace_cleaner.add_silencer { |line| line =~ /minitest/ }
|
54
|
+
|
55
|
+
|
51
56
|
### So this is EffectiveTestBot 'code' here
|
52
57
|
### That gets run just once before the whole test suite loads
|
53
58
|
|
@@ -4,25 +4,34 @@ require 'rails/test_unit/sub_test_task'
|
|
4
4
|
# rake test:bot
|
5
5
|
# rake test:bot TEST=documents#new
|
6
6
|
# rake test:bot TEST=documents#new,documents#show
|
7
|
-
# rake test:bot
|
7
|
+
# rake test:bot TOUR=true
|
8
|
+
# rake test:bot TOUR=verbose
|
8
9
|
|
9
10
|
# rake test:bot:environment
|
11
|
+
# rake test:bot:purge
|
10
12
|
|
11
13
|
namespace :test do
|
12
|
-
desc 'Runs
|
14
|
+
desc 'Runs the effective_test_bot'
|
13
15
|
task :bot do
|
14
16
|
if ENV['TEST'].present?
|
15
17
|
ENV['TEST_BOT_TEST'] = ENV['TEST']
|
16
18
|
ENV['TEST'] = nil
|
17
19
|
end
|
18
20
|
|
19
|
-
Rake::Task[
|
21
|
+
Rake::Task['test:effective_test_bot'].invoke
|
20
22
|
end
|
21
23
|
|
22
24
|
namespace :bot do
|
23
|
-
desc 'Runs
|
25
|
+
desc 'Runs effective_test_bot environment test'
|
24
26
|
task :environment do
|
25
|
-
Rake::Task[
|
27
|
+
Rake::Task['test:effective_test_bot_environment'].invoke
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Deletes all effective_test_bot temporary, failure and tour screenshots'
|
31
|
+
task :purge do
|
32
|
+
FileUtils.rm_rf(Rails.root + 'test/tour')
|
33
|
+
FileUtils.rm_rf(Rails.root + 'tmp/test_bot')
|
34
|
+
puts "Successfully purged all effective_test_bot screenshots"
|
26
35
|
end
|
27
36
|
end
|
28
37
|
|
@@ -45,9 +45,10 @@ module TestBotable
|
|
45
45
|
options[:resource_name].pluralize
|
46
46
|
].compact.join('/') + '#' + test.to_s
|
47
47
|
|
48
|
-
method_name = test_bot_method_name('crud_test', label || options_for_method[:current_test])
|
49
48
|
next if EffectiveTestBot.skip?(label || options_for_method[:current_test])
|
50
49
|
|
50
|
+
method_name = test_bot_method_name('crud_test', label || options_for_method[:current_test])
|
51
|
+
|
51
52
|
define_method(method_name) { crud_action_test(test, resource, user, options_for_method) }
|
52
53
|
end
|
53
54
|
end
|
@@ -21,9 +21,9 @@ module TestBotable
|
|
21
21
|
|
22
22
|
[:sign_up, :sign_in_valid, :sign_in_invalid].each do |test|
|
23
23
|
options[:current_test] = label || test
|
24
|
+
next if EffectiveTestBot.skip?(options[:current_test])
|
24
25
|
|
25
26
|
method_name = test_bot_method_name('devise_test', options[:current_test])
|
26
|
-
next if EffectiveTestBot.skip?(options[:current_test])
|
27
27
|
|
28
28
|
define_method(method_name) { devise_action_test(test, options) }
|
29
29
|
end
|
@@ -19,9 +19,9 @@ module TestBotable
|
|
19
19
|
|
20
20
|
def member_test(controller, action, user, obj_to_param = nil, options = {})
|
21
21
|
options[:current_test] = options.delete(:label) || "#{controller}##{action}"
|
22
|
+
return if EffectiveTestBot.skip?(options[:current_test])
|
22
23
|
|
23
24
|
method_name = test_bot_method_name('member_test', options[:current_test])
|
24
|
-
return if EffectiveTestBot.skip?(options[:current_test])
|
25
25
|
|
26
26
|
define_method(method_name) { member_action_test(controller, action, user, obj_to_param, options) }
|
27
27
|
end
|
@@ -17,9 +17,9 @@ module TestBotable
|
|
17
17
|
|
18
18
|
def page_test(path, user, options = {})
|
19
19
|
options[:current_test] = options.delete(:label) || path.to_s
|
20
|
+
return if EffectiveTestBot.skip?(options[:current_test])
|
20
21
|
|
21
22
|
method_name = test_bot_method_name('page_test', options[:current_test])
|
22
|
-
return if EffectiveTestBot.skip?(options[:current_test])
|
23
23
|
|
24
24
|
define_method(method_name) { page_action_test(path, user, options) }
|
25
25
|
end
|
@@ -16,9 +16,9 @@ module TestBotable
|
|
16
16
|
|
17
17
|
def redirect_test(from_path, to_path, user, options = {})
|
18
18
|
options[:current_test] = options.delete(:label) || "#{from_path} to #{to_path}"
|
19
|
+
return if EffectiveTestBot.skip?(options[:current_test])
|
19
20
|
|
20
21
|
method_name = test_bot_method_name('redirect_test', options[:current_test])
|
21
|
-
return if EffectiveTestBot.skip?(options[:current_test])
|
22
22
|
|
23
23
|
define_method(method_name) { redirect_action_test(from_path, to_path, user, options) }
|
24
24
|
end
|
@@ -19,9 +19,9 @@ module TestBotable
|
|
19
19
|
|
20
20
|
def wizard_test(from_path, to_path, user, options = {})
|
21
21
|
options[:current_test] = options.delete(:label) || "#{from_path} to #{to_path}"
|
22
|
+
return if EffectiveTestBot.skip?(options[:current_test])
|
22
23
|
|
23
24
|
method_name = test_bot_method_name('wizard_test', options[:current_test])
|
24
|
-
return if EffectiveTestBot.skip?(options[:current_test])
|
25
25
|
|
26
26
|
define_method(method_name) { wizard_action_test(from_path, to_path, user, options) }
|
27
27
|
end
|
@@ -51,7 +51,14 @@ module EffectiveTestBotAssertions
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def assert_no_exceptions(message = nil)
|
54
|
-
assert exceptions.blank?, message || "(no_exceptions) Unexpected exception:\n#{exceptions.join("\n")}\n========== End
|
54
|
+
assert exceptions.blank?, message || "(no_exceptions) Unexpected exception:\n#{exceptions.join("\n")}\n========== End of rails server exception ==========\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
# This must be run after submit_form()
|
58
|
+
# It ensures there are no HTML5 validation errors that would prevent the form from being submit
|
59
|
+
def assert_no_html5_form_validation_errors(message = nil)
|
60
|
+
errors = all(':invalid', visible: false).map { |field| field['name'] }
|
61
|
+
assert errors.blank?, message || "(no_html5_form_validation_errors) Unable to submit form, unexpected HTML5 validation error present on the following fields:\n#{errors.join("\n")}"
|
55
62
|
end
|
56
63
|
|
57
64
|
# assert_flash
|
@@ -84,17 +91,20 @@ module EffectiveTestBotAssertions
|
|
84
91
|
# assert_no_assigns_errors :post
|
85
92
|
def assert_no_assigns_errors(key = nil, message = nil)
|
86
93
|
if key.present?
|
87
|
-
|
94
|
+
errors = (assigns[key.to_s] || {})['errors']
|
95
|
+
assert errors.blank?, message || "(no_assigns_errors) Unexpected @#{key} rails validation errors:\n#{errors}"
|
88
96
|
else
|
89
97
|
assigns.each do |key, value|
|
90
|
-
|
98
|
+
errors = value['errors']
|
99
|
+
assert errors.blank?, message || "(no_assigns_errors) Unexpected @#{key} rails validation errors:\n#{errors}"
|
91
100
|
end
|
92
101
|
end
|
93
102
|
end
|
94
103
|
|
95
104
|
# assert_assigns_errors :post
|
96
105
|
def assert_assigns_errors(key, message = nil)
|
97
|
-
|
106
|
+
errors = (assigns[key.to_s] || {})['errors']
|
107
|
+
assert errors.present?, message || "(assigns_errors) Expected @#{key}.errors to be present"
|
98
108
|
end
|
99
109
|
|
100
110
|
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
module EffectiveTestBotFormFiller
|
4
|
+
DIGITS = ('1'..'9').to_a
|
5
|
+
LETTERS = ('A'..'Z').to_a
|
6
|
+
|
7
|
+
# Fill a boostrap tabs based form
|
8
|
+
def fill_bootstrap_tabs_form(fills = {}, boostrap_tab_elements = nil)
|
9
|
+
fills = HashWithIndifferentAccess.new(fills) unless fills.kind_of?(HashWithIndifferentAccess)
|
10
|
+
|
11
|
+
tabs = boostrap_tab_elements || all("a[data-toggle='tab']")
|
12
|
+
|
13
|
+
# If there's only 1 tab, just fill it out
|
14
|
+
(fill_form_fields(fills) and return) unless tabs.length > 1
|
15
|
+
|
16
|
+
# If there's more than one tab:
|
17
|
+
# We first fill in all fields that are outside of the tab-content
|
18
|
+
# Then we start at the first, and go left-to-right through all the tabs
|
19
|
+
# clicking each one and filling any form fields found within
|
20
|
+
|
21
|
+
active_tab = find("li.active > a[data-toggle='tab']")
|
22
|
+
tab_content = find("div#{active_tab['href']}").find(:xpath, '..')
|
23
|
+
|
24
|
+
excluding_fields_with_parent(tab_content) { fill_form_fields(fills) }
|
25
|
+
|
26
|
+
# Refresh the tabs, as they may have changed
|
27
|
+
tabs = all("a[data-toggle='tab']")
|
28
|
+
|
29
|
+
# Click through each tab and fill the form inside it.
|
30
|
+
tabs.each do |tab|
|
31
|
+
# changing the call to to fill_bootstrap_tabs_form for recursiveness should work
|
32
|
+
# but it would be an extra all() lookup, and probably not worth it.
|
33
|
+
tab.click()
|
34
|
+
synchronize!
|
35
|
+
save_test_bot_screenshot
|
36
|
+
|
37
|
+
within("div#{tab['href']}") { fill_form_fields(fills) }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# Only fills in visible fields
|
43
|
+
# fill_form(:email => 'somethign@soneone.com', :password => 'blahblah', 'user.last_name' => 'hlwerewr')
|
44
|
+
def fill_form_fields(fills = {})
|
45
|
+
fills = HashWithIndifferentAccess.new(fills) unless fills.kind_of?(HashWithIndifferentAccess)
|
46
|
+
|
47
|
+
# Support for the cocoon gem
|
48
|
+
all('a.add_fields[data-association-insertion-template]').each do |field|
|
49
|
+
next if skip_form_field?(field)
|
50
|
+
2.times { field.click(); save_test_bot_screenshot }
|
51
|
+
end
|
52
|
+
|
53
|
+
all('input,select,textarea').each do |field|
|
54
|
+
next if skip_form_field?(field)
|
55
|
+
|
56
|
+
case [field.tag_name, field['type']].compact.join('_')
|
57
|
+
when 'input_text', 'input_email', 'input_password', 'input_tel', 'input_number', 'input_checkbox', 'input_radio', 'textarea'
|
58
|
+
field.set(value_for_field(field, fills))
|
59
|
+
when 'select'
|
60
|
+
if field['class'].to_s.include?('select2') # effective_select
|
61
|
+
page.execute_script("try { $('select##{field['id']}').select2('open'); } catch(e) {};")
|
62
|
+
save_test_bot_screenshot
|
63
|
+
end
|
64
|
+
|
65
|
+
field.select(value_for_field(field, fills), match: :first)
|
66
|
+
when 'input_file'
|
67
|
+
if field['class'].to_s.include?('asset-box-uploader-fileinput')
|
68
|
+
upload_effective_asset(field, value_for_field(field, fills))
|
69
|
+
else
|
70
|
+
field.set(value_for_field(field, fills))
|
71
|
+
end
|
72
|
+
when 'input_submit', 'input_search'
|
73
|
+
# Do nothing
|
74
|
+
else
|
75
|
+
raise "unsupported field type #{[field.tag_name, field['type']].compact.join('_')}"
|
76
|
+
end
|
77
|
+
|
78
|
+
save_test_bot_screenshot
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Generates an appropriately pseudo-random value for the given field
|
83
|
+
# Pass in a Hash of fills to define pre-selected values
|
84
|
+
#
|
85
|
+
# Operates on just string keys, no symbols here
|
86
|
+
|
87
|
+
def value_for_field(field, fills = nil)
|
88
|
+
field_name = [field.tag_name, field['type']].compact.join('_')
|
89
|
+
attributes = field['name'].to_s.gsub(']', '').split('[') # user[something_attributes][last_name] => ['user', 'something_attributes', 'last_name']
|
90
|
+
|
91
|
+
fill_value = fill_value_for_field(fills, attributes)
|
92
|
+
|
93
|
+
# If there is a predefined fill value for this field, return it here
|
94
|
+
# except for select fields which are treated differently, so we can match fill values on both the html text or value
|
95
|
+
# this edge case is implemented below
|
96
|
+
if fill_value.present? && !['select'].include?(field_name)
|
97
|
+
return fill_value
|
98
|
+
end
|
99
|
+
|
100
|
+
case field_name
|
101
|
+
when 'input_text'
|
102
|
+
classes = field['class'].to_s.split(' ')
|
103
|
+
|
104
|
+
if classes.include?('date') # Let's assume this is a date input.
|
105
|
+
if attributes.last.to_s.include?('end') # Make sure end dates are after start dates
|
106
|
+
Faker::Date.forward(365).strftime('%Y-%m-%d')
|
107
|
+
else
|
108
|
+
Faker::Date.backward(365).strftime('%Y-%m-%d')
|
109
|
+
end
|
110
|
+
elsif classes.include?('datetime')
|
111
|
+
if attributes.last.to_s.include?('end')
|
112
|
+
Faker::Date.forward(365).strftime('%Y-%m-%d %H:%m')
|
113
|
+
else
|
114
|
+
Faker::Date.backward(365).strftime('%Y-%m-%d %H:%m')
|
115
|
+
end
|
116
|
+
elsif classes.include?('price') # effective_form_inputs price
|
117
|
+
4.times.map { DIGITS.sample }.join('') + '.00'
|
118
|
+
elsif classes.include?('numeric')
|
119
|
+
min = (Float(field['min']) rescue 1)
|
120
|
+
max = (Float(field['max']) rescue 1000)
|
121
|
+
number = Random.new.rand(min..max)
|
122
|
+
number.kind_of?(Float) ? number.round(2) : number
|
123
|
+
elsif attributes.last.to_s.include?('first_name')
|
124
|
+
Faker::Name.first_name
|
125
|
+
elsif attributes.last.to_s.include?('last_name')
|
126
|
+
Faker::Name.last_name
|
127
|
+
elsif attributes.last.to_s.include?('name')
|
128
|
+
Faker::Name.name
|
129
|
+
elsif attributes.last.to_s.include?('postal') # Make a Canadian Postal Code
|
130
|
+
LETTERS.sample + DIGITS.sample + LETTERS.sample + ' ' + DIGITS.sample + LETTERS.sample + DIGITS.sample
|
131
|
+
else
|
132
|
+
Faker::Lorem.word
|
133
|
+
end
|
134
|
+
|
135
|
+
when 'select'
|
136
|
+
if fill_value.present? # accept a value or text
|
137
|
+
field.all('option:enabled').each do |option|
|
138
|
+
return option.text if (option.text == fill_value || option.value.to_s == fill_value)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
field.all('option:enabled').select { |option| option.value.present? }.sample.try(:text) || '' # Don't select an empty option
|
143
|
+
when 'input_number'
|
144
|
+
min = (Float(field['min']) rescue 1)
|
145
|
+
max = (Float(field['max']) rescue 1000)
|
146
|
+
number = Random.new.rand(min..max)
|
147
|
+
number.kind_of?(Float) ? number.round(2) : number
|
148
|
+
when 'input_email'
|
149
|
+
Faker::Internet.email
|
150
|
+
when 'input_password'
|
151
|
+
# Use the same password throughout a single test. Allows passwords and password_confirmations to match.
|
152
|
+
@test_bot_current_password ||= Faker::Internet.password
|
153
|
+
when 'input_tel'
|
154
|
+
d = 10.times.map { DIGITS.sample }
|
155
|
+
d[0] + d[1] + d[2] + '-' + d[3] + d[4] + d[5] + '-' + d[6] + d[7] + d[8] + d[9]
|
156
|
+
when 'textarea'
|
157
|
+
Faker::Lorem.sentence
|
158
|
+
when 'input_checkbox'
|
159
|
+
[true, false].sample
|
160
|
+
when 'input_radio'
|
161
|
+
[true, false].sample
|
162
|
+
when 'input_file'
|
163
|
+
"#{File.dirname(__FILE__)}/effective_assets_upload_file._test"
|
164
|
+
else
|
165
|
+
raise "fill_value unsupported field type: #{field['type']}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# The field here is going to be the %input{:type => file}. Files can be one or more pathnames
|
170
|
+
# http://stackoverflow.com/questions/5188240/using-selenium-to-imitate-dragging-a-file-onto-an-upload-element/11203629#11203629
|
171
|
+
def upload_effective_asset(field, files)
|
172
|
+
files = Array(files)
|
173
|
+
uid = field['id']
|
174
|
+
|
175
|
+
js = "fileList = Array();"
|
176
|
+
|
177
|
+
files.each_with_index do |file, i|
|
178
|
+
# Generate a fake input selector
|
179
|
+
page.execute_script("if($('#effectiveAssetsPlaceholder#{i}').length == 0) {effectiveAssetsPlaceholder#{i} = window.$('<input/>').attr({id: 'effectiveAssetsPlaceholder#{i}', type: 'file'}).appendTo('body'); }")
|
180
|
+
|
181
|
+
# Attach file to the fake input selector through Capybara
|
182
|
+
page.document.attach_file("effectiveAssetsPlaceholder#{i}", files[i])
|
183
|
+
|
184
|
+
# Build up the fake js event
|
185
|
+
js = "#{js} fileList.push(effectiveAssetsPlaceholder#{i}.get(0).files[0]);"
|
186
|
+
end
|
187
|
+
|
188
|
+
# Trigger the fake drop event
|
189
|
+
page.execute_script("#{js} e = $.Event('drop'); e.originalEvent = {dataTransfer : { files : fileList } }; $('#s3_#{uid}').trigger(e);")
|
190
|
+
|
191
|
+
# Remove the file inputs we created
|
192
|
+
page.execute_script("$('input[id^=effectiveAssetsPlaceholder]').remove();")
|
193
|
+
|
194
|
+
# Wait till the Uploader bar goes away
|
195
|
+
begin
|
196
|
+
Timeout.timeout(files.length * 5) do
|
197
|
+
within("#asset-box-input-#{uid}") do
|
198
|
+
within('.uploads') do
|
199
|
+
while (first('.upload').present? rescue false) do
|
200
|
+
save_test_bot_screenshot
|
201
|
+
sleep(0.5)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
rescue Timeout::Error
|
207
|
+
puts "file upload timed out after #{files.length * 5}s"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def fill_value_for_field(fills, attributes)
|
214
|
+
return if fills.blank? || attributes.blank?
|
215
|
+
|
216
|
+
key = nil
|
217
|
+
attributes.reverse_each do |name| # match last_name, then something_attributes.last_name, then user.something_attributes.last_name
|
218
|
+
key = (key.present? ? "#{name}.#{key}" : name) # builds up the string as we go along
|
219
|
+
return fills[key].to_s if fills.key?(key)
|
220
|
+
end
|
221
|
+
|
222
|
+
nil
|
223
|
+
end
|
224
|
+
|
225
|
+
# Takes a capybara element
|
226
|
+
def excluding_fields_with_parent(element, &block)
|
227
|
+
@test_bot_excluded_fields_xpath = element.path
|
228
|
+
yield
|
229
|
+
@test_bot_excluded_fields_xpath = nil
|
230
|
+
end
|
231
|
+
|
232
|
+
def skip_form_field?(field)
|
233
|
+
field.visible? == false ||
|
234
|
+
field.disabled? ||
|
235
|
+
['true', true, 1].include?(field['data-test-bot-skip']) ||
|
236
|
+
(@test_bot_excluded_fields_xpath.present? && field.path.include?(@test_bot_excluded_fields_xpath))
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|