Commit 439a61783d0b61bbcc8f3c9e5b828b2270a679aa

Authored by Ciro Santillli
1 parent c86553cd

User can leave group from group page.

app/controllers/application_controller.rb
... ... @@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base
135 135 end
136 136 end
137 137  
138   - def render_404
139   - render file: Rails.root.join("public", "404"), layout: false, status: "404"
  138 + def render_403
  139 + head :forbidden
140 140 end
141 141  
142   - def render_403
143   - render file: Rails.root.join("public", "403"), layout: false, status: "403"
  142 + def render_404
  143 + render file: Rails.root.join("public", "404"), layout: false, status: "404"
144 144 end
145 145  
146 146 def require_non_empty_project
... ...
app/controllers/profiles/groups_controller.rb
... ... @@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController
7 7  
8 8 def leave
9 9 @users_group = group.users_groups.where(user_id: current_user.id).first
10   -
11   - if group.last_owner?(current_user)
12   - redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.")
13   - else
  10 + if can?(current_user, :destroy, @users_group)
14 11 @users_group.destroy
15 12 redirect_to(profile_groups_path, info: "You left #{group.name} group.")
  13 + else
  14 + return render_403
16 15 end
17 16 end
18 17  
... ...
app/controllers/users_groups_controller.rb
... ... @@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController
19 19  
20 20 def destroy
21 21 @users_group = @group.users_groups.find(params[:id])
22   - @users_group.destroy
23   -
24   - respond_to do |format|
25   - format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
26   - format.js { render nothing: true }
  22 + if can?(current_user, :destroy, @users_group) # May fail if last owner.
  23 + @users_group.destroy
  24 + respond_to do |format|
  25 + format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
  26 + format.js { render nothing: true }
  27 + end
  28 + else
  29 + return render_403
27 30 end
28 31 end
29 32  
... ...
app/helpers/groups_helper.rb
1 1 module GroupsHelper
2 2 def remove_user_from_group_message(group, user)
3   - "You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
  3 + "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?"
  4 + end
  5 +
  6 + def leave_group_message(group)
  7 + "Are you sure you want to leave \"#{group}\" group?"
4 8 end
5 9  
6 10 def group_head_title
... ...
app/models/ability.rb
... ... @@ -14,6 +14,7 @@ class Ability
14 14 when "MergeRequest" then merge_request_abilities(user, subject)
15 15 when "Group" then group_abilities(user, subject)
16 16 when "Namespace" then namespace_abilities(user, subject)
  17 + when "UsersGroup" then users_group_abilities(user, subject)
17 18 else []
18 19 end.concat(global_abilities(user))
19 20 end
... ... @@ -219,5 +220,19 @@ class Ability
219 220 end
220 221 end
221 222 end
  223 +
  224 + def users_group_abilities(user, subject)
  225 + rules = []
  226 + target_user = subject.user
  227 + group = subject.group
  228 + can_manage = group_abilities(user, group).include?(:manage_group)
  229 + if can_manage && (user != target_user)
  230 + rules << :modify
  231 + end
  232 + if !group.last_owner?(user) && (can_manage || (user == target_user))
  233 + rules << :destroy
  234 + end
  235 + rules
  236 + end
222 237 end
223 238 end
... ...
app/views/groups/members.html.haml
... ... @@ -6,7 +6,6 @@
6 6 %strong= link_to "here", help_permissions_path, class: "vlink"
7 7  
8 8 %hr
9   -- can_manage_group = current_user.can? :manage_group, @group
10 9 .ui-box
11 10 .title
12 11 %strong #{@group.name}
... ... @@ -15,6 +14,6 @@
15 14 (#{@members.count})
16 15 %ul.well-list
17 16 - @members.each do |member|
18   - = render 'users_groups/users_group', member: member, show_controls: can_manage_group
19   -- if can_manage_group
  17 + = render 'users_groups/users_group', member: member, show_controls: true
  18 +- if current_user.can? :manage_group, @group
20 19 = render "new_group_member"
... ...
app/views/help/permissions.html.haml
... ... @@ -217,3 +217,4 @@
217 217 %td
218 218 %td
219 219 %td.permission-x &#10003;
  220 + %p.light Any user can remove himself from a group, unless he is the last Owner of the group.
... ...
app/views/profiles/groups/index.html.haml
... ... @@ -22,9 +22,10 @@
22 22 %i.icon-cogs
23 23 Settings
24 24  
25   - = link_to leave_profile_group_path(group), data: { confirm: "Are you sure you want to leave #{group.name} group?"}, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do
26   - %i.icon-signout
27   - Leave
  25 + - if can?(current_user, :destroy, user_group)
  26 + = link_to leave_profile_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn grouped", title: 'Remove user from group' do
  27 + %i.icon-signout
  28 + Leave
28 29  
29 30 = link_to group, class: 'group-name' do
30 31 %strong= group.name
... ...
app/views/users_groups/_users_group.html.haml
... ... @@ -9,12 +9,17 @@
9 9  
10 10 %span.pull-right
11 11 %strong= member.human_access
12   -
13   - - if show_controls && can?(current_user, :manage_group, @group) && current_user != user
14   - = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
15   - %i.icon-edit
16   - = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
17   - %i.icon-minus.icon-white
  12 + - if show_controls
  13 + - if can?(current_user, :modify, member)
  14 + = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
  15 + %i.icon-edit
  16 + - if can?(current_user, :destroy, member)
  17 + - if current_user == member.user
  18 + = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
  19 + %i.icon-minus.icon-white
  20 + - else
  21 + = link_to group_users_group_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
  22 + %i.icon-minus.icon-white
18 23  
19 24 .edit-member.hide.js-toggle-content
20 25 = form_for [@group, member], remote: true do |f|
... ...
features/admin/groups.feature
... ... @@ -2,7 +2,7 @@ Feature: Admin Groups
2 2 Background:
3 3 Given I sign in as an admin
4 4 And I have group with projects
5   - And Create user "John Doe"
  5 + And User "John Doe" exists
6 6 And I visit admin groups page
7 7  
8 8 Scenario: See group list
... ...
features/group.feature 0 → 100644
... ... @@ -0,0 +1,116 @@
  1 +Feature: Groups
  2 + Background:
  3 + Given I sign in as "John Doe"
  4 + And "John Doe" is owner of group "Owned"
  5 + And "John Doe" is guest of group "Guest"
  6 +
  7 + @javascript
  8 + Scenario: I should see group "Owned" dashboard list
  9 + When I visit group "Owned" page
  10 + Then I should see group "Owned" projects list
  11 + And I should see projects activity feed
  12 +
  13 + Scenario: Create a group from dasboard
  14 + When I visit group "Owned" page
  15 + And I visit dashboard page
  16 + And I click new group link
  17 + And submit form with new group "Samurai" info
  18 + Then I should be redirected to group "Samurai" page
  19 + And I should see newly created group "Samurai"
  20 +
  21 + Scenario: I should see group "Owned" issues list
  22 + Given project from group "Owned" has issues assigned to me
  23 + When I visit group "Owned" issues page
  24 + Then I should see issues from group "Owned" assigned to me
  25 +
  26 + Scenario: I should see group "Owned" merge requests list
  27 + Given project from group "Owned" has merge requests assigned to me
  28 + When I visit group "Owned" merge requests page
  29 + Then I should see merge requests from group "Owned" assigned to me
  30 +
  31 + @javascript
  32 + Scenario: I should add user to projects in group "Owned"
  33 + Given User "Mary Jane" exists
  34 + When I visit group "Owned" members page
  35 + And I select user "Mary Jane" from list with role "Reporter"
  36 + Then I should see user "Mary Jane" in team list
  37 +
  38 + Scenario: I should see edit group "Owned" page
  39 + When I visit group "Owned" settings page
  40 + And I change group "Owned" name to "new-name"
  41 + Then I should see new group "Owned" name
  42 +
  43 + Scenario: I edit group "Owned" avatar
  44 + When I visit group "Owned" settings page
  45 + And I change group "Owned" avatar
  46 + And I visit group "Owned" settings page
  47 + Then I should see new group "Owned" avatar
  48 + And I should see the "Remove avatar" button
  49 +
  50 + Scenario: I remove group "Owned" avatar
  51 + When I visit group "Owned" settings page
  52 + And I have group "Owned" avatar
  53 + And I visit group "Owned" settings page
  54 + And I remove group "Owned" avatar
  55 + Then I should not see group "Owned" avatar
  56 + And I should not see the "Remove avatar" button
  57 +
  58 + # Leave
  59 +
  60 + @javascript
  61 + Scenario: Owner should be able to remove himself from group if he is not the last owner
  62 + Given "Mary Jane" is owner of group "Owned"
  63 + When I visit group "Owned" members page
  64 + Then I should see user "John Doe" in team list
  65 + Then I should see user "Mary Jane" in team list
  66 + When I click on the "Remove User From Group" button for "John Doe"
  67 + And I visit group "Owned" members page
  68 + Then I should not see user "John Doe" in team list
  69 + Then I should see user "Mary Jane" in team list
  70 +
  71 + @javascript
  72 + Scenario: Owner should not be able to remove himself from group if he is the last owner
  73 + Given "Mary Jane" is guest of group "Owned"
  74 + When I visit group "Owned" members page
  75 + Then I should see user "John Doe" in team list
  76 + Then I should see user "Mary Jane" in team list
  77 + Then I should not see the "Remove User From Group" button for "Mary Jane"
  78 +
  79 + @javascript
  80 + Scenario: Guest should be able to remove himself from group
  81 + Given "Mary Jane" is guest of group "Guest"
  82 + When I visit group "Guest" members page
  83 + Then I should see user "John Doe" in team list
  84 + Then I should see user "Mary Jane" in team list
  85 + When I click on the "Remove User From Group" button for "John Doe"
  86 + When I visit group "Guest" members page
  87 + Then I should not see user "John Doe" in team list
  88 + Then I should see user "Mary Jane" in team list
  89 +
  90 + @javascript
  91 + Scenario: Guest should be able to remove himself from group even if he is the only user in the group
  92 + When I visit group "Guest" members page
  93 + Then I should see user "John Doe" in team list
  94 + When I click on the "Remove User From Group" button for "John Doe"
  95 + When I visit group "Guest" members page
  96 + Then I should not see user "John Doe" in team list
  97 +
  98 + # Remove others
  99 +
  100 + @javascript
  101 + Scenario: Owner should be able to remove other users from group
  102 + Given "Mary Jane" is owner of group "Owned"
  103 + When I visit group "Owned" members page
  104 + Then I should see user "John Doe" in team list
  105 + Then I should see user "Mary Jane" in team list
  106 + When I click on the "Remove User From Group" button for "Mary Jane"
  107 + When I visit group "Owned" members page
  108 + Then I should see user "John Doe" in team list
  109 + Then I should not see user "Mary Jane" in team list
  110 +
  111 + Scenario: Guest should not be able to remove other users from group
  112 + Given "Mary Jane" is guest of group "Guest"
  113 + When I visit group "Guest" members page
  114 + Then I should see user "John Doe" in team list
  115 + Then I should see user "Mary Jane" in team list
  116 + Then I should not see the "Remove User From Group" button for "Mary Jane"
... ...
features/group/create_group.feature
... ... @@ -1,11 +0,0 @@
1   -Feature: Groups
2   - Background:
3   - Given I sign in as a user
4   -
5   - Scenario: Create a group from dasboard
6   - Given I have group with projects
7   - And I visit dashboard page
8   - When I click new group link
9   - And submit form with new group info
10   - Then I should be redirected to group page
11   - And I should see newly created group
features/group/group.feature
... ... @@ -1,47 +0,0 @@
1   -Feature: Groups
2   - Background:
3   - Given I sign in as a user
4   - And I have group with projects
5   -
6   - @javascript
7   - Scenario: I should see group dashboard list
8   - When I visit group page
9   - Then I should see projects list
10   - And I should see projects activity feed
11   -
12   - Scenario: I should see group issues list
13   - Given project from group has issues assigned to me
14   - When I visit group issues page
15   - Then I should see issues from this group assigned to me
16   -
17   - Scenario: I should see group merge requests list
18   - Given project from group has merge requests assigned to me
19   - When I visit group merge requests page
20   - Then I should see merge requests from this group assigned to me
21   -
22   - @javascript
23   - Scenario: I should add user to projects in Group
24   - Given Create user "John Doe"
25   - When I visit group members page
26   - And I select user "John Doe" from list with role "Reporter"
27   - Then I should see user "John Doe" in team list
28   -
29   - Scenario: I should see edit group page
30   - When I visit group settings page
31   - And I change group name
32   - Then I should see new group name
33   -
34   - Scenario: I edit my group avatar
35   - When I visit group settings page
36   - And I change my group avatar
37   - And I visit group settings page
38   - Then I should see new group avatar
39   - And I should see the "Remove avatar" button
40   -
41   - Scenario: I remove my group avatar
42   - When I visit group settings page
43   - And I have an group avatar
44   - And I visit group settings page
45   - And I remove my group avatar
46   - Then I should not see my group avatar
47   - And I should not see the "Remove avatar" button
features/profile/group.feature 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +Feature: Profile Group
  2 + Background:
  3 + Given I sign in as "John Doe"
  4 + And "John Doe" is owner of group "Owned"
  5 + And "John Doe" is guest of group "Guest"
  6 +
  7 + # Leave groups
  8 +
  9 + @javascript
  10 + Scenario: Owner should be able to leave from group if he is not the last owner
  11 + Given "Mary Jane" is owner of group "Owned"
  12 + When I visit profile groups page
  13 + Then I should see group "Owned" in group list
  14 + Then I should see group "Guest" in group list
  15 + When I click on the "Leave" button for group "Owned"
  16 + And I visit profile groups page
  17 + Then I should not see group "Owned" in group list
  18 + Then I should see group "Guest" in group list
  19 +
  20 + @javascript
  21 + Scenario: Owner should not be able to leave from group if he is the last owner
  22 + Given "Mary Jane" is guest of group "Owned"
  23 + When I visit profile groups page
  24 + Then I should see group "Owned" in group list
  25 + Then I should see group "Guest" in group list
  26 + Then I should not see the "Leave" button for group "Owned"
  27 +
  28 + @javascript
  29 + Scenario: Guest should be able to leave from group
  30 + Given "Mary Jane" is guest of group "Guest"
  31 + When I visit profile groups page
  32 + Then I should see group "Owned" in group list
  33 + Then I should see group "Guest" in group list
  34 + When I click on the "Leave" button for group "Guest"
  35 + When I visit profile groups page
  36 + Then I should see group "Owned" in group list
  37 + Then I should not see group "Guest" in group list
  38 +
  39 + @javascript
  40 + Scenario: Guest should be able to leave from group even if he is the only user in the group
  41 + When I visit profile groups page
  42 + Then I should see group "Owned" in group list
  43 + Then I should see group "Guest" in group list
  44 + When I click on the "Leave" button for group "Guest"
  45 + When I visit profile groups page
  46 + Then I should see group "Owned" in group list
  47 + Then I should not see group "Guest" in group list
... ...
features/steps/group/group.rb
1 1 class Groups < Spinach::FeatureSteps
2 2 include SharedAuthentication
3 3 include SharedPaths
  4 + include SharedGroup
4 5 include SharedUser
5 6 include Select2Helper
6 7  
7   - Then 'I should see projects list' do
8   - current_user.authorized_projects.each do |project|
  8 + Then 'I should see group "Owned" projects list' do
  9 + Group.find_by(name: "Owned").projects.each do |project|
9 10 page.should have_link project.name
10 11 end
11 12 end
12 13  
13   - And 'I have group with projects' do
14   - @group = create(:group)
15   - @group.add_owner(current_user)
16   - @project = create(:project, namespace: @group)
17   - @event = create(:closed_issue_event, project: @project)
18   -
19   - @project.team << [current_user, :master]
20   - end
21   -
22 14 And 'I should see projects activity feed' do
23 15 page.should have_content 'closed issue'
24 16 end
25 17  
26   - Then 'I should see issues from this group assigned to me' do
  18 + Then 'I should see issues from group "Owned" assigned to me' do
27 19 assigned_to_me(:issues).each do |issue|
28 20 page.should have_content issue.title
29 21 end
30 22 end
31 23  
32   - Then 'I should see merge requests from this group assigned to me' do
  24 + Then 'I should see merge requests from group "Owned" assigned to me' do
33 25 assigned_to_me(:merge_requests).each do |issue|
34 26 page.should have_content issue.title[0..80]
35 27 end
36 28 end
37 29  
38   - And 'I select user "John Doe" from list with role "Reporter"' do
39   - user = User.find_by(name: "John Doe")
  30 + And 'I select user "Mary Jane" from list with role "Reporter"' do
  31 + user = User.find_by(name: "Mary Jane") || create(:user, name: "Mary Jane")
40 32 within ".users-group-form" do
41 33 select2(user.id, from: "#user_ids", multiple: true)
42 34 select "Reporter", from: "group_access"
... ... @@ -49,14 +41,29 @@ class Groups &lt; Spinach::FeatureSteps
49 41 projects_with_access.should have_content("John Doe")
50 42 end
51 43  
52   - Given 'project from group has issues assigned to me' do
  44 + Then 'I should not see user "John Doe" in team list' do
  45 + projects_with_access = find(".ui-box .well-list")
  46 + projects_with_access.should_not have_content("John Doe")
  47 + end
  48 +
  49 + Then 'I should see user "Mary Jane" in team list' do
  50 + projects_with_access = find(".ui-box .well-list")
  51 + projects_with_access.should have_content("Mary Jane")
  52 + end
  53 +
  54 + Then 'I should not see user "Mary Jane" in team list' do
  55 + projects_with_access = find(".ui-box .well-list")
  56 + projects_with_access.should_not have_content("Mary Jane")
  57 + end
  58 +
  59 + Given 'project from group "Owned" has issues assigned to me' do
53 60 create :issue,
54 61 project: project,
55 62 assignee: current_user,
56 63 author: current_user
57 64 end
58 65  
59   - Given 'project from group has merge requests assigned to me' do
  66 + Given 'project from group "Owned" has merge requests assigned to me' do
60 67 create :merge_request,
61 68 source_project: project,
62 69 target_project: project,
... ... @@ -68,78 +75,94 @@ class Groups &lt; Spinach::FeatureSteps
68 75 click_link "New group"
69 76 end
70 77  
71   - And 'submit form with new group info' do
  78 + And 'submit form with new group "Samurai" info' do
72 79 fill_in 'group_name', with: 'Samurai'
73 80 fill_in 'group_description', with: 'Tokugawa Shogunate'
74 81 click_button "Create group"
75 82 end
76 83  
77   - Then 'I should see newly created group' do
  84 + Then 'I should be redirected to group "Samurai" page' do
  85 + current_path.should == group_path(Group.last)
  86 + end
  87 +
  88 + Then 'I should see newly created group "Samurai"' do
78 89 page.should have_content "Samurai"
79 90 page.should have_content "Tokugawa Shogunate"
80 91 page.should have_content "You will only see events from projects in this group"
81 92 end
82 93  
83   - Then 'I should be redirected to group page' do
84   - current_path.should == group_path(Group.last)
85   - end
86   -
87   - And 'I change group name' do
  94 + And 'I change group "Owned" name to "new-name"' do
88 95 fill_in 'group_name', with: 'new-name'
89 96 click_button "Save group"
90 97 end
91 98  
92   - Then 'I should see new group name' do
  99 + Then 'I should see new group "Owned" name' do
93 100 within ".navbar-gitlab" do
94 101 page.should have_content "group: new-name"
95 102 end
96 103 end
97 104  
98   - step 'I change my group avatar' do
  105 + step 'I change group "Owned" avatar' do
99 106 attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png'))
100 107 click_button "Save group"
101   - @group.reload
  108 + Group.find_by(name: "Owned").reload
102 109 end
103 110  
104   - step 'I should see new group avatar' do
105   - @group.avatar.should be_instance_of AttachmentUploader
106   - @group.avatar.url.should == "/uploads/group/avatar/#{ @group.id }/gitlab_logo.png"
  111 + step 'I should see new group "Owned" avatar' do
  112 + Group.find_by(name: "Owned").avatar.should be_instance_of AttachmentUploader
  113 + Group.find_by(name: "Owned").avatar.url.should == "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/gitlab_logo.png"
107 114 end
108 115  
109 116 step 'I should see the "Remove avatar" button' do
110 117 page.should have_link("Remove avatar")
111 118 end
112 119  
113   - step 'I have an group avatar' do
  120 + step 'I have group "Owned" avatar' do
114 121 attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png'))
115 122 click_button "Save group"
116   - @group.reload
  123 + Group.find_by(name: "Owned").reload
117 124 end
118 125  
119   - step 'I remove my group avatar' do
  126 + step 'I remove group "Owned" avatar' do
120 127 click_link "Remove avatar"
121   - @group.reload
  128 + Group.find_by(name: "Owned").reload
122 129 end
123 130  
124   - step 'I should not see my group avatar' do
125   - @group.avatar?.should be_false
  131 + step 'I should not see group "Owned" avatar' do
  132 + Group.find_by(name: "Owned").avatar?.should be_false
126 133 end
127 134  
128 135 step 'I should not see the "Remove avatar" button' do
129 136 page.should_not have_link("Remove avatar")
130 137 end
131 138  
132   - protected
  139 + step 'I click on the "Remove User From Group" button for "John Doe"' do
  140 + find(:css, 'li', text: "John Doe").find(:css, 'a.btn-remove').click
  141 + # poltergeist always confirms popups.
  142 + end
133 143  
134   - def current_group
135   - @group ||= Group.first
  144 + step 'I click on the "Remove User From Group" button for "Mary Jane"' do
  145 + find(:css, 'li', text: "Mary Jane").find(:css, 'a.btn-remove').click
  146 + # poltergeist always confirms popups.
136 147 end
137 148  
138   - def project
139   - current_group.projects.first
  149 + step 'I should not see the "Remove User From Group" button for "John Doe"' do
  150 + find(:css, 'li', text: "John Doe").should_not have_selector(:css, 'a.btn-remove')
  151 + # poltergeist always confirms popups.
140 152 end
141 153  
  154 + step 'I should not see the "Remove User From Group" button for "Mary Jane"' do
  155 + find(:css, 'li', text: "Mary Jane").should_not have_selector(:css, 'a.btn-remove')
  156 + # poltergeist always confirms popups.
  157 + end
  158 +
  159 + protected
  160 +
142 161 def assigned_to_me key
143 162 project.send(key).where(assignee_id: current_user.id)
144 163 end
  164 +
  165 + def project
  166 + Group.find_by(name: "Owned").projects.first
  167 + end
145 168 end
... ...
features/steps/profile/group.rb 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +class ProfileGroup < Spinach::FeatureSteps
  2 + include SharedAuthentication
  3 + include SharedGroup
  4 + include SharedPaths
  5 + include SharedUser
  6 +
  7 + # Leave
  8 +
  9 + step 'I click on the "Leave" button for group "Owned"' do
  10 + find(:css, 'li', text: "Owner").find(:css, 'i.icon-signout').click
  11 + # poltergeist always confirms popups.
  12 + end
  13 +
  14 + step 'I click on the "Leave" button for group "Guest"' do
  15 + find(:css, 'li', text: "Guest").find(:css, 'i.icon-signout').click
  16 + # poltergeist always confirms popups.
  17 + end
  18 +
  19 + step 'I should not see the "Leave" button for group "Owned"' do
  20 + find(:css, 'li', text: "Owner").should_not have_selector(:css, 'i.icon-signout')
  21 + # poltergeist always confirms popups.
  22 + end
  23 +
  24 + step 'I should not see the "Leave" button for groupr "Guest"' do
  25 + find(:css, 'li', text: "Guest").should_not have_selector(:css, 'i.icon-signout')
  26 + # poltergeist always confirms popups.
  27 + end
  28 +
  29 + step 'I should see group "Owned" in group list' do
  30 + page.should have_content("Owned")
  31 + end
  32 +
  33 + step 'I should not see group "Owned" in group list' do
  34 + page.should_not have_content("Owned")
  35 + end
  36 +
  37 + step 'I should see group "Guest" in group list' do
  38 + page.should have_content("Guest")
  39 + end
  40 +
  41 + step 'I should not see group "Guest" in group list' do
  42 + page.should_not have_content("Guest")
  43 + end
  44 +end
... ...
features/steps/project/project_network_graph.rb
1 1 class ProjectNetworkGraph < Spinach::FeatureSteps
2 2 include SharedAuthentication
  3 + include SharedPaths
3 4 include SharedProject
4 5  
5 6 Then 'page should have network graph' do
... ...
features/steps/shared/authentication.rb
... ... @@ -12,6 +12,14 @@ module SharedAuthentication
12 12 login_as :admin
13 13 end
14 14  
  15 + step 'I sign in as "John Doe"' do
  16 + login_with(user_exists("John Doe"))
  17 + end
  18 +
  19 + step 'I sign in as "Mary Jane"' do
  20 + login_with(user_exists("Mary Jane"))
  21 + end
  22 +
15 23 step 'I should be redirected to sign in page' do
16 24 current_path.should == new_user_session_path
17 25 end
... ...
features/steps/shared/group.rb 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +module SharedGroup
  2 + include Spinach::DSL
  3 +
  4 + step '"John Doe" is owner of group "Owned"' do
  5 + is_member_of("John Doe", "Owned", Gitlab::Access::OWNER)
  6 + end
  7 +
  8 + step '"John Doe" is guest of group "Guest"' do
  9 + is_member_of("John Doe", "Guest", Gitlab::Access::GUEST)
  10 + end
  11 +
  12 + step '"Mary Jane" is owner of group "Owned"' do
  13 + is_member_of("Mary Jane", "Owned", Gitlab::Access::OWNER)
  14 + end
  15 +
  16 + step '"Mary Jane" is guest of group "Owned"' do
  17 + is_member_of("Mary Jane", "Owned", Gitlab::Access::GUEST)
  18 + end
  19 +
  20 + step '"Mary Jane" is guest of group "Guest"' do
  21 + is_member_of("Mary Jane", "Guest", Gitlab::Access::GUEST)
  22 + end
  23 +
  24 + protected
  25 +
  26 + def is_member_of(username, groupname, role)
  27 + @project_count ||= 0
  28 + user = User.find_by(name: username) || create(:user, name: username)
  29 + group = Group.find_by(name: groupname) || create(:group, name: groupname)
  30 + group.add_user(user, role)
  31 + project ||= create(:project, namespace: group, path: "project#{@project_count}")
  32 + event ||= create(:closed_issue_event, project: project)
  33 + project.team << [user, :master]
  34 + @project_count += 1
  35 + end
  36 +end
... ...
features/steps/shared/paths.rb
... ... @@ -17,24 +17,44 @@ module SharedPaths
17 17 # Group
18 18 # ----------------------------------------
19 19  
20   - step 'I visit group page' do
21   - visit group_path(current_group)
  20 + step 'I visit group "Owned" page' do
  21 + visit group_path(Group.find_by(name:"Owned"))
22 22 end
23 23  
24   - step 'I visit group issues page' do
25   - visit issues_group_path(current_group)
  24 + step 'I visit group "Owned" issues page' do
  25 + visit issues_group_path(Group.find_by(name:"Owned"))
26 26 end
27 27  
28   - step 'I visit group merge requests page' do
29   - visit merge_requests_group_path(current_group)
  28 + step 'I visit group "Owned" merge requests page' do
  29 + visit merge_requests_group_path(Group.find_by(name:"Owned"))
30 30 end
31 31  
32   - step 'I visit group members page' do
33   - visit members_group_path(current_group)
  32 + step 'I visit group "Owned" members page' do
  33 + visit members_group_path(Group.find_by(name:"Owned"))
34 34 end
35 35  
36   - step 'I visit group settings page' do
37   - visit edit_group_path(current_group)
  36 + step 'I visit group "Owned" settings page' do
  37 + visit edit_group_path(Group.find_by(name:"Owned"))
  38 + end
  39 +
  40 + step 'I visit group "Guest" page' do
  41 + visit group_path(Group.find_by(name:"Guest"))
  42 + end
  43 +
  44 + step 'I visit group "Guest" issues page' do
  45 + visit issues_group_path(Group.find_by(name:"Guest"))
  46 + end
  47 +
  48 + step 'I visit group "Guest" merge requests page' do
  49 + visit merge_requests_group_path(Group.find_by(name:"Guest"))
  50 + end
  51 +
  52 + step 'I visit group "Guest" members page' do
  53 + visit members_group_path(Group.find_by(name:"Guest"))
  54 + end
  55 +
  56 + step 'I visit group "Guest" settings page' do
  57 + visit edit_group_path(Group.find_by(name:"Guest"))
38 58 end
39 59  
40 60 # ----------------------------------------
... ... @@ -93,6 +113,14 @@ module SharedPaths
93 113 visit history_profile_path
94 114 end
95 115  
  116 + step 'I visit profile groups page' do
  117 + visit profile_groups_path
  118 + end
  119 +
  120 + step 'I should be redirected to the profile groups page' do
  121 + current_path.should == profile_groups_path
  122 + end
  123 +
96 124 # ----------------------------------------
97 125 # Admin
98 126 # ----------------------------------------
... ... @@ -326,4 +354,12 @@ module SharedPaths
326 354 def project
327 355 project = Project.find_by!(name: "Shop")
328 356 end
  357 +
  358 + # ----------------------------------------
  359 + # Errors
  360 + # ----------------------------------------
  361 +
  362 + Then 'page status code should be 404' do
  363 + page.status_code.should == 404
  364 + end
329 365 end
... ...
features/steps/shared/project.rb
... ... @@ -58,10 +58,6 @@ module SharedProject
58 58 page.should have_content("Features:")
59 59 end
60 60  
61   - Then 'page status code should be 404' do
62   - page.status_code.should == 404
63   - end
64   -
65 61 def current_project
66 62 @project ||= Project.first
67 63 end
... ... @@ -107,24 +103,21 @@ module SharedProject
107 103 end
108 104  
109 105 step '"John Doe" is authorized to private project "Enterprise"' do
110   - user = User.find_by(name: "John Doe")
111   - user ||= create(:user, name: "John Doe", username: "john_doe")
  106 + user = user_exists("John Doe", username: "john_doe")
112 107 project = Project.find_by(name: "Enterprise")
113 108 project ||= create(:project, name: "Enterprise", namespace: user.namespace)
114 109 project.team << [user, :master]
115 110 end
116 111  
117 112 step '"John Doe" is authorized to internal project "Internal"' do
118   - user = User.find_by(name: "John Doe")
119   - user ||= create(:user, name: "John Doe", username: "john_doe")
  113 + user = user_exists("John Doe", username: "john_doe")
120 114 project = Project.find_by(name: "Internal")
121 115 project ||= create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL
122 116 project.team << [user, :master]
123 117 end
124 118  
125 119 step '"John Doe" is authorized to public project "Community"' do
126   - user = User.find_by(name: "John Doe")
127   - user ||= create(:user, name: "John Doe", username: "john_doe")
  120 + user = user_exists("John Doe", username: "john_doe")
128 121 project = Project.find_by(name: "Community")
129 122 project ||= create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC
130 123 project.team << [user, :master]
... ...
features/steps/shared/user.rb
1 1 module SharedUser
2 2 include Spinach::DSL
3 3  
4   - step 'Create user "John Doe"' do
5   - create(:user, name: "John Doe", username: "john_doe")
  4 + step 'User "John Doe" exists' do
  5 + user_exists("John Doe", {username: "john_doe"})
6 6 end
7 7  
8   - step 'I sign in as "John Doe"' do
9   - login_with(User.find_by(name: "John Doe"))
  8 + step 'User "Mary Jane" exists' do
  9 + user_exists("Mary Jane", {username: "mary_jane"})
  10 + end
  11 +
  12 + protected
  13 +
  14 + def user_exists(name, options = {})
  15 + User.find_by(name: name) || create(:user, {name: name, admin: false}.merge(options))
10 16 end
11 17 end
... ...
features/user.feature
1 1 Feature: User
2 2 Background:
3   - Given Create user "John Doe"
  3 + Given User "John Doe" exists
4 4 And "John Doe" is authorized to private project "Enterprise"
5 5  
6 6 # Signed out
... ...