Fix Canceled -> Cancelled (american vs canadian spelling, canada wins)
[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 'Check collection count for A Project in the tab pane titles' do
11     project_uuid = api_fixture('groups')['aproject']['uuid']
12     visit page_with_token 'active', '/projects/' + project_uuid
13     collection_count = page.all("[data-pk*='collection']").count
14     assert_selector '#Data_collections-tab span', text: "(#{collection_count})"
15   end
16
17   test 'Find a project and edit its description' do
18     visit page_with_token 'active', '/'
19     find('.arv-project-list a,button', text: 'A Project').
20       click
21     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
22       find('span', text: api_fixture('groups')['aproject']['name']).click
23       within('.arv-description-as-subtitle') do
24         find('.fa-pencil').click
25         find('.editable-input textarea').set('I just edited this.')
26         find('.editable-submit').click
27       end
28       wait_for_ajax
29     end
30     visit current_path
31     assert(find?('.container-fluid', text: 'I just edited this.'),
32            "Description update did not survive page refresh")
33   end
34
35   test 'Find a project and edit description to textile description' do
36     visit page_with_token 'active', '/'
37     find('.arv-project-list a,button', text: 'A Project').
38       click
39     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
40       find('span', text: api_fixture('groups')['aproject']['name']).click
41       within('.arv-description-as-subtitle') do
42         find('.fa-pencil').click
43         find('.editable-input textarea').set('<p>*Textile description for A project* - "take me home":/ </p><p>And a new paragraph in description.</p>')
44         find('.editable-submit').click
45       end
46       wait_for_ajax
47     end
48
49     # visit project page
50     visit current_path
51     assert(has_no_text?('.container-fluid', text: '*Textile description for A project*'),
52            "Description is not rendered properly")
53     assert(find?('.container-fluid', text: 'Textile description for A project'),
54            "Description update did not survive page refresh")
55     assert(find?('.container-fluid', text: 'And a new paragraph in description'),
56            "Description did not contain the expected new paragraph")
57     assert(page.has_link?("take me home"), "link not found in description")
58
59     click_link 'take me home'
60
61     # now in dashboard
62     assert(page.has_text?('My projects'), 'My projects - not found on dashboard')
63     assert(page.has_text?('Projects shared with me'), 'Projects shared with me - not found on dashboard')
64     assert(page.has_text?('Textile description for A project'), "Project description not found")
65     assert(page.has_no_text?('*Textile description for A project*'), "Project description is not rendered properly in dashboard")
66     assert(page.has_no_text?('And a new paragraph in description'), "Project description is not truncated after first paragraph")
67   end
68
69   test 'Find a project and edit description to html description' do
70     visit page_with_token 'active', '/'
71     find('.arv-project-list a,button', text: 'A Project').
72       click
73     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
74       find('span', text: api_fixture('groups')['aproject']['name']).click
75       within('.arv-description-as-subtitle') do
76         find('.fa-pencil').click
77         find('.editable-input textarea').set('<br>Textile description for A project</br> - <a href="/">take me home</a>')
78         find('.editable-submit').click
79       end
80       wait_for_ajax
81     end
82     visit current_path
83     assert(find?('.container-fluid', text: 'Textile description for A project'),
84            "Description update did not survive page refresh")
85     assert(!find?('.container-fluid', text: '<br>Textile description for A project</br>'),
86            "Textile description is displayed with uninterpreted formatting characters")
87     assert(page.has_link?("take me home"),"link not found in description")
88     click_link 'take me home'
89     assert page.has_text?('My projects')
90     assert page.has_text?('Projects shared with me')
91   end
92
93   test 'Find a project and edit description to textile description with link to object' do
94     visit page_with_token 'active', '/'
95     find('.arv-project-list a,button', text: 'A Project').
96       click
97     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
98       find('span', text: api_fixture('groups')['aproject']['name']).click
99       within('.arv-description-as-subtitle') do
100         find('.fa-pencil').click
101         find('.editable-input textarea').set('*Textile description for A project* - "go to sub-project":' + api_fixture('groups')['asubproject']['uuid'] + "'")
102         find('.editable-submit').click
103       end
104       wait_for_ajax
105     end
106     visit current_path
107     assert(find?('.container-fluid', text: 'Textile description for A project'),
108            "Description update did not survive page refresh")
109     assert(!find?('.container-fluid', text: '*Textile description for A project*'),
110            "Textile description is displayed with uninterpreted formatting characters")
111     assert(page.has_link?("go to sub-project"), "link not found in description")
112     click_link 'go to sub-project'
113     assert(page.has_text?(api_fixture('groups')['asubproject']['name']), 'sub-project name not found after clicking link')
114   end
115
116   test 'Add a new name, then edit it, without creating a duplicate' do
117     project_uuid = api_fixture('groups')['aproject']['uuid']
118     specimen_uuid = api_fixture('traits')['owned_by_aproject_with_no_name']['uuid']
119     visit page_with_token 'active', '/projects/' + project_uuid
120     click_link 'Other objects'
121     within '.selection-action-container' do
122       # Wait for the tab to load:
123       assert_selector 'tr[data-kind="arvados#trait"]'
124       within first('tr', text: 'Trait') do
125         find(".fa-pencil").click
126         find('.editable-input input').set('Now I have a name.')
127         find('.glyphicon-ok').click
128         assert_selector '.editable', text: 'Now I have a name.'
129         find(".fa-pencil").click
130         find('.editable-input input').set('Now I have a new name.')
131         find('.glyphicon-ok').click
132       end
133       wait_for_ajax
134       assert_selector '.editable', text: 'Now I have a new name.'
135     end
136     visit current_path
137     click_link 'Other objects'
138     within '.selection-action-container' do
139       find '.editable', text: 'Now I have a new name.'
140       page.assert_no_selector '.editable', text: 'Now I have a name.'
141     end
142   end
143
144   test 'Create a project and move it into a different project' do
145     visit page_with_token 'active', '/projects'
146     find('.btn', text: "Add new project").click
147
148     # within('.editable', text: 'New project') do
149     within('h2') do
150       find('.fa-pencil').click
151       find('.editable-input input').set('Project 1234')
152       find('.glyphicon-ok').click
153     end
154     wait_for_ajax
155
156     visit '/projects'
157     find('.btn', text: "Add new project").click
158     within('h2') do
159       find('.fa-pencil').click
160       find('.editable-input input').set('Project 5678')
161       find('.glyphicon-ok').click
162     end
163     wait_for_ajax
164
165     click_link 'Move to project...'
166     find('.selectable', text: 'Project 1234').click
167     find('.modal-footer a,button', text: 'Move').click
168     wait_for_ajax
169
170     # Wait for the page to refresh and show the new parent in Sharing panel
171     click_link 'Sharing'
172     assert(page.has_link?("Project 1234"),
173            "Project 5678 should now be inside project 1234")
174   end
175
176   def show_project_using(auth_key, proj_key='aproject')
177     project_uuid = api_fixture('groups')[proj_key]['uuid']
178     visit(page_with_token(auth_key, "/projects/#{project_uuid}"))
179     assert(page.has_text?("A Project"), "not on expected project page")
180   end
181
182   def share_rows
183     find('#project_sharing').all('tr')
184   end
185
186   def add_share_and_check(share_type, name)
187     assert(page.has_no_text?(name), "project is already shared with #{name}")
188     start_share_count = share_rows.size
189     click_on("Share with #{share_type}")
190     within(".modal-container") do
191       # Order is important here: we should find something that appears in the
192       # modal before we make any assertions about what's not in the modal.
193       # Otherwise, the not-included assertions might falsely pass because
194       # the modal hasn't loaded yet.
195       find(".selectable", text: name).click
196       assert(has_no_selector?(".modal-dialog-preview-pane"),
197              "preview pane available in sharing dialog")
198       assert_raises(Capybara::ElementNotFound,
199                     "Projects pulldown available from sharing dialog") do
200         click_on "All projects"
201       end
202       click_on "Add"
203     end
204     using_wait_time(Capybara.default_wait_time * 3) do
205       assert(page.has_link?(name),
206              "new share was not added to sharing table")
207       assert_equal(start_share_count + 1, share_rows.size,
208                    "new share did not add row to sharing table")
209     end
210   end
211
212   def modify_share_and_check(name)
213     start_rows = share_rows
214     link_row = start_rows.select { |row| row.has_text?(name) }
215     assert_equal(1, link_row.size, "row with new permission not found")
216     within(link_row.first) do
217       click_on("Read")
218       select("Write", from: "share_change_level")
219       click_on("editable-submit")
220       assert(has_link?("Write"),
221              "failed to change access level on new share")
222       click_on "Revoke"
223     end
224     using_wait_time(Capybara.default_wait_time * 3) do
225       assert(page.has_no_text?(name),
226              "new share row still exists after being revoked")
227       assert_equal(start_rows.size - 1, share_rows.size,
228                    "revoking share did not remove row from sharing table")
229     end
230   end
231
232   test "project viewer can't see project sharing tab" do
233     show_project_using("project_viewer")
234     assert(page.has_no_link?("Sharing"),
235            "read-only project user sees sharing tab")
236   end
237
238   test "project owner can manage sharing for another user" do
239     add_user = api_fixture('users')['future_project_user']
240     new_name = ["first_name", "last_name"].map { |k| add_user[k] }.join(" ")
241
242     show_project_using("active")
243     click_on "Sharing"
244     add_share_and_check("users", new_name)
245     modify_share_and_check(new_name)
246   end
247
248   test "project owner can manage sharing for another group" do
249     new_name = api_fixture('groups')['future_project_viewing_group']['name']
250
251     show_project_using("active")
252     click_on "Sharing"
253     add_share_and_check("groups", new_name)
254     modify_share_and_check(new_name)
255   end
256
257   test "'share with group' listing does not offer projects" do
258     show_project_using("active")
259     click_on "Sharing"
260     click_on "Share with groups"
261     good_uuid = api_fixture("groups")["private"]["uuid"]
262     assert(page.has_selector?(".selectable[data-object-uuid=\"#{good_uuid}\"]"),
263            "'share with groups' listing missing owned user group")
264     bad_uuid = api_fixture("groups")["asubproject"]["uuid"]
265     assert(page.has_no_selector?(".selectable[data-object-uuid=\"#{bad_uuid}\"]"),
266            "'share with groups' listing includes project")
267   end
268
269   [
270     'Move',
271     'Remove',
272     'Copy',
273   ].each do |action|
274     test "selection #{action} for project" do
275       src = api_fixture('groups')['aproject']
276       dest = api_fixture('groups')['asubproject']
277       my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
278
279       perform_selection_action src, dest, my_collection, action
280
281       case action
282       when 'Copy'
283         assert page.has_text?(my_collection['name']), 'Collection not found in src project after copy'
284         visit page_with_token 'active', '/'
285         find('.arv-project-list a,button', text: dest['name']).click
286         assert page.has_text?(my_collection['name']), 'Collection not found in dest project after copy'
287
288         # now remove it from destination project to restore to original state
289         perform_selection_action dest, nil, my_collection, 'Remove'
290       when 'Move'
291         assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after move'
292         visit page_with_token 'active', '/'
293         find('.arv-project-list a,button', text: dest['name']).click
294         assert page.has_text?(my_collection['name']), 'Collection not found in dest project after move'
295
296         # move it back to src project to restore to original state
297         perform_selection_action dest, src, my_collection, action
298       when 'Remove'
299         assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after remove'
300         visit page_with_token 'active', '/'
301         find('.arv-project-list a,button', text: 'Home').click
302         assert page.has_text?(my_collection['name']), 'Collection not found in home project after remove'
303       end
304     end
305   end
306
307   def perform_selection_action src, dest, item, action
308     visit page_with_token 'active', '/'
309     find('.arv-project-list a,button', text: src['name']).click
310     assert page.has_text?(item['name']), 'Collection not found in src project'
311
312     within('tr', text: item['name']) do
313       find('input[type=checkbox]').click
314     end
315
316     click_button 'Selection...'
317
318     within('.selection-action-container') do
319       assert page.has_text?("Compare selected"), "Compare selected link text not found"
320       assert page.has_link?("Copy selected"), "Copy selected link not found"
321       assert page.has_link?("Move selected"), "Move selected link not found"
322       assert page.has_link?("Remove selected"), "Remove selected link not found"
323
324       click_link "#{action} selected"
325     end
326
327     # select the destination project if a Copy or Move action is being performed
328     if action == 'Copy' || action == 'Move'
329       within(".modal-container") do
330         find('.selectable', text: dest['name']).click
331         find('.modal-footer a,button', text: action).click
332         wait_for_ajax
333       end
334     end
335   end
336
337   # Test copy action state. It should not be available when a subproject is selected.
338   test "copy action is disabled when a subproject is selected" do
339     my_project = api_fixture('groups')['aproject']
340     my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
341     my_subproject = api_fixture('groups')['asubproject']
342
343     # verify that selection options are disabled on the project until an item is selected
344     visit page_with_token 'active', '/'
345     find('.arv-project-list a,button', text: my_project['name']).click
346
347     click_button 'Selection...'
348     within('.selection-action-container') do
349       page.assert_selector 'li.disabled', text: 'Create new collection with selected collections'
350       page.assert_selector 'li.disabled', text: 'Compare selected'
351       page.assert_selector 'li.disabled', text: 'Copy selected'
352       page.assert_selector 'li.disabled', text: 'Move selected'
353       page.assert_selector 'li.disabled', text: 'Remove selected'
354     end
355
356     # select collection and verify links are enabled
357     visit page_with_token 'active', '/'
358     find('.arv-project-list a,button', text: my_project['name']).click
359     assert page.has_text?(my_collection['name']), 'Collection not found in project'
360
361     within('tr', text: my_collection['name']) do
362       find('input[type=checkbox]').click
363     end
364
365     click_button 'Selection...'
366     within('.selection-action-container') do
367       page.assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
368       page.assert_selector 'li', text: 'Create new collection with selected collections'
369       page.assert_selector 'li.disabled', text: 'Compare selected'
370       page.assert_no_selector 'li.disabled', text: 'Copy selected'
371       page.assert_selector 'li', text: 'Copy selected'
372       page.assert_no_selector 'li.disabled', text: 'Move selected'
373       page.assert_selector 'li', text: 'Move selected'
374       page.assert_no_selector 'li.disabled', text: 'Remove selected'
375       page.assert_selector 'li', text: 'Remove selected'
376     end
377
378     # select subproject and verify that copy action is disabled
379     visit page_with_token 'active', '/'
380     find('.arv-project-list a,button', text: my_project['name']).click
381
382     click_link 'Subprojects'
383     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
384
385     within('tr', text: my_subproject['name']) do
386       find('input[type=checkbox]').click
387     end
388
389     click_button 'Selection...'
390     within('.selection-action-container') do
391       page.assert_selector 'li.disabled', text: 'Create new collection with selected collections'
392       page.assert_selector 'li.disabled', text: 'Compare selected'
393       page.assert_selector 'li.disabled', text: 'Copy selected'
394       page.assert_no_selector 'li.disabled', text: 'Move selected'
395       page.assert_selector 'li', text: 'Move selected'
396       page.assert_no_selector 'li.disabled', text: 'Remove selected'
397       page.assert_selector 'li', text: 'Remove selected'
398     end
399
400     # select subproject and a collection and verify that copy action is still disabled
401     visit page_with_token 'active', '/'
402     find('.arv-project-list a,button', text: my_project['name']).click
403
404     click_link 'Subprojects'
405     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
406
407     within('tr', text: my_subproject['name']) do
408       find('input[type=checkbox]').click
409     end
410
411     click_link 'Data collections'
412     assert page.has_text?(my_collection['name']), 'Collection not found in project'
413
414     within('tr', text: my_collection['name']) do
415       find('input[type=checkbox]').click
416     end
417
418     click_button 'Selection...'
419     within('.selection-action-container') do
420       page.assert_selector 'li.disabled', text: 'Create new collection with selected collections'
421       page.assert_selector 'li.disabled', text: 'Compare selected'
422       page.assert_selector 'li.disabled', text: 'Copy selected'
423       page.assert_no_selector 'li.disabled', text: 'Move selected'
424       page.assert_selector 'li', text: 'Move selected'
425       page.assert_no_selector 'li.disabled', text: 'Remove selected'
426       page.assert_selector 'li', text: 'Remove selected'
427     end
428   end
429
430   test "combine selected collections into new collection" do
431     my_project = api_fixture('groups')['aproject']
432     my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
433
434     visit page_with_token 'active', '/'
435     find('.arv-project-list a,button', text: my_project['name']).click
436     assert page.has_text?(my_collection['name']), 'Collection not found in project'
437
438     within('tr', text: my_collection['name']) do
439       find('input[type=checkbox]').click
440     end
441
442     click_button 'Selection...'
443     within('.selection-action-container') do
444       click_link 'Create new collection with selected collections'
445     end
446
447     # back in project page
448     assert page.has_text?(my_collection['name']), 'Collection not found in project'
449     assert page.has_link?('Jobs and pipelines'), 'Jobs and pipelines link not found in project'
450   end
451
452 end