g5_authenticatable 0.4.2 → 0.5.0

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