Skip to content

Commit 54e5a8f

Browse files
committed
Tests: sponsor member management
Summary: * Tests ability of sponsor owner to add/remove/update members * Tests to ensure at least one sponsor owner * Tests for forbidden actions by sponsor non-owners Resolves T212, T213 Test Plan: * make test Reviewers: doshitan Reviewed By: doshitan Maniphest Tasks: T213, T212 Differential Revision: https://phabricator.opengovfoundation.org/D142
1 parent d8ea73f commit 54e5a8f

File tree

4 files changed

+210
-8
lines changed

4 files changed

+210
-8
lines changed

app/Http/Requests/SponsorMember/Create.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@ public function authorize()
1717
{
1818
$currentUser = $this->user();
1919

20-
return $this->sponsor->isActive() || (
21-
$currentUser && (
22-
$currentUser->isAdmin() || $this->sponsor->isSponsorOwner($currentUser->id)
23-
)
20+
return $currentUser && (
21+
$currentUser->isAdmin() || $this->sponsor->isSponsorOwner($currentUser->id)
2422
);
2523
}
2624

resources/views/sponsor_members/list.blade.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
</thead>
2525
<tbody>
2626
@foreach ($members as $member)
27-
<tr>
27+
<tr id="user-{{ $member->user->id }}">
2828
<td>{{ $member->name }}</td>
2929
<td>{{ $member->email }}</td>
3030
<td>
@@ -34,7 +34,10 @@
3434
'role',
3535
$allRoles,
3636
$member->role,
37-
[ 'onchange' => 'if (this.selectedIndex >= 0) this.form.submit();' ]
37+
[
38+
'onchange' => 'if (this.selectedIndex >= 0) this.form.submit();',
39+
'class' => 'no-select2',
40+
]
3841
)
3942
}}
4043
{{ Form::close() }}
@@ -52,7 +55,7 @@
5255
@if ($sponsor->isSponsorOwner(Auth::user()->id) || Auth::user()->isAdmin())
5356
<div class="btn-group">
5457
{{ Form::open(['route' => ['sponsors.members.destroy', $sponsor, $member], 'method' => 'delete']) }}
55-
<button type="submit" class="btn btn-xs btn-link">
58+
<button type="submit" class="btn btn-xs btn-link remove">
5659
<i class="fa fa-close"></i>
5760
</button>
5861
{{ Form::close() }}
@@ -71,7 +74,9 @@
7174

7275
<hr>
7376

74-
{{ Html::linkRoute('sponsors.members.create', trans('messages.sponsor_member.add'), [$sponsor], ['class' => 'btn btn-primary'])}}
77+
@if ($sponsor->isSponsorOwner(Auth::user()->id) || Auth::user()->isAdmin())
78+
{{ Html::linkRoute('sponsors.members.create', trans('messages.sponsor_member.add'), [$sponsor], ['class' => 'btn btn-primary add-member'])}}
79+
@endif
7580
</div>
7681
</div>
7782
@endsection
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Tests\Browser\Pages\Sponsor;
4+
5+
use App\Models\Sponsor;
6+
use Laravel\Dusk\Browser;
7+
use Tests\Browser\Pages\Page;
8+
9+
class MembersPage extends Page
10+
{
11+
public $sponsor;
12+
13+
public function __construct(Sponsor $sponsor)
14+
{
15+
$this->sponsor = $sponsor;
16+
}
17+
18+
/**
19+
* Get the URL for the page.
20+
*
21+
* @return string
22+
*/
23+
public function url()
24+
{
25+
return route('sponsors.members.index', [$this->sponsor], false);
26+
}
27+
28+
/**
29+
* Assert that the browser is on the page.
30+
*
31+
* @return void
32+
*/
33+
public function assert(Browser $browser)
34+
{
35+
$browser->assertPathIs($this->url());
36+
}
37+
38+
/**
39+
* Get the element shortcuts for the page.
40+
*
41+
* @return array
42+
*/
43+
public function elements()
44+
{
45+
return [
46+
'@addMemberButton' => '.add-member',
47+
];
48+
}
49+
50+
}

tests/Browser/SponsorTest.php

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,153 @@ public function testNonOwnerCantEditSponsorSettings()
159159
;
160160
});
161161
}
162+
163+
public function testSponsorOwnerCanAddMembers()
164+
{
165+
$owner = factory(User::class)->create();
166+
$sponsor = FactoryHelpers::createActiveSponsorWithUser($owner);
167+
168+
$user = factory(User::class)->create();
169+
$role = Sponsor::ROLE_EDITOR;
170+
171+
$this->browse(function ($browser) use ($owner, $sponsor, $user, $role) {
172+
$browser
173+
->loginAs($owner)
174+
->visit(new SponsorPages\MembersPage($sponsor))
175+
->assertDontSeeIn('table', $user->display_name)
176+
->click('@addMemberButton')
177+
->assertRouteIs('sponsors.members.create', $sponsor)
178+
->type('email', $user->email)
179+
->select('role', $role)
180+
->press(trans('messages.sponsor_member.add_user'))
181+
->assertRouteIs('sponsors.members.index', $sponsor)
182+
->assertSeeIn('table', $user->display_name)
183+
->assertSeeIn('tr#user-'.$user->id, trans('messages.sponsor_member.roles.'.$role))
184+
;
185+
});
186+
}
187+
188+
public function testNonSponsorOwnerCannotAddMembers()
189+
{
190+
$owner = factory(User::class)->create();
191+
$editor = factory(User::class)->create();
192+
193+
$sponsor = FactoryHelpers::createActiveSponsorWithUser($owner);
194+
$sponsor->addMember($editor->id, Sponsor::ROLE_EDITOR);
195+
196+
$this->browse(function ($browser) use ($sponsor, $editor) {
197+
$browser
198+
->loginAs($editor)
199+
->visit(new SponsorPages\MembersPage($sponsor))
200+
->assertMissing('@addMemberButton')
201+
->visitRoute('sponsors.members.create', $sponsor)
202+
->assertSee('Whoops, looks like something went wrong') // 403 status
203+
;
204+
});
205+
}
206+
207+
public function testSponsorOwnerCanRemoveMembers()
208+
{
209+
$owner = factory(User::class)->create();
210+
$editor = factory(User::class)->create();
211+
212+
$sponsor = FactoryHelpers::createActiveSponsorWithUser($owner);
213+
$sponsor->addMember($editor->id, Sponsor::ROLE_EDITOR);
214+
215+
$this->browse(function ($browser) use ($owner, $sponsor, $editor) {
216+
$browser
217+
->loginAs($owner)
218+
->visit(new SponsorPages\MembersPage($sponsor))
219+
->assertSeeIn('table', $editor->display_name)
220+
->with('tr#user-' . $editor->id, function ($userRow) {
221+
$userRow->press('.remove');
222+
})
223+
->assertVisible('.alert.alert-info') // some success
224+
->assertRouteIs('sponsors.members.index', $sponsor)
225+
->assertDontSeeIn('table', $editor->display_name)
226+
;
227+
});
228+
}
229+
230+
public function testNonSponsorOwnerCannotRemoveMembers()
231+
{
232+
$owner = factory(User::class)->create();
233+
$editor = factory(User::class)->create();
234+
235+
$sponsor = FactoryHelpers::createActiveSponsorWithUser($owner);
236+
$sponsor->addMember($editor->id, Sponsor::ROLE_EDITOR);
237+
238+
$this->browse(function ($browser) use ($sponsor, $editor) {
239+
$browser
240+
->loginAs($editor)
241+
->visit(new SponsorPages\MembersPage($sponsor))
242+
->assertMissing('tr .remove')
243+
;
244+
});
245+
}
246+
247+
public function testSponsorOwnerCanUpdateMemberRoles()
248+
{
249+
$owner = factory(User::class)->create();
250+
$editor = factory(User::class)->create();
251+
252+
$sponsor = FactoryHelpers::createActiveSponsorWithUser($owner);
253+
$sponsor->addMember($editor->id, Sponsor::ROLE_EDITOR);
254+
255+
$newRole = Sponsor::ROLE_STAFF;
256+
257+
$this->browse(function ($browser) use ($owner, $sponsor, $editor, $newRole) {
258+
$browser
259+
->loginAs($owner)
260+
->visit(new SponsorPages\MembersPage($sponsor))
261+
->assertSeeIn('table', $editor->display_name)
262+
->with('tr#user-' . $editor->id, function ($userRow) use ($newRole) {
263+
$userRow->select('role', $newRole);
264+
})
265+
->assertVisible('.alert.alert-info') // some success
266+
->assertRouteIs('sponsors.members.index', $sponsor)
267+
->assertSeeIn('tr#user-' . $editor->id, trans('messages.sponsor_member.roles.'.$newRole))
268+
;
269+
});
270+
}
271+
272+
public function testNonSponsorOwnerCannotUpdateMemberRoles()
273+
{
274+
$owner = factory(User::class)->create();
275+
$editor = factory(User::class)->create();
276+
277+
$sponsor = FactoryHelpers::createActiveSponsorWithUser($owner);
278+
$sponsor->addMember($editor->id, Sponsor::ROLE_EDITOR);
279+
280+
$this->browse(function ($browser) use ($sponsor, $editor) {
281+
$browser
282+
->loginAs($editor)
283+
->visit(new SponsorPages\MembersPage($sponsor))
284+
->assertMissing('tr select')
285+
;
286+
});
287+
}
288+
289+
public function testEnsuresAtLeastOneOwner()
290+
{
291+
$owner = factory(User::class)->create();
292+
293+
$sponsor = FactoryHelpers::createActiveSponsorWithUser($owner);
294+
$sponsor->addMember(factory(User::class)->create()->id, Sponsor::ROLE_EDITOR);
295+
296+
$originalRole = Sponsor::ROLE_OWNER;
297+
$newRole = Sponsor::ROLE_STAFF;
298+
299+
$this->browse(function ($browser) use ($sponsor, $owner, $originalRole, $newRole) {
300+
$browser
301+
->loginAs($owner)
302+
->visit(new SponsorPages\MembersPage($sponsor))
303+
->with('tr#user-' . $owner->id, function ($userRow) use ($originalRole, $newRole) {
304+
$userRow->select('role', $newRole);
305+
})
306+
->assertSeeIn('.alert', trans('messages.sponsor_member.need_owner'))
307+
->assertSeeIn('tr#user-' . $owner->id, trans('messages.sponsor_member.roles.' . $originalRole))
308+
;
309+
});
310+
}
162311
}

0 commit comments

Comments
 (0)