g5_authenticatable 0.4.2 → 0.5.0

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +12 -0
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile +2 -2
  5. data/README.md +186 -1
  6. data/app/controllers/concerns/g5_authenticatable/authorization.rb +21 -0
  7. data/app/models/g5_authenticatable/role.rb +8 -0
  8. data/app/models/g5_authenticatable/user.rb +41 -0
  9. data/app/policies/g5_authenticatable/base_policy.rb +73 -0
  10. data/config/initializers/rolify.rb +8 -0
  11. data/g5_authenticatable.gemspec +3 -0
  12. data/lib/g5_authenticatable/engine.rb +3 -0
  13. data/lib/g5_authenticatable/rspec.rb +1 -0
  14. data/lib/g5_authenticatable/test/factory.rb +51 -1
  15. data/lib/g5_authenticatable/test/feature_helpers.rb +15 -2
  16. data/lib/g5_authenticatable/version.rb +1 -1
  17. data/lib/generators/g5_authenticatable/install/USAGE +7 -1
  18. data/lib/generators/g5_authenticatable/install/install_generator.rb +33 -6
  19. data/lib/generators/g5_authenticatable/install/templates/403.html +26 -0
  20. data/lib/generators/g5_authenticatable/install/templates/application_policy.rb +4 -0
  21. data/lib/generators/g5_authenticatable/install/templates/{g5_authenticatable.rb → initializer.rb} +0 -0
  22. data/lib/generators/g5_authenticatable/install/templates/migrate/add_g5_authenticatable_users_contact_info.rb +11 -0
  23. data/lib/generators/g5_authenticatable/install/templates/migrate/create_g5_authenticatable_roles.rb +20 -0
  24. data/lib/generators/g5_authenticatable/install/templates/{create_g5_authenticatable_users.rb → migrate/create_g5_authenticatable_users.rb} +0 -0
  25. data/spec/controllers/application_controller_spec.rb +12 -0
  26. data/spec/controllers/concerns/g5_authenticatable/authorization.rb +50 -0
  27. data/spec/dummy/app/assets/javascripts/posts.js +2 -0
  28. data/spec/dummy/app/assets/stylesheets/posts.css +4 -0
  29. data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
  30. data/spec/dummy/app/controllers/application_controller.rb +1 -0
  31. data/spec/dummy/app/controllers/posts_controller.rb +74 -0
  32. data/spec/dummy/app/helpers/posts_helper.rb +2 -0
  33. data/spec/dummy/app/models/post.rb +3 -0
  34. data/spec/dummy/app/policies/application_policy.rb +4 -0
  35. data/spec/dummy/app/policies/post_policy.rb +4 -0
  36. data/spec/dummy/app/views/home/index.html.erb +40 -0
  37. data/spec/dummy/app/views/posts/_form.html.erb +21 -0
  38. data/spec/dummy/app/views/posts/edit.html.erb +6 -0
  39. data/spec/dummy/app/views/posts/index.html.erb +30 -0
  40. data/spec/dummy/app/views/posts/new.html.erb +5 -0
  41. data/spec/dummy/app/views/posts/show.html.erb +17 -0
  42. data/spec/dummy/config/database.yml.ci +1 -2
  43. data/spec/dummy/config/initializers/g5_authenticatable.rb +8 -0
  44. data/spec/dummy/config/routes.rb +2 -0
  45. data/spec/dummy/db/migrate/20150428182339_add_g5_authenticatable_users_contact_info.rb +11 -0
  46. data/spec/dummy/db/migrate/20150429212919_create_g5_authenticatable_roles.rb +20 -0
  47. data/spec/dummy/db/migrate/20150509061150_create_posts.rb +9 -0
  48. data/spec/dummy/db/schema.rb +37 -4
  49. data/spec/dummy/public/403.html +26 -0
  50. data/spec/factories/post.rb +6 -0
  51. data/spec/features/default_role_authorization_spec.rb +254 -0
  52. data/spec/features/sign_in_spec.rb +144 -8
  53. data/spec/lib/generators/g5_authenticatable/install_generator_spec.rb +72 -1
  54. data/spec/models/g5_authenticatable/role_spec.rb +81 -0
  55. data/spec/models/g5_authenticatable/user_spec.rb +340 -3
  56. data/spec/models/post_spec.rb +12 -0
  57. data/spec/policies/application_policy_spec.rb +171 -0
  58. data/spec/policies/post_policy_spec.rb +35 -0
  59. data/spec/requests/default_role_authorization_spec.rb +169 -0
  60. data/spec/spec_helper.rb +0 -3
  61. data/spec/support/shared_examples/super_admin_authorizer.rb +33 -0
  62. metadata +109 -5
  63. data/circle.yml +0 -4
@@ -0,0 +1,254 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Default role-based authorization UI' do
4
+ describe 'Posts index' do
5
+ let(:visit_posts_index) { visit_path_and_login_with(posts_path, user) }
6
+
7
+ let!(:post) { FactoryGirl.create(:post, author: user) }
8
+ let!(:other_post) { FactoryGirl.create(:post) }
9
+
10
+ before { visit_posts_index }
11
+
12
+ context 'when authenticated user is a super admin' do
13
+ let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
14
+
15
+ it 'renders the posts index page' do
16
+ expect(current_path).to eq(posts_path)
17
+ end
18
+
19
+ it 'shows the first post' do
20
+ expect(page).to have_content(post.content)
21
+ end
22
+
23
+ it 'shows the second post' do
24
+ expect(page).to have_content(other_post.content)
25
+ end
26
+ end
27
+
28
+ context 'when authenticated user is not a super admin' do
29
+ let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
30
+
31
+ it 'displays an error message' do
32
+ expect(page).to have_content(/forbidden/i)
33
+ end
34
+
35
+ it 'does not show the first post' do
36
+ expect(page).to_not have_content(post.content)
37
+ end
38
+
39
+ it 'does not show the second post' do
40
+ expect(page).to_not have_content(other_post.content)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe 'Show post' do
46
+ let(:show_post) { visit_path_and_login_with(post_path(post.id), user) }
47
+
48
+ let!(:post) { FactoryGirl.create(:post, author: user) }
49
+
50
+ before { show_post }
51
+
52
+ context 'when authenticated user is a super_admin' do
53
+ let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
54
+
55
+ it 'renders the show post page' do
56
+ expect(current_path).to eq(post_path(post.id))
57
+ end
58
+
59
+ it 'shows the post content' do
60
+ expect(page).to have_content(post.content)
61
+ end
62
+ end
63
+
64
+ context 'when authenticated user is not a super_admin' do
65
+ let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
66
+
67
+ it 'displays an error message' do
68
+ expect(page).to have_content(/forbidden/i)
69
+ end
70
+
71
+ it 'does not show the post content' do
72
+ expect(page).to_not have_content(post.content)
73
+ end
74
+ end
75
+ end
76
+
77
+ describe 'New post' do
78
+ let(:visit_new_post) { visit_path_and_login_with(new_post_path, user) }
79
+
80
+ before { visit_new_post }
81
+
82
+ context 'when authenticated user is a super admin' do
83
+ let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
84
+
85
+ it 'renders the new post page' do
86
+ expect(current_path).to eq(new_post_path)
87
+ end
88
+
89
+ it 'renders a form that accepts post content' do
90
+ expect(page).to have_field('Content')
91
+ end
92
+ end
93
+
94
+ context 'when authenticated user is not a super admin' do
95
+ let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
96
+
97
+ it 'displays an error message' do
98
+ expect(page).to have_content(/forbidden/i)
99
+ end
100
+
101
+ it 'does not render a form that accepts post content' do
102
+ expect(page).to_not have_field('Content')
103
+ end
104
+ end
105
+ end
106
+
107
+ describe 'Create post' do
108
+ subject(:create_post) { click_button 'Create Post' }
109
+
110
+ before do
111
+ visit_path_and_login_with(new_post_path, user)
112
+ fill_in 'Content', with: post.content
113
+ end
114
+
115
+ let(:post) { FactoryGirl.build(:post, author: user) }
116
+ let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
117
+
118
+ context 'when authenticated user is a super admin' do
119
+ it 'renders the flash message' do
120
+ create_post
121
+ expect(page).to have_content('Post was successfully created.')
122
+ end
123
+
124
+ it 'renders the post content' do
125
+ create_post
126
+ expect(page).to have_content(post.content)
127
+ end
128
+
129
+ it 'creates a post in the db' do
130
+ expect { create_post }.to change { Post.count }.by(1)
131
+ end
132
+ end
133
+
134
+ context 'when authenticated user is not a super admin on form submission' do
135
+ before do
136
+ user.roles.clear
137
+ end
138
+
139
+ it 'displays an error message' do
140
+ create_post
141
+ expect(page).to have_content(/forbidden/i)
142
+ end
143
+
144
+ it 'does not create a post' do
145
+ expect { create_post }.to_not change { Post.count }
146
+ end
147
+ end
148
+ end
149
+
150
+ describe 'Edit post' do
151
+ subject(:edit_post) { visit_path_and_login_with(edit_post_path(post.id), user) }
152
+ before { edit_post }
153
+
154
+ let(:post) { FactoryGirl.create(:post, author: user) }
155
+
156
+ context 'when authenticated user is a super admin' do
157
+ let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
158
+
159
+ it 'renders the edit post page' do
160
+ expect(current_path).to eq(edit_post_path(post.id))
161
+ end
162
+
163
+ it 'renders a form that accepts post content' do
164
+ expect(page).to have_field('Content', with: post.content)
165
+ end
166
+ end
167
+
168
+ context 'when authenticated user is not a super admin' do
169
+ let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
170
+
171
+ it 'displays an error message' do
172
+ expect(page).to have_content(/forbidden/i)
173
+ end
174
+
175
+ it 'does not render a form that accepts post content' do
176
+ expect(page).to_not have_field('Content')
177
+ end
178
+ end
179
+ end
180
+
181
+ describe 'Update post' do
182
+ subject(:update_post) { click_button 'Update Post' }
183
+
184
+ before do
185
+ visit_path_and_login_with(edit_post_path(post.id), user)
186
+ fill_in 'Content', with: new_content
187
+ end
188
+
189
+ let(:post) { FactoryGirl.create(:post, author: user) }
190
+ let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
191
+ let(:new_content) { 'My updated post content' }
192
+
193
+ context 'when authenticated user is a super admin' do
194
+ it 'renders the flash message' do
195
+ update_post
196
+ expect(page).to have_content('Post was successfully updated.')
197
+ end
198
+
199
+ it 'renders the post content' do
200
+ update_post
201
+ expect(page).to have_content(new_content)
202
+ end
203
+ end
204
+
205
+ context 'when authenticated user is not a super admin on form submission' do
206
+ before do
207
+ user.roles.clear
208
+ end
209
+
210
+ it 'displays an error message' do
211
+ update_post
212
+ expect(page).to have_content(/forbidden/i)
213
+ end
214
+
215
+ it 'does not update post content' do
216
+ update_post
217
+ expect(page).to_not have_content(new_content)
218
+ end
219
+ end
220
+ end
221
+
222
+ describe 'Delete post' do
223
+ subject(:delete_post) { click_link 'Destroy' }
224
+
225
+ let!(:post) { FactoryGirl.create(:post, author: user) }
226
+ let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
227
+
228
+ before { visit_path_and_login_with(posts_path, user) }
229
+
230
+ context 'when authenticated user is a super admin' do
231
+ it 'renders the flash message' do
232
+ delete_post
233
+ expect(page).to have_content('Post was successfully destroyed.')
234
+ end
235
+
236
+ it 'deletes the post' do
237
+ expect { delete_post }.to change { Post.count }.by(-1)
238
+ end
239
+ end
240
+
241
+ context 'when authenticated user is not a super admin' do
242
+ before { user.roles.clear }
243
+
244
+ it 'displays an error message' do
245
+ delete_post
246
+ expect(page).to have_content(/forbidden/i)
247
+ end
248
+
249
+ it 'does not delete the post' do
250
+ expect { delete_post }.to_not change { Post.count }
251
+ end
252
+ end
253
+ end
254
+ end
@@ -10,31 +10,127 @@ describe 'Signing in' do
10
10
 
11
11
  context 'when user exists locally' do
12
12
  before do
13
- stub_g5_omniauth(user)
14
- login
13
+ OmniAuth.config.mock_auth[:g5] = OmniAuth::AuthHash.new({
14
+ uid: user.uid,
15
+ provider: user.provider,
16
+ info: {
17
+ email: user.email,
18
+ name: "#{updated_first_name} #{updated_last_name}",
19
+ first_name: updated_first_name,
20
+ last_name: updated_last_name,
21
+ phone: updated_phone_number
22
+ },
23
+ credentials: {
24
+ token: updated_access_token,
25
+ expires: true,
26
+ expires_at: Time.now + 1000
27
+ },
28
+ extra: {
29
+ title: updated_title,
30
+ organization_name: updated_organization_name,
31
+ roles: [{name: updated_role.name}],
32
+ raw_info: {}
33
+ }
34
+ })
15
35
  end
16
36
 
37
+ let(:updated_first_name) { "Updated #{user.first_name}" }
38
+ let(:updated_last_name) { "Updated #{user.last_name}" }
39
+ let(:updated_phone_number) { "#{user.phone_number} x1234" }
40
+ let(:updated_title) { "Updated #{user.title}" }
41
+ let(:updated_organization_name) { "Updated #{user.organization_name}" }
42
+ let(:updated_access_token) { "updated-#{user.g5_access_token}-123" }
43
+ let(:updated_role) { FactoryGirl.create(:g5_authenticatable_super_admin_role) }
44
+
17
45
  it 'should sign in the user successfully' do
46
+ login
18
47
  expect(page).to have_content('Signed in successfully.')
19
48
  end
20
49
 
21
50
  it 'should redirect the user to the root path' do
51
+ login
22
52
  expect(current_path).to eq(root_path)
23
53
  end
54
+
55
+ it 'should not create a new user' do
56
+ expect { login }.to_not change { G5Authenticatable::User.count }
57
+ end
58
+
59
+ it 'should not update the user email' do
60
+ login
61
+ expect(page).to have_content(user.email)
62
+ end
63
+
64
+ it 'should update the first name' do
65
+ login
66
+ expect(page).to have_content(updated_first_name)
67
+ end
68
+
69
+ it 'should update the last name' do
70
+ login
71
+ expect(page).to have_content(updated_last_name)
72
+ end
73
+
74
+ it 'should update the phone number' do
75
+ login
76
+ expect(page).to have_content(updated_phone_number)
77
+ end
78
+
79
+ it 'should update the title' do
80
+ login
81
+ expect(page).to have_content(updated_title)
82
+ end
83
+
84
+ it 'should update the organization name' do
85
+ login
86
+ expect(page).to have_content(updated_organization_name)
87
+ end
88
+
89
+ it 'should update the access token' do
90
+ login
91
+ expect(page).to have_content(updated_access_token)
92
+ end
93
+
94
+ it 'should assign the updated role' do
95
+ login
96
+ expect(page).to have_content(updated_role.name)
97
+ end
98
+
99
+ it 'should unassign the previous role' do
100
+ old_role = user.roles.first
101
+ login
102
+ expect(page).to_not have_content(old_role.name)
103
+ end
24
104
  end
25
105
 
26
106
  context 'when user does not exist locally' do
27
107
  before do
28
108
  OmniAuth.config.mock_auth[:g5] = OmniAuth::AuthHash.new({
29
- uid: uid,
30
- provider: 'g5',
31
- info: {email: 'new.test.user@test.host'},
32
- credentials: {token: g5_access_token}
109
+ uid: user_attributes[:uid],
110
+ provider: user_attributes[:provider],
111
+ info: {
112
+ email: user_attributes[:email],
113
+ name: "#{user_attributes[:first_name]} #{user_attributes[:last_name]}",
114
+ first_name: user_attributes[:first_name],
115
+ last_name: user_attributes[:last_name],
116
+ phone: user_attributes[:phone_number]
117
+ },
118
+ credentials: {
119
+ token: user_attributes[:g5_access_token],
120
+ expires: true,
121
+ expires_at: Time.now + 1000
122
+ },
123
+ extra: {
124
+ title: user_attributes[:title],
125
+ organization_name: user_attributes[:organization_name],
126
+ roles: [{name: role_attributes[:name]}],
127
+ raw_info: {}
128
+ }
33
129
  })
34
130
  end
35
131
 
36
- let(:uid) { 42 }
37
- let(:g5_access_token) { 'my secret token string' }
132
+ let(:user_attributes) { FactoryGirl.attributes_for(:g5_authenticatable_user) }
133
+ let(:role_attributes) { FactoryGirl.attributes_for(:g5_authenticatable_editor_role) }
38
134
 
39
135
  it 'should sign in the user successfully' do
40
136
  login
@@ -49,6 +145,46 @@ describe 'Signing in' do
49
145
  it 'should create the user locally' do
50
146
  expect { login }.to change { G5Authenticatable::User.count }.by(1)
51
147
  end
148
+
149
+ it 'should save the user email' do
150
+ login
151
+ expect(page).to have_content(user_attributes[:email])
152
+ end
153
+
154
+ it 'should save the user first_name' do
155
+ login
156
+ expect(page).to have_content(user_attributes[:first_name])
157
+ end
158
+
159
+ it 'should save the user last_name' do
160
+ login
161
+ expect(page).to have_content(user_attributes[:last_name])
162
+ end
163
+
164
+ it 'should save the user phone_number' do
165
+ login
166
+ expect(page).to have_content(user_attributes[:phone_number])
167
+ end
168
+
169
+ it 'should save the user token' do
170
+ login
171
+ expect(page).to have_content(user_attributes[:g5_access_token])
172
+ end
173
+
174
+ it 'should save the user title' do
175
+ login
176
+ expect(page).to have_content(user_attributes[:title])
177
+ end
178
+
179
+ it 'should save the user organization_name' do
180
+ login
181
+ expect(page).to have_content(user_attributes[:organization_name])
182
+ end
183
+
184
+ it 'should save the user role' do
185
+ login
186
+ expect(page).to have_content(role_attributes[:name])
187
+ end
52
188
  end
53
189
  end
54
190
 
@@ -12,10 +12,11 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
12
12
  before do
13
13
  prepare_destination
14
14
  setup_routes
15
+ setup_application_controller
15
16
  run_generator
16
17
  end
17
18
 
18
- it 'should copy the migration' do
19
+ it 'should copy the create user migration' do
19
20
  expect(destination_root).to have_structure {
20
21
  directory 'db' do
21
22
  directory 'migrate' do
@@ -27,6 +28,30 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
27
28
  }
28
29
  end
29
30
 
31
+ it 'should copy the migration to add user contact info' do
32
+ expect(destination_root).to have_structure {
33
+ directory 'db' do
34
+ directory 'migrate' do
35
+ migration 'add_g5_authenticatable_users_contact_info' do
36
+ contains 'class AddG5AuthenticatableUsersContactInfo < ActiveRecord::Migration'
37
+ end
38
+ end
39
+ end
40
+ }
41
+ end
42
+
43
+ it 'should copy the migration to add user roles' do
44
+ expect(destination_root).to have_structure {
45
+ directory 'db' do
46
+ directory 'migrate' do
47
+ migration 'create_g5_authenticatable_roles' do
48
+ contains 'class CreateG5AuthenticatableRoles < ActiveRecord::Migration'
49
+ end
50
+ end
51
+ end
52
+ }
53
+ end
54
+
30
55
  it 'should copy the initializer' do
31
56
  expect(destination_root).to have_structure {
32
57
  directory 'config' do
@@ -49,6 +74,40 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
49
74
  }
50
75
  end
51
76
 
77
+ it 'should include authorization in the application controller' do
78
+ expect(destination_root).to have_structure {
79
+ directory 'app' do
80
+ directory 'controllers' do
81
+ file 'application_controller.rb' do
82
+ contains 'include G5Authenticatable::Authorization'
83
+ end
84
+ end
85
+ end
86
+ }
87
+ end
88
+
89
+ it 'should create the default application policy' do
90
+ expect(destination_root).to have_structure {
91
+ directory 'app' do
92
+ directory 'policies' do
93
+ file 'application_policy.rb' do
94
+ contains 'class ApplicationPolicy < G5Authenticatable::BasePolicy'
95
+ end
96
+ end
97
+ end
98
+ }
99
+ end
100
+
101
+ it 'should copy the static 403 error page' do
102
+ expect(destination_root).to have_structure {
103
+ directory 'public' do
104
+ file '403.html' do
105
+ contains 'Access forbidden'
106
+ end
107
+ end
108
+ }
109
+ end
110
+
52
111
  def setup_routes
53
112
  routes = <<-END
54
113
  Rails.application.routes.draw do
@@ -64,4 +123,16 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
64
123
  FileUtils.mkdir_p(config_dir)
65
124
  File.write(File.join(config_dir, 'routes.rb'), routes)
66
125
  end
126
+
127
+ def setup_application_controller
128
+ controller = <<-END
129
+ class ApplicationController < ActionController::Base
130
+ protect_from_forgery
131
+ end
132
+ END
133
+ controllers_dir = File.join(destination_root, 'app', 'controllers')
134
+
135
+ FileUtils.mkdir_p(controllers_dir)
136
+ File.write(File.join(controllers_dir, 'application_controller.rb'), controller)
137
+ end
67
138
  end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe G5Authenticatable::Role do
4
+ subject { role }
5
+ let(:role) { G5Authenticatable::Role.new(role_attributes) }
6
+ let(:role_attributes) { FactoryGirl.attributes_for(:g5_authenticatable_role) }
7
+
8
+ it { is_expected.to have_and_belong_to_many(:users) }
9
+ it { is_expected.to belong_to(:resource) }
10
+
11
+ it 'should expose the name attribute' do
12
+ expect(role.name).to eq(role_attributes[:name])
13
+ end
14
+
15
+ describe '.global' do
16
+ subject(:global) { G5Authenticatable::Role.global }
17
+ let!(:global_role) { user.roles.first }
18
+ let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
19
+
20
+ let!(:scoped_role) do
21
+ FactoryGirl.create(:g5_authenticatable_role,
22
+ resource: user)
23
+ end
24
+
25
+ it 'should match one role' do
26
+ expect(global.count).to eq(1)
27
+ end
28
+
29
+ it 'should only match the unscoped role' do
30
+ expect(global.first).to eq(global_role)
31
+ end
32
+ end
33
+
34
+ describe '.class_scoped' do
35
+ subject(:class_scoped) { G5Authenticatable::Role.class_scoped(G5Authenticatable::User) }
36
+ let!(:global_role) { FactoryGirl.create(:g5_authenticatable_role) }
37
+ let!(:class_scoped_role) do
38
+ FactoryGirl.create(:g5_authenticatable_role,
39
+ resource_type: 'G5Authenticatable::User')
40
+ end
41
+ let!(:instance_scoped_role) do
42
+ FactoryGirl.create(:g5_authenticatable_role, resource: user)
43
+ end
44
+ let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
45
+
46
+ it 'should match one role' do
47
+ expect(class_scoped.count).to eq(1)
48
+ end
49
+
50
+ it 'should only match the class scoped role' do
51
+ expect(class_scoped.first).to eq(class_scoped_role)
52
+ end
53
+ end
54
+
55
+ describe '.instance_scoped' do
56
+ subject(:instance_scoped) { G5Authenticatable::Role.instance_scoped(user) }
57
+ let!(:global_role) { FactoryGirl.create(:g5_authenticatable_role) }
58
+ let!(:class_scoped_role) do
59
+ FactoryGirl.create(:g5_authenticatable_role,
60
+ resource_type: 'G5Authenticatable::User')
61
+ end
62
+
63
+ let!(:user_scoped_role) do
64
+ FactoryGirl.create(:g5_authenticatable_role, resource: user)
65
+ end
66
+ let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
67
+
68
+ let!(:other_user_scoped_role) do
69
+ FactoryGirl.create(:g5_authenticatable_role, resource: other_user)
70
+ end
71
+ let(:other_user) { FactoryGirl.create(:g5_authenticatable_user) }
72
+
73
+ it 'should match one role' do
74
+ expect(instance_scoped.count).to eq(1)
75
+ end
76
+
77
+ it 'should only match the role scoped to this user instance' do
78
+ expect(instance_scoped.first).to eq(user_scoped_role)
79
+ end
80
+ end
81
+ end