Merge branch 'master' into 3339-truncate-project-descriptions
[arvados.git] / apps / workbench / test / integration / projects_test.rb
1 require 'integration_helper'
2 require 'selenium-webdriver'
3 require 'headless'
4
5 class ProjectsTest < ActionDispatch::IntegrationTest
6   setup do
7     Capybara.current_driver = Capybara.javascript_driver
8   end
9
10   test 'Find a project and edit its description' do
11     visit page_with_token 'active', '/'
12     find('.arv-project-list a,button', text: 'A Project').
13       click
14     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
15       find('span', text: api_fixture('groups')['aproject']['name']).click
16       within('.arv-description-as-subtitle') do
17         find('.fa-pencil').click
18         find('.editable-input textarea').set('I just edited this.')
19         find('.editable-submit').click
20       end
21       wait_for_ajax
22     end
23     visit current_path
24     assert(find?('.container-fluid', text: 'I just edited this.'),
25            "Description update did not survive page refresh")
26   end
27
28   test 'Find a project and edit description to textile description' do
29     visit page_with_token 'active', '/'
30     find('.arv-project-list a,button', text: 'A Project').
31       click
32     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
33       find('span', text: api_fixture('groups')['aproject']['name']).click
34       within('.arv-description-as-subtitle') do
35         find('.fa-pencil').click
36         find('.editable-input textarea').set('<p>*Textile description for A project* - "take me home":/ </p><p>And a new paragraph in description.<p/>')
37         find('.editable-submit').click
38       end
39       wait_for_ajax
40     end
41
42     # visit project page
43     visit current_path
44     assert(has_no_text?('.container-fluid', text: '*Textile description for A project*'),
45            "Description is not rendered properly")
46     assert(find?('.container-fluid', text: 'Textile description for A project'),
47            "Description update did not survive page refresh")
48     assert(find?('.container-fluid', text: 'And a new paragraph in description'),
49            "Description did not contain the expected new paragraph")
50     assert(page.has_link?("take me home"), "link not found in description")
51
52     click_link 'take me home'
53
54     # now in dashboard
55     assert(page.has_text?('My projects'), 'My projects - not found on dashboard')
56     assert(page.has_text?('Projects shared with me'), 'Projects shared with me - not found on dashboard')
57     assert(page.has_text?('Textile description for A project'), "Project description not found")
58     assert(page.has_no_text?('*Textile description for A project*'), "Project description is not rendered properly in dashboard")
59     assert(page.has_no_text?('And a new paragraph in description'), "Project description is not truncated after first paragraph")
60   end
61
62   test 'Find a project and edit description to html description' do
63     visit page_with_token 'active', '/'
64     find('.arv-project-list a,button', text: 'A Project').
65       click
66     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
67       find('span', text: api_fixture('groups')['aproject']['name']).click
68       within('.arv-description-as-subtitle') do
69         find('.fa-pencil').click
70         find('.editable-input textarea').set('<br>Textile description for A project</br> - <a href="/">take me home</a>')
71         find('.editable-submit').click
72       end
73       wait_for_ajax
74     end
75     visit current_path
76     assert(find?('.container-fluid', text: 'Textile description for A project'),
77            "Description update did not survive page refresh")
78     assert(!find?('.container-fluid', text: '<br>Textile description for A project</br>'),
79            "Textile description is displayed with uninterpreted formatting characters")
80     assert(page.has_link?("take me home"),"link not found in description")
81     click_link 'take me home'
82     assert page.has_text?('My projects')
83     assert page.has_text?('Projects shared with me')
84   end
85
86   test 'Find a project and edit description to textile description with link to object' do
87     visit page_with_token 'active', '/'
88     find('.arv-project-list a,button', text: 'A Project').
89       click
90     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
91       find('span', text: api_fixture('groups')['aproject']['name']).click
92       within('.arv-description-as-subtitle') do
93         find('.fa-pencil').click
94         find('.editable-input textarea').set('*Textile description for A project* - "go to sub-project":' + api_fixture('groups')['asubproject']['uuid'] + "'")
95         find('.editable-submit').click
96       end
97       wait_for_ajax
98     end
99     visit current_path
100     assert(find?('.container-fluid', text: 'Textile description for A project'),
101            "Description update did not survive page refresh")
102     assert(!find?('.container-fluid', text: '*Textile description for A project*'),
103            "Textile description is displayed with uninterpreted formatting characters")
104     assert(page.has_link?("go to sub-project"), "link not found in description")
105     click_link 'go to sub-project'
106     assert(page.has_text?(api_fixture('groups')['asubproject']['name']), 'sub-project name not found after clicking link')
107   end
108
109   test 'Add a new name, then edit it, without creating a duplicate' do
110     project_uuid = api_fixture('groups')['aproject']['uuid']
111     specimen_uuid = api_fixture('traits')['owned_by_aproject_with_no_name']['uuid']
112     visit page_with_token 'active', '/projects/' + project_uuid
113     click_link 'Other objects'
114     within '.selection-action-container' do
115       # Wait for the tab to load:
116       assert_selector 'tr[data-kind="arvados#trait"]'
117       within first('tr', text: 'Trait') do
118         find(".fa-pencil").click
119         find('.editable-input input').set('Now I have a name.')
120         find('.glyphicon-ok').click
121         assert_selector '.editable', text: 'Now I have a name.'
122         find(".fa-pencil").click
123         find('.editable-input input').set('Now I have a new name.')
124         find('.glyphicon-ok').click
125       end
126       wait_for_ajax
127       assert_selector '.editable', text: 'Now I have a new name.'
128     end
129     visit current_path
130     click_link 'Other objects'
131     within '.selection-action-container' do
132       find '.editable', text: 'Now I have a new name.'
133       page.assert_no_selector '.editable', text: 'Now I have a name.'
134     end
135   end
136
137   test 'Create a project and move it into a different project' do
138     visit page_with_token 'active', '/projects'
139     find('.btn', text: "Add new project").click
140
141     # within('.editable', text: 'New project') do
142     within('h2') do
143       find('.fa-pencil').click
144       find('.editable-input input').set('Project 1234')
145       find('.glyphicon-ok').click
146     end
147     wait_for_ajax
148
149     visit '/projects'
150     find('.btn', text: "Add new project").click
151     within('h2') do
152       find('.fa-pencil').click
153       find('.editable-input input').set('Project 5678')
154       find('.glyphicon-ok').click
155     end
156     wait_for_ajax
157
158     click_link 'Move project...'
159     find('.selectable', text: 'Project 1234').click
160     find('.modal-footer a,button', text: 'Move').click
161     wait_for_ajax
162
163     # Wait for the page to refresh and show the new parent in Sharing panel
164     click_link 'Sharing'
165     assert(page.has_link?("Project 1234"),
166            "Project 5678 should now be inside project 1234")
167   end
168
169   def show_project_using(auth_key, proj_key='aproject')
170     project_uuid = api_fixture('groups')[proj_key]['uuid']
171     visit(page_with_token(auth_key, "/projects/#{project_uuid}"))
172     assert(page.has_text?("A Project"), "not on expected project page")
173   end
174
175   def share_rows
176     find('#project_sharing').all('tr')
177   end
178
179   def add_share_and_check(share_type, name)
180     assert(page.has_no_text?(name), "project is already shared with #{name}")
181     start_share_count = share_rows.size
182     click_on("Share with #{share_type}")
183     within(".modal-container") do
184       # Order is important here: we should find something that appears in the
185       # modal before we make any assertions about what's not in the modal.
186       # Otherwise, the not-included assertions might falsely pass because
187       # the modal hasn't loaded yet.
188       find(".selectable", text: name).click
189       assert(has_no_selector?(".modal-dialog-preview-pane"),
190              "preview pane available in sharing dialog")
191       assert_raises(Capybara::ElementNotFound,
192                     "Projects pulldown available from sharing dialog") do
193         click_on "All projects"
194       end
195       click_on "Add"
196     end
197     using_wait_time(Capybara.default_wait_time * 3) do
198       assert(page.has_link?(name),
199              "new share was not added to sharing table")
200       assert_equal(start_share_count + 1, share_rows.size,
201                    "new share did not add row to sharing table")
202     end
203   end
204
205   def modify_share_and_check(name)
206     start_rows = share_rows
207     link_row = start_rows.select { |row| row.has_text?(name) }
208     assert_equal(1, link_row.size, "row with new permission not found")
209     within(link_row.first) do
210       click_on("Read")
211       select("Write", from: "share_change_level")
212       click_on("editable-submit")
213       assert(has_link?("Write"),
214              "failed to change access level on new share")
215       click_on "Revoke"
216     end
217     using_wait_time(Capybara.default_wait_time * 3) do
218       assert(page.has_no_text?(name),
219              "new share row still exists after being revoked")
220       assert_equal(start_rows.size - 1, share_rows.size,
221                    "revoking share did not remove row from sharing table")
222     end
223   end
224
225   test "project viewer can't see project sharing tab" do
226     show_project_using("project_viewer")
227     assert(page.has_no_link?("Sharing"),
228            "read-only project user sees sharing tab")
229   end
230
231   test "project owner can manage sharing for another user" do
232     add_user = api_fixture('users')['future_project_user']
233     new_name = ["first_name", "last_name"].map { |k| add_user[k] }.join(" ")
234
235     show_project_using("active")
236     click_on "Sharing"
237     add_share_and_check("users", new_name)
238     modify_share_and_check(new_name)
239   end
240
241   test "project owner can manage sharing for another group" do
242     new_name = api_fixture('groups')['future_project_viewing_group']['name']
243
244     show_project_using("active")
245     click_on "Sharing"
246     add_share_and_check("groups", new_name)
247     modify_share_and_check(new_name)
248   end
249
250   test "'share with group' listing does not offer projects" do
251     show_project_using("active")
252     click_on "Sharing"
253     click_on "Share with groups"
254     good_uuid = api_fixture("groups")["private"]["uuid"]
255     assert(page.has_selector?(".selectable[data-object-uuid=\"#{good_uuid}\"]"),
256            "'share with groups' listing missing owned user group")
257     bad_uuid = api_fixture("groups")["asubproject"]["uuid"]
258     assert(page.has_no_selector?(".selectable[data-object-uuid=\"#{bad_uuid}\"]"),
259            "'share with groups' listing includes project")
260   end
261 end