Module: Incline::Extensions::TestCase::ClassMethods

Defined in:
lib/incline/extensions/test_case.rb

Overview

Adds the #access_tests_for method.

Instance Method Summary collapse

Instance Method Details

#access_tests_for(*actions) ⇒ Object

This method will generate multiple generic access tests for your controller.

The action argument can be one or more actions to test. These can be specified as arguments or an array.

access_tests_for :new, :edit, :show
access_tests_for [ :new, :edit, :show ]

Options are provided after the last action to test. All options will be applied to all actions. The action_params option being the only one that is explicitly for a specific action.

Valid options:

controller

The name of the controller. If not supplied, the controller is inferred from the class name.

url_helper

The code used to generate the URL. If not supplied, the helper is inferred from the controller and action name.

fixture_helper

A string defining the fixture helper to use. If not supplied the pluralized controller name will be used.

fixture_key

The key to use to load a fixture. The default is :one.

allow_anon

Determines if anonymous users should be able to access the action. The default is false.

allow_any_user

Determines if any authenticated user should be able to access the action. The default is false.

allow_groups

Specifies a list of groups that should be able to access the action. The default is nil.

deny_groups

Specifies a list of groups that should not be able to access the action. The default is nil.

allow_admin

Specifies if a system admin should be able to access the action. The default is true.

method

Specifies the method to process the action with. The default is ‘get’.

success

Determines the result on success. Defauls to :success for ‘get’ requests, otherwise the pluralized controller helper path.

failure

Determines the result on failure for non-anon tests. Defaults to ‘main_app.root_path’.

anon_failure

Determines the result on failure for anon tests. Defaults to ‘incline.login_path’.

action_params

You can pass params to the action by specifying a hash containing them in this fashion. e.g. - :new_params => { } # params for :new action

return_code

If this is set to a true value, the test code is generated, but not executed. The test code will then be returned as a string. If this is not to a true value, the test code will be executed as generated and nil will be returned.

access_tests_for :new, controller: 'users', allow_anon: true, allow_any_user: false, allow_admin: false


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/incline/extensions/test_case.rb', line 57

def access_tests_for(*actions)

  options = actions.delete(actions.last) if actions.last.is_a?(::Hash)
  options ||= { }

  if actions.count == 1 && actions.first.is_a?(::Array)
    actions = actions.first
  end

  if actions.count > 1
    data = actions.map{|act| access_tests_for(act, options.dup)}
    if options[:return_code]
      return data.join
    else
      return nil
    end
  end

  action = actions.first

  options = {
      allow_anon:         false,
      allow_any_user:     false,
      allow_groups:       nil,
      deny_groups:        nil,
      allow_admin:        true,
      fixture_key:        :one,
      failure:            'main_app.root_path',
      anon_failure:       'incline.login_path'
  }.merge((options || {}).symbolize_keys)

  action = action.to_sym
  params = options[:"#{action}_params"]
  params = params.inspect if params.is_a?(::Hash)
  params = nil unless params.is_a?(::String)

  # guess at the method to use.
  if options[:method].blank?
    options[:method] =
        if action == :destroy
          'delete'
        elsif action == :update
          'patch'
        elsif action == :create
          'post'
        else
          'get'
        end
  end
  options[:method] = options[:method].to_sym

  if options[:controller].blank?
    # only works with controller tests (eg - UsersControllerTest => users_controller_test => users_controller)
    options[:controller] = self.name.underscore.rpartition('_')[0]
  else
    options[:controller] = options[:controller].to_s.underscore
  end

  if options[:controller] =~ /_controller$/
    options[:controller] = options[:controller].rpartition('_')[0]
  end

  if options[:fixture_helper].blank?
    options[:fixture_helper] = options[:controller].pluralize
  end

  if options[:url_helper].blank?
    fix_val = "#{options[:fixture_helper]}(#{options[:fixture_key].inspect})"
    options[:url_helper] =
        case action
          when :show, :update, :destroy   then  "#{options[:controller].singularize}_path(#{fix_val})"
          when :edit                      then  "edit_#{options[:controller].singularize}_path(#{fix_val})"
          when :new                       then  "new_#{options[:controller].singularize}_path"
          else                                  "#{options[:controller].pluralize}_path"
        end
  end

  if options[:success].blank?
    if options[:method] == :get
      options[:success] = :success
    else
      options[:success] = "#{options[:controller].pluralize}_path"
    end
  end


  method = options[:method]
  url_helper = options[:url_helper]

  tests = [
      #   label         result                    user    group   success_override    failure_override
      [ 'anonymous',  options[:allow_anon],       nil,    nil,    nil,                options[:anon_failure] ],
      [ 'any user',   options[:allow_any_user],   :basic ],
      [ 'admin user', options[:allow_admin],      :admin ]
  ]

  unless options[:allow_groups].blank?
    if options[:allow_groups].is_a?(::String)
      options[:allow_groups] = options[:allow_groups].gsub(',', ';').split(';').map{|v| v.strip}
    end
    options[:allow_groups].each do |group|
      tests << [ "#{group} member", true, :basic, group ]
    end
  end

  unless options[:deny_groups].blank?
    if options[:deny_groups].is_a?(::String)
      options[:deny_groups] = options[:deny_groups].gsub(',', ';').split(';').map{|v| v.strip}
    end
    options[:deny_groups].each do |group|
      tests << [ "#{group} member", false, :basic, group ]
    end
  end

  all_code = ''

  tests.each do |(label, result, user, group, success_override, failure_override)|
    expected_result = result ? (success_override || options[:success]) : (failure_override || options[:failure])

    # build the code block
    test_code = "test \"should #{result ? '' : 'not '}allow access to #{action} for #{label}\" do\n"

    if user
      test_code += "  user = incline_users(#{user.inspect})\n"
      if group
        test_code += "  group = Incline::AccessGroup.find_or_create_by(name: #{group.inspect})\n"
        test_code += "  user.groups << group\n"
      end
      test_code += "  log_in_as user\n"
    end

    test_code += "  path = #{url_helper}\n"

    if params.blank?
      test_code += "  #{method}(path)\n"
    else
      test_code += "  #{method}(path, #{params})\n"
    end

    if expected_result.is_a?(::Symbol)
      test_code += "  assert_response #{expected_result.inspect}\n"
    else
      test_code += "  assert_redirected_to #{expected_result}\n"
    end

    test_code += "end\n"

    all_code += test_code

    unless options[:return_code]
      Incline::Log::debug test_code
      eval test_code
    end
  end

  options[:return_code] ? all_code : nil

end