effective_test_bot 0.4.1 → 0.4.2

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.
@@ -0,0 +1,39 @@
1
+ # This DSL gives a class level and an instance level way of calling specific test suite
2
+ #
3
+ # class PostsTest < ActionDispatch::IntegrationTest
4
+ # page_test(:posts_path, User.first)
5
+ #
6
+ # test 'a one-off action' do
7
+ # page_action_test(:posts_path, User.first)
8
+ # end
9
+ # end
10
+
11
+
12
+ module TestBotable
13
+ module PageDsl
14
+ extend ActiveSupport::Concern
15
+
16
+ module ClassMethods
17
+
18
+ def page_test(path, user, options = {})
19
+ options[:current_test] = path.to_s
20
+ method_name = test_bot_method_name('page_test', options.delete(:label) || options[:current_test])
21
+
22
+ define_method(method_name) { page_action_test(path, user, options) }
23
+ end
24
+
25
+ end
26
+
27
+ # Instance Methods - Call me from within a test
28
+ def page_action_test(path, user, options = {})
29
+ begin
30
+ assign_test_bot_lets!(options.reverse_merge!(user: user, page_path: path))
31
+ rescue => e
32
+ raise "Error: #{e.message}. Expected usage: crud_action_test(:new, Post || Post.new, User.first, options_hash)"
33
+ end
34
+
35
+ self.send(:test_bot_page_test)
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,37 @@
1
+ # This DSL gives a class level and an instance level way of calling specific test suite
2
+ #
3
+ # class AboutTest < ActionDispatch::IntegrationTest
4
+ # redirect_test('/about', '/new-about', User.first)
5
+ #
6
+ # test 'a one-off action' do
7
+ # redirect_action_test('/about', '/new-about', User.first)
8
+ # end
9
+ # end
10
+
11
+ module TestBotable
12
+ module RedirectDsl
13
+ extend ActiveSupport::Concern
14
+
15
+ module ClassMethods
16
+
17
+ def redirect_test(from_path, to_path, user, options = {})
18
+ options[:current_test] = "#{from_path} to #{to_path}"
19
+ method_name = test_bot_method_name('redirect_test', options.delete(:label) || options[:current_test])
20
+
21
+ define_method(method_name) { redirect_action_test(from_path, to_path, user, options) }
22
+ end
23
+ end
24
+
25
+ # Instance Methods - Call me from within a test
26
+ def redirect_action_test(from_path, to_path, user, options = {})
27
+ begin
28
+ assign_test_bot_lets!(options.reverse_merge!(from_path: from_path, to_path: to_path, user: user))
29
+ rescue => e
30
+ raise "Error: #{e.message}. Expected usage: redirect_action_test('/about', '/new-about', User.first)"
31
+ end
32
+
33
+ self.send(:test_bot_redirect_test)
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,41 @@
1
+ # This DSL gives a class level and an instance level way of calling specific test suite
2
+ #
3
+ # class PostsTest < ActionDispatch::IntegrationTest
4
+ # member_test('admin/jobs', 'unarchive', User.first, Post.first)
5
+ #
6
+ # test 'a one-off action' do
7
+ # member_action_test('admin/jobs', 'unarchive', User.first)
8
+ # end
9
+ # end
10
+
11
+ # A member_test assumes assumes route.name.present? && route.verb.to_s.include?('GET') && route.path.required_names == ['id']
12
+ # we HAVE TO build or have available one of these resources so we can pass the ID to it and see what happens :)
13
+
14
+ module TestBotable
15
+ module WizardDsl
16
+ extend ActiveSupport::Concern
17
+
18
+ module ClassMethods
19
+
20
+ def wizard_test(from_path, to_path, user, options = {})
21
+ options[:current_test] = "#{from_path} to #{to_path}"
22
+ method_name = test_bot_method_name('wizard_test', options.delete(:label) || options[:current_test])
23
+
24
+ define_method(method_name) { wizard_action_test(from_path, to_path, user, options) }
25
+ end
26
+
27
+ end
28
+
29
+ # Instance Methods - Call me from within a test
30
+ def wizard_action_test(from_path, to_path, user, options = {})
31
+ begin
32
+ assign_test_bot_lets!(options.reverse_merge!(from_path: from_path, to_path: to_path, user: user))
33
+ rescue => e
34
+ raise "Error: #{e.message}. Expected usage: wizard_action_test('/fee_wizard/step1', '/fee_wizard/step5', User.first)"
35
+ end
36
+
37
+ self.send(:test_bot_wizard_test)
38
+ end
39
+
40
+ end
41
+ end
@@ -1,17 +1,17 @@
1
1
  module EffectiveTestBotAssertions
2
- def assert_signed_in
2
+ def assert_signed_in(message = nil)
3
3
  visit new_user_session_path
4
- assert_content I18n.t('devise.failure.already_authenticated')
5
- assert page.has_no_selector?('form#new_user')
4
+ assert_content I18n.t('devise.failure.already_authenticated') #, message || '(signed_in) Expected devise already_authenticated content to be present'
5
+ assert page.has_no_selector?('form#new_user'), message || '(signed_in) Expected new_user form to be blank'
6
6
  end
7
7
 
8
- def assert_signed_out
8
+ def assert_signed_out(message = nil)
9
9
  visit new_user_session_path
10
- refute_content I18n.t('devise.failure.already_authenticated')
11
- assert page.has_selector?('form#new_user')
10
+ refute_content I18n.t('devise.failure.already_authenticated') #, message || '(signed_out) Expected devise already_authenticated content to be blank'
11
+ assert page.has_selector?('form#new_user'), message || '(signed_out) Expected new_user form to be present'
12
12
  end
13
13
 
14
- def assert_page_title(title = :any, message = 'Expected page title to be present')
14
+ def assert_page_title(title = :any, message = '(page_title) Expected page title to be present')
15
15
  if title.present? && title != :any
16
16
  assert_title(title) # Capybara TitleQuery, match this text
17
17
  else
@@ -20,44 +20,76 @@ module EffectiveTestBotAssertions
20
20
  end
21
21
  end
22
22
 
23
- def assert_page_status(status = 200, message = 'Expected :status: HTTP status code')
23
+ def assert_page_status(status = 200, message = '(page_status) Expected :status: HTTP status code')
24
24
  assert_equal status, page.status_code, message.sub(':status:', status.to_s)
25
25
  end
26
26
 
27
- def assert_no_js_errors
27
+ def assert_current_path(path, message = '(current_path) Expected current_path to be :path:')
28
+ path = public_send(path) if path.kind_of?(Symbol)
29
+ assert_equal path, page.current_path, message.sub(':path', path.to_s)
30
+ end
31
+
32
+ # assert_redirect '/about'
33
+ # assert_redirect '/about', '/about-us'
34
+ def assert_redirect(from_path, to_path = nil, message = nil)
35
+ if to_path.present?
36
+ assert_equal to_path, page.current_path, message || "(redirect) Expected redirect from #{from_path} to #{to_path}"
37
+ else
38
+ refute_equal from_path, page.current_path, message || "(redirect) Expected redirect away from #{from_path}"
39
+ end
40
+ end
41
+
42
+
43
+ def assert_no_js_errors(message = nil)
28
44
  errors = page.driver.error_messages
29
- assert_equal 0, errors.size, errors.ai
45
+ assert_equal 0, errors.size, message || "(no_js_errors) Unexpected javascript error: #{errors.join(', ')}"
30
46
  end
31
47
 
32
- def assert_no_unpermitted_params(message = 'Expected no unpermitted params')
48
+ def assert_no_unpermitted_params(message = '(no_unpermitted_params) Expected no unpermitted params')
33
49
  assert_equal [], unpermitted_params, message
34
50
  end
35
51
 
36
52
  # assert_flash
37
53
  # assert_flash :success
38
54
  # assert_flash :error, 'there was a specific error'
39
- def assert_flash(key = nil, value = nil)
55
+ def assert_flash(key = nil, value = nil, message = nil)
40
56
  if key.present? && value.present?
41
- assert_equal value, flash[key.to_s]
57
+ assert_equal value, flash[key.to_s], message || "(flash) Expected flash[#{key}] to equal #{value}. Instead, it was: #{value}"
42
58
  elsif key.present?
43
- assert flash[key.to_s].present?, "Expected flash[#{key}] to be present"
59
+ assert flash[key.to_s].present?, message || "(flash) Expected flash[#{key}] to be present"
44
60
  else
45
- assert flash.present?, 'Expected flash to be present'
61
+ assert flash.present?, message || '(flash) Expected flash to be present'
46
62
  end
47
63
  end
48
64
 
49
65
  # assert_assigns
50
66
  # assert_assigns :current_user
51
67
  # assert_assigns :current_user, true
52
- def assert_assigns(key = nil, value = nil)
68
+ def assert_assigns(key = nil, value = nil, message = nil)
53
69
  if key.present? && value.present?
54
- assert_equal value, assigns[key.to_s]
70
+ assert_equal value, assigns[key.to_s], message || "(assigns) Expected assigns[#{key}] to equal #{value}. Instead, it was: #{value}"
55
71
  elsif key.present?
56
- assert assigns[key.to_s].present?, "Expected @#{key} to be assigned"
72
+ assert assigns[key.to_s].present?, message || "(assigns) Expected @#{key} to be assigned"
73
+ else
74
+ assert assigns.present?, message || '(assigns) Expected assigns to be present'
75
+ end
76
+ end
77
+
78
+ # assert_no_assigns_errors
79
+ # assert_no_assigns_errors :post
80
+ def assert_no_assigns_errors(key = nil, message = nil)
81
+ if key.present?
82
+ assert_equal [], ((assigns[key.to_s] || {})['errors'] || []), message || "(no_assigns_errors) Expected @#{key}[:errors] to be blank. Instead, it was: #{assigns}"
57
83
  else
58
- assert assigns.present?, 'Expected assigns to be present'
84
+ assigns.each do |key, value|
85
+ assert_equal [], (value['errors'] || []), message || "(no_assigns_errors) Expected @#{key}[:errors] to be blank"
86
+ end
59
87
  end
60
88
  end
61
89
 
90
+ # assert_assigns_errors :post
91
+ def assert_assigns_errors(key, message = nil)
92
+ refute_equal [], ((assigns[key.to_s] || {})['errors'] || []), message || "(assigns_errors) Expected @#{key}[:errors] to be present"
93
+ end
62
94
 
63
95
  end
@@ -14,6 +14,8 @@ module EffectiveTestBotFormHelper
14
14
  end
15
15
 
16
16
  all('input,select,textarea').each do |field|
17
+ next unless field.visible?
18
+
17
19
  case [field.tag_name, field['type']].compact.join('_')
18
20
  when 'input_text', 'input_email', 'input_password', 'input_tel', 'input_number', 'textarea'
19
21
  field.set(fill_value(field, fills))
@@ -23,7 +25,7 @@ module EffectiveTestBotFormHelper
23
25
  field.select(fill_value(field, fills), match: :first)
24
26
  when 'input_file'
25
27
  file_path = fill_value(field, fills)
26
- field['class'].include?('asset-box-uploader-fileinput') ? upload_effective_asset(field, file_path) : field.set(file_path)
28
+ field['class'].to_s.include?('asset-box-uploader-fileinput') ? upload_effective_asset(field, file_path) : field.set(file_path)
27
29
  when 'input_submit', 'input_search'
28
30
  # Do nothing
29
31
  else
@@ -40,6 +42,7 @@ module EffectiveTestBotFormHelper
40
42
  end
41
43
 
42
44
  # Operates on just string keys
45
+ # This function receives the same fill values that you call fill_form with
43
46
  def fill_value(field, fills = nil)
44
47
  attributes = field['name'].to_s.gsub(']', '').split('[') # user[something_attributes][last_name] => ['user', 'something_attributes', 'last_name']
45
48
  field_name = [field.tag_name, field['type']].compact.join('_')
@@ -47,11 +50,12 @@ module EffectiveTestBotFormHelper
47
50
 
48
51
  if fills.present?
49
52
  key = nil
50
- attributes.reverse_each do |name|
51
- key = (key.present? ? "#{name}.#{key}" : name)
53
+ attributes.reverse_each do |name| # match last_name, then something_attributes.last_name, then user.something_attributes.last_name
54
+ key = (key.present? ? "#{name}.#{key}" : name) # builds up the string as we go along
52
55
 
53
56
  if fills.key?(key)
54
57
  fill_value = fills[key]
58
+ # select is treated differently, because we want the passed prefill to match both the html text or value (which is implemented below)
55
59
  ['select'].include?(field_name) ? break : (return fill_value)
56
60
  end
57
61
  end
@@ -86,7 +90,7 @@ module EffectiveTestBotFormHelper
86
90
  Faker::Lorem.word
87
91
  end
88
92
  when 'select'
89
- if fill_value.present? # accept a value or label
93
+ if fill_value.present? # accept a value or text
90
94
  field.all('option').each do |option|
91
95
  return option.text if option.text == fill_value || option.value.to_s == fill_value.to_s
92
96
  end
@@ -126,7 +130,7 @@ module EffectiveTestBotFormHelper
126
130
  def with_raised_unpermitted_params_exceptions(&block)
127
131
  action = nil
128
132
 
129
- begin # This will only work with Rails >= 4.0
133
+ begin # This may only work with Rails >= 4.0
130
134
  action = ActionController::Parameters.action_on_unpermitted_parameters
131
135
  ActionController::Parameters.action_on_unpermitted_parameters = :raise
132
136
  rescue => e
@@ -6,14 +6,14 @@ module EffectiveTestBotLoginHelper
6
6
  end
7
7
 
8
8
  def sign_in(user) # Warden::Test::Helpers
9
- user.kind_of?(String) == true ? login_as(User.find_by_email!(user)) : login_as(user)
9
+ user.kind_of?(String) ? login_as(User.find_by_email!(user)) : login_as(user)
10
10
  end
11
11
 
12
12
  def sign_in_manually(email, password)
13
13
  visit new_user_session_path
14
14
 
15
15
  within('form#new_user') do
16
- fill_form(:email => email, :password => password)
16
+ fill_form(email: email, password: password)
17
17
  submit_form
18
18
  end
19
19
  end
@@ -22,7 +22,7 @@ module EffectiveTestBotLoginHelper
22
22
  visit new_user_registration_path
23
23
 
24
24
  within('form#new_user') do
25
- fill_form(:email => email, :password => password, :password_confirmation => password)
25
+ fill_form(email: email, password: password, password_confirmation: password)
26
26
  submit_form
27
27
  end
28
28
 
@@ -1,5 +1,4 @@
1
1
  module EffectiveTestBotTestHelper
2
-
3
2
  # This makes sure capybara is done, and breaks out of any 'within' blocks
4
3
  def synchronize!
5
4
  page.document.find('html')
@@ -20,6 +19,10 @@ module EffectiveTestBotTestHelper
20
19
  @unpermitted_params = (JSON.parse(Base64.decode64(session.driver.response_headers['Test-Bot-Unpermitted-Params'])) rescue [])
21
20
  end
22
21
 
22
+ def was_redirect?(from_path, to_path = nil)
23
+ from_path != (to_path || page.current_path)
24
+ end
25
+
23
26
  # EffectiveTestBot includes an after_filter on ApplicationController to set an http header
24
27
  # that encodes the flash message, and some of the assigns
25
28
  def flash
@@ -33,5 +36,4 @@ module EffectiveTestBotTestHelper
33
36
  def unpermitted_params
34
37
  @unpermitted_params ||= (JSON.parse(Base64.decode64(page.response_headers['Test-Bot-Unpermitted-Params'])) rescue [])
35
38
  end
36
-
37
39
  end
@@ -0,0 +1,86 @@
1
+ require 'test_helper'
2
+
3
+ module TestBot
4
+ class ApplicationTest < ActionDispatch::IntegrationTest
5
+ CRUD_ACTIONS = %w(index create new edit show update destroy) # Same order as resources :object creates them in
6
+
7
+ class << self
8
+
9
+ # Go through every route, and run an appropriate test suite on it
10
+ def initialize_tests
11
+ puts 'test_bot scanning....'
12
+
13
+ routes = Rails.application.routes.routes.to_a
14
+ seen_actions = Hash.new([]) # {posts: ['new', 'edit'], events: ['new', 'edit', 'show']}
15
+
16
+ #Rails.application.routes.recognize_path('/your/path/here')
17
+ #Rails.application.routes.recognize_path('/admin/jobs/3/unarchive')
18
+ # => {:action=>"unarchive", :controller=>"admin/jobs", :id=>"3"}
19
+
20
+ routes.each_with_index do |route, index|
21
+ controller = route.defaults[:controller]
22
+ action = route.defaults[:action]
23
+
24
+ # Devise Test
25
+ if (controller || '').include?('devise')
26
+ next if seen_actions['devise'].present?
27
+
28
+ puts 'define devise test!!'
29
+ seen_actions['devise'] = true # So we don't repeat it
30
+
31
+ # Redirect Test
32
+ elsif route.app.kind_of?(ActionDispatch::Routing::PathRedirect) && route.path.required_names.blank?
33
+ path = route.path.spec.to_s
34
+ route.path.optional_names.each { |name| path.sub!("(.:#{name})", '') } # Removes (.:format) from path
35
+ redirect_test(path, route.app.path([], nil), User.first)
36
+
37
+ # CRUD Test
38
+ elsif is_crud_controller?(route)
39
+ seen_actions[controller] += [action]
40
+
41
+ next_controller = (routes[index+1].defaults[:controller] rescue :last)
42
+ next_action = (routes[index+1].defaults[:action] rescue :last)
43
+
44
+ # If we're done accumulating CRUD actions, launch the crud_test with all seen actions
45
+ if controller != next_controller || CRUD_ACTIONS.include?(next_action) == false
46
+ begin
47
+ crud_test(controller, User.first, only: seen_actions.delete(controller))
48
+ rescue => e
49
+ puts e.message # Sometimes there is an object that can't be instantiated, so we still want to continue the application test
50
+ end
51
+ end
52
+
53
+ # Member Test
54
+ elsif route.verb.to_s.include?('GET') && route.path.required_names == ['id']
55
+ member_test(controller, action, User.first)
56
+
57
+ # Page Test
58
+ elsif route.verb.to_s.include?('GET') && route.name.present?
59
+ page_test("#{route.name}_path".to_sym, User.first, route: route, label: "#{route.name}_path")
60
+
61
+ else
62
+ puts "skipping #{route.name}_path | #{route.path.spec} | #{route.verb} | #{route.defaults[:controller]} | #{route.defaults[:action]}"
63
+
64
+ end # / Routes
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def is_crud_controller?(route)
71
+ return false unless CRUD_ACTIONS.include?(route.defaults[:action])
72
+
73
+ controller_klass = (route.app.controller(route.defaults) rescue nil) if route.defaults[:controller].present? && route.app.respond_to?(:controller)
74
+ controller_instance = controller_klass.new() if controller_klass
75
+
76
+ # Is this a CRUD capable controller?
77
+ controller_instance && controller_instance.respond_to?(:new) && controller_instance.respond_to?(:create)
78
+ end
79
+
80
+ end
81
+
82
+ initialize_tests
83
+
84
+ end
85
+
86
+ end
@@ -39,11 +39,11 @@ module TestBot
39
39
  assert_equal (original_users_count + 1), User.count
40
40
  end
41
41
 
42
- test '05: test database is back to normal' do
42
+ test '05: test database has reset' do
43
43
  assert_normal
44
44
  end
45
45
 
46
- test '06: capybara can create a user' do
46
+ test '06: capybara can sign up a user' do
47
47
  user = sign_up()
48
48
  assert user.kind_of?(User)
49
49
 
@@ -51,26 +51,30 @@ module TestBot
51
51
  assert_signed_in
52
52
  end
53
53
 
54
- test '07: test database is back to normal' do
54
+ test '07: database and session have reset' do
55
+ assert_signed_out
55
56
  assert_normal
56
57
  end
57
58
 
58
- test '08: capybara session has been reset after manual sign up' do
59
- assert_signed_out
59
+ test '08: capybara can login_as via warden test helper' do
60
60
  create_user!
61
61
  sign_in(email)
62
62
  assert_signed_in
63
63
  end
64
64
 
65
- test '09: test database is back to normal' do
65
+ test '09: database and session have reset' do
66
+ assert_signed_out
66
67
  assert_normal
67
68
  end
68
69
 
69
- test '10: capybara session has been reset after warden login_as' do
70
- assert_signed_out
70
+ test '10: capybara can sign in manually' do
71
+ create_user!
72
+ sign_in_manually(email, password)
73
+ assert_signed_in
71
74
  end
72
75
 
73
- test '11: test database is back to normal' do
76
+ test '11: database and session have reset' do
77
+ assert_signed_out
74
78
  assert_normal
75
79
  end
76
80
 
@@ -78,8 +82,9 @@ module TestBot
78
82
 
79
83
  def assert_normal
80
84
  visit root_path
81
- assert_equal page.status_code, 200
82
- assert_equal original_users_count, User.count
85
+ assert_page_status
86
+ assert_equal original_users_count, User.count, 'Epected User.count to be back to original'
87
+ assert assigns[:current_user].blank?, 'Expected current_user to be blank'
83
88
 
84
89
  # Someitmes it's nice to assert your environment...
85
90
  #assert users(:normal).present?