effective_test_bot 0.4.1 → 0.4.2

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