closes #4799
[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     headless = Headless.new
8     headless.start
9     Capybara.current_driver = :selenium
10
11     # project tests need bigger page size to be able to see all the buttons
12     Capybara.current_session.driver.browser.manage.window.resize_to(1152, 768)
13   end
14
15   test 'Check collection count for A Project in the tab pane titles' do
16     project_uuid = api_fixture('groups')['aproject']['uuid']
17     visit page_with_token 'active', '/projects/' + project_uuid
18     wait_for_ajax
19     collection_count = page.all("[data-pk*='collection']").count
20     assert_selector '#Data_collections-tab span', text: "(#{collection_count})"
21   end
22
23   test 'Find a project and edit its description' do
24     visit page_with_token 'active', '/'
25     find("#projects-menu").click
26     find(".dropdown-menu a", text: "A Project").click
27     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
28       find('span', text: api_fixture('groups')['aproject']['name']).click
29       within('.arv-description-as-subtitle') do
30         find('.fa-pencil').click
31         find('.editable-input textarea').set('I just edited this.')
32         find('.editable-submit').click
33       end
34       wait_for_ajax
35     end
36     visit current_path
37     assert(find?('.container-fluid', text: 'I just edited this.'),
38            "Description update did not survive page refresh")
39   end
40
41   test 'Find a project and edit description to textile description' do
42     visit page_with_token 'active', '/'
43     find("#projects-menu").click
44     find(".dropdown-menu a", text: "A Project").click
45     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
46       find('span', text: api_fixture('groups')['aproject']['name']).click
47       within('.arv-description-as-subtitle') do
48         find('.fa-pencil').click
49         find('.editable-input textarea').set('<p>*Textile description for A project* - "take me home":/ </p><p>And a new paragraph in description.</p>')
50         find('.editable-submit').click
51       end
52       wait_for_ajax
53     end
54
55     # visit project page
56     visit current_path
57     assert_no_text '*Textile description for A project*'
58     assert(find?('.container-fluid', text: 'Textile description for A project'),
59            "Description update did not survive page refresh")
60     assert(find?('.container-fluid', text: 'And a new paragraph in description'),
61            "Description did not contain the expected new paragraph")
62     assert(page.has_link?("take me home"), "link not found in description")
63
64     click_link 'take me home'
65
66     # now in dashboard
67     assert(page.has_text?('Active pipelines'), 'Active pipelines - not found on dashboard')
68   end
69
70   test 'Find a project and edit description to html description' do
71     visit page_with_token 'active', '/'
72     find("#projects-menu").click
73     find(".dropdown-menu a", text: "A Project").click
74     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
75       find('span', text: api_fixture('groups')['aproject']['name']).click
76       within('.arv-description-as-subtitle') do
77         find('.fa-pencil').click
78         find('.editable-input textarea').set('<br>Textile description for A project</br> - <a href="/">take me home</a>')
79         find('.editable-submit').click
80       end
81       wait_for_ajax
82     end
83     visit current_path
84     assert(find?('.container-fluid', text: 'Textile description for A project'),
85            "Description update did not survive page refresh")
86     assert(!find?('.container-fluid', text: '<br>Textile description for A project</br>'),
87            "Textile description is displayed with uninterpreted formatting characters")
88     assert(page.has_link?("take me home"),"link not found in description")
89     click_link 'take me home'
90     assert page.has_text?('Active pipelines')
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("#projects-menu").click
96     find(".dropdown-menu a", text: "A Project").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       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("#projects-menu").click
147     find(".dropdown-menu a", text: "Home").click
148     find('.btn', text: "Add a subproject").click
149
150     # within('.editable', text: 'New project') do
151     within('h2') do
152       find('.fa-pencil').click
153       find('.editable-input input').set('Project 1234')
154       find('.glyphicon-ok').click
155     end
156     wait_for_ajax
157
158     visit '/projects'
159     find("#projects-menu").click
160     find(".dropdown-menu a", text: "Home").click
161     find('.btn', text: "Add a subproject").click
162     within('h2') do
163       find('.fa-pencil').click
164       find('.editable-input input').set('Project 5678')
165       find('.glyphicon-ok').click
166     end
167     wait_for_ajax
168
169     click_link 'Move project...'
170     find('.selectable', text: 'Project 1234').click
171     find('.modal-footer a,button', text: 'Move').click
172     wait_for_ajax
173
174     # Wait for the page to refresh and show the new parent in Sharing panel
175     click_link 'Sharing'
176     assert(page.has_link?("Project 1234"),
177            "Project 5678 should now be inside project 1234")
178   end
179
180   def show_project_using(auth_key, proj_key='aproject')
181     project_uuid = api_fixture('groups')[proj_key]['uuid']
182     visit(page_with_token(auth_key, "/projects/#{project_uuid}"))
183     assert(page.has_text?("A Project"), "not on expected project page")
184   end
185
186   def share_rows
187     find('#project_sharing').all('tr')
188   end
189
190   def add_share_and_check(share_type, name, obj=nil)
191     assert(page.has_no_text?(name), "project is already shared with #{name}")
192     start_share_count = share_rows.size
193     click_on("Share with #{share_type}")
194     within(".modal-container") do
195       # Order is important here: we should find something that appears in the
196       # modal before we make any assertions about what's not in the modal.
197       # Otherwise, the not-included assertions might falsely pass because
198       # the modal hasn't loaded yet.
199       find(".selectable", text: name).click
200       assert(has_no_selector?(".modal-dialog-preview-pane"),
201              "preview pane available in sharing dialog")
202       if share_type == 'users' and obj and obj['email']
203         assert(page.has_text?(obj['email']), "Did not find user's email")
204       end
205       assert_raises(Capybara::ElementNotFound,
206                     "Projects pulldown available from sharing dialog") do
207         click_on "All projects"
208       end
209       click_on "Add"
210     end
211     using_wait_time(Capybara.default_wait_time * 3) do
212       assert(page.has_link?(name),
213              "new share was not added to sharing table")
214       assert_equal(start_share_count + 1, share_rows.size,
215                    "new share did not add row to sharing table")
216     end
217   end
218
219   def modify_share_and_check(name)
220     start_rows = share_rows
221     link_row = start_rows.select { |row| row.has_text?(name) }
222     assert_equal(1, link_row.size, "row with new permission not found")
223     within(link_row.first) do
224       click_on("Read")
225       select("Write", from: "share_change_level")
226       click_on("editable-submit")
227       assert(has_link?("Write"),
228              "failed to change access level on new share")
229       click_on "Revoke"
230       page.driver.browser.switch_to.alert.accept
231     end
232     wait_for_ajax
233     using_wait_time(Capybara.default_wait_time * 3) do
234       assert(page.has_no_text?(name),
235              "new share row still exists after being revoked")
236       assert_equal(start_rows.size - 1, share_rows.size,
237                    "revoking share did not remove row from sharing table")
238     end
239   end
240
241   test "project viewer can't see project sharing tab" do
242     show_project_using("project_viewer")
243     assert(page.has_no_link?("Sharing"),
244            "read-only project user sees sharing tab")
245   end
246
247   test "project owner can manage sharing for another user" do
248     add_user = api_fixture('users')['future_project_user']
249     new_name = ["first_name", "last_name"].map { |k| add_user[k] }.join(" ")
250
251     show_project_using("active")
252     click_on "Sharing"
253     add_share_and_check("users", new_name, add_user)
254     modify_share_and_check(new_name)
255   end
256
257   test "project owner can manage sharing for another group" do
258     new_name = api_fixture('groups')['future_project_viewing_group']['name']
259
260     show_project_using("active")
261     click_on "Sharing"
262     add_share_and_check("groups", new_name)
263     modify_share_and_check(new_name)
264   end
265
266   test "'share with group' listing does not offer projects" do
267     show_project_using("active")
268     click_on "Sharing"
269     click_on "Share with groups"
270     good_uuid = api_fixture("groups")["private"]["uuid"]
271     assert(page.has_selector?(".selectable[data-object-uuid=\"#{good_uuid}\"]"),
272            "'share with groups' listing missing owned user group")
273     bad_uuid = api_fixture("groups")["asubproject"]["uuid"]
274     assert(page.has_no_selector?(".selectable[data-object-uuid=\"#{bad_uuid}\"]"),
275            "'share with groups' listing includes project")
276   end
277
278   [
279     ['Move',api_fixture('collections')['collection_to_move_around_in_aproject'],
280       api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
281     ['Remove',api_fixture('collections')['collection_to_move_around_in_aproject'],
282       api_fixture('groups')['aproject']],
283     ['Copy',api_fixture('collections')['collection_to_move_around_in_aproject'],
284       api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
285     ['Remove',api_fixture('collections')['collection_in_aproject_with_same_name_as_in_home_project'],
286       api_fixture('groups')['aproject'],nil,true],
287   ].each do |action, my_collection, src, dest=nil, expect_name_change=nil|
288     test "selection #{action} -> #{expect_name_change.inspect} for project" do
289       perform_selection_action src, dest, my_collection, action
290
291       case action
292       when 'Copy'
293         assert page.has_text?(my_collection['name']), 'Collection not found in src project after copy'
294         visit page_with_token 'active', '/'
295         find("#projects-menu").click
296         find(".dropdown-menu a", text: dest['name']).click
297         assert page.has_text?(my_collection['name']), 'Collection not found in dest project after copy'
298
299       when 'Move'
300         assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after move'
301         visit page_with_token 'active', '/'
302         find("#projects-menu").click
303         find(".dropdown-menu a", text: dest['name']).click
304         assert page.has_text?(my_collection['name']), 'Collection not found in dest project after move'
305
306       when 'Remove'
307         assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after remove'
308         visit page_with_token 'active', '/'
309         find("#projects-menu").click
310         find(".dropdown-menu a", text: "Home").click
311         assert page.has_text?(my_collection['name']), 'Collection not found in home project after remove'
312         if expect_name_change
313           assert page.has_text?(my_collection['name']+' removed from ' + src['name']),
314             'Collection with update name is not found in home project after remove'
315         end
316       end
317     end
318   end
319
320   def perform_selection_action src, dest, item, action
321     visit page_with_token 'active', '/'
322     find("#projects-menu").click
323     find(".dropdown-menu a", text: src['name']).click
324     assert page.has_text?(item['name']), 'Collection not found in src project'
325
326     within('tr', text: item['name']) do
327       find('input[type=checkbox]').click
328     end
329
330     click_button 'Selection'
331
332     within('.selection-action-container') do
333       assert page.has_text?("Compare selected"), "Compare selected link text not found"
334       assert page.has_link?("Copy selected"), "Copy selected link not found"
335       assert page.has_link?("Move selected"), "Move selected link not found"
336       assert page.has_link?("Remove selected"), "Remove selected link not found"
337
338       click_link "#{action} selected"
339     end
340
341     # select the destination project if a Copy or Move action is being performed
342     if action == 'Copy' || action == 'Move'
343       within(".modal-container") do
344         find('.selectable', text: dest['name']).click
345         find('.modal-footer a,button', text: action).click
346         wait_for_ajax
347       end
348     end
349   end
350
351   # Test copy action state. It should not be available when a subproject is selected.
352   test "copy action is disabled when a subproject is selected" do
353     my_project = api_fixture('groups')['aproject']
354     my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
355     my_subproject = api_fixture('groups')['asubproject']
356
357     # verify that selection options are disabled on the project until an item is selected
358     visit page_with_token 'active', '/'
359     find("#projects-menu").click
360     find(".dropdown-menu a", text: my_project['name']).click
361
362     click_button 'Selection'
363     within('.selection-action-container') do
364       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
365       assert_selector 'li.disabled', text: 'Compare selected'
366       assert_selector 'li.disabled', text: 'Copy selected'
367       assert_selector 'li.disabled', text: 'Move selected'
368       assert_selector 'li.disabled', text: 'Remove selected'
369     end
370
371     # select collection and verify links are enabled
372     visit page_with_token 'active', '/'
373     find("#projects-menu").click
374     find(".dropdown-menu a", text: my_project['name']).click
375     assert page.has_text?(my_collection['name']), 'Collection not found in project'
376
377     within('tr', text: my_collection['name']) do
378       find('input[type=checkbox]').click
379     end
380
381     click_button 'Selection'
382     within('.selection-action-container') do
383       assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
384       assert_selector 'li', text: 'Create new collection with selected collections'
385       assert_selector 'li.disabled', text: 'Compare selected'
386       assert_no_selector 'li.disabled', text: 'Copy selected'
387       assert_selector 'li', text: 'Copy selected'
388       assert_no_selector 'li.disabled', text: 'Move selected'
389       assert_selector 'li', text: 'Move selected'
390       assert_no_selector 'li.disabled', text: 'Remove selected'
391       assert_selector 'li', text: 'Remove selected'
392     end
393
394     # select subproject and verify that copy action is disabled
395     visit page_with_token 'active', '/'
396     find("#projects-menu").click
397     find(".dropdown-menu a", text: my_project['name']).click
398
399     click_link 'Subprojects'
400     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
401
402     within('tr', text: my_subproject['name']) do
403       find('input[type=checkbox]').click
404     end
405
406     click_button 'Selection'
407     within('.selection-action-container') do
408       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
409       assert_selector 'li.disabled', text: 'Compare selected'
410       assert_selector 'li.disabled', text: 'Copy selected'
411       assert_no_selector 'li.disabled', text: 'Move selected'
412       assert_selector 'li', text: 'Move selected'
413       assert_no_selector 'li.disabled', text: 'Remove selected'
414       assert_selector 'li', text: 'Remove selected'
415     end
416
417     # select subproject and a collection and verify that copy action is still disabled
418     visit page_with_token 'active', '/'
419     find("#projects-menu").click
420     find(".dropdown-menu a", text: my_project['name']).click
421
422     click_link 'Subprojects'
423     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
424
425     within('tr', text: my_subproject['name']) do
426       find('input[type=checkbox]').click
427     end
428
429     click_link 'Data collections'
430     assert page.has_text?(my_collection['name']), 'Collection not found in project'
431
432     within('tr', text: my_collection['name']) do
433       find('input[type=checkbox]').click
434     end
435
436     click_link 'Subprojects'
437     click_button 'Selection'
438     within('.selection-action-container') do
439       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
440       assert_selector 'li.disabled', text: 'Compare selected'
441       assert_selector 'li.disabled', text: 'Copy selected'
442       assert_no_selector 'li.disabled', text: 'Move selected'
443       assert_selector 'li', text: 'Move selected'
444       assert_no_selector 'li.disabled', text: 'Remove selected'
445       assert_selector 'li', text: 'Remove selected'
446     end
447   end
448
449   # When project tabs are switched, only options applicable to the current tab's selections are enabled.
450   test "verify selection options when tabs are switched" do
451     my_project = api_fixture('groups')['aproject']
452     my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
453     my_subproject = api_fixture('groups')['asubproject']
454
455     # select subproject and a collection and verify that copy action is still disabled
456     visit page_with_token 'active', '/'
457     find("#projects-menu").click
458     find(".dropdown-menu a", text: my_project['name']).click
459
460     # Select a sub-project
461     click_link 'Subprojects'
462     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
463
464     within('tr', text: my_subproject['name']) do
465       find('input[type=checkbox]').click
466     end
467
468     # Select a collection
469     click_link 'Data collections'
470     assert page.has_text?(my_collection['name']), 'Collection not found in project'
471
472     within('tr', text: my_collection['name']) do
473       find('input[type=checkbox]').click
474     end
475
476     # Go back to Subprojects tab
477     click_link 'Subprojects'
478     click_button 'Selection'
479     within('.selection-action-container') do
480       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
481       assert_selector 'li.disabled', text: 'Compare selected'
482       assert_selector 'li.disabled', text: 'Copy selected'
483       assert_no_selector 'li.disabled', text: 'Move selected'
484       assert_selector 'li', text: 'Move selected'
485       assert_no_selector 'li.disabled', text: 'Remove selected'
486       assert_selector 'li', text: 'Remove selected'
487     end
488
489     # Go back to Data collections tab
490     click_link 'Data collections'
491     click_button 'Selection'
492     within('.selection-action-container') do
493       assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
494       assert_selector 'li', text: 'Create new collection with selected collections'
495       assert_selector 'li.disabled', text: 'Compare selected'
496       assert_no_selector 'li.disabled', text: 'Copy selected'
497       assert_selector 'li', text: 'Copy selected'
498       assert_no_selector 'li.disabled', text: 'Move selected'
499       assert_selector 'li', text: 'Move selected'
500       assert_no_selector 'li.disabled', text: 'Remove selected'
501       assert_selector 'li', text: 'Remove selected'
502     end
503   end
504
505   # "Move selected" and "Remove selected" options should not be available when current user cannot write to the project
506   test "move selected and remove selected actions not available when current user cannot write to project" do
507     my_project = api_fixture('groups')['anonymously_accessible_project']
508     visit page_with_token 'active', "/projects/#{my_project['uuid']}"
509
510     click_button 'Selection'
511     within('.selection-action-container') do
512       assert_selector 'li', text: 'Create new collection with selected collections'
513       assert_selector 'li', text: 'Compare selected'
514       assert_selector 'li', text: 'Copy selected'
515       assert_no_selector 'li', text: 'Move selected'
516       assert_no_selector 'li', text: 'Remove selected'
517     end
518   end
519
520   [
521     ['active', true],
522     ['project_viewer', false],
523   ].each do |user, expect_collection_in_aproject|
524     test "combine selected collections into new collection #{user} #{expect_collection_in_aproject}" do
525       my_project = api_fixture('groups')['aproject']
526       my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
527
528       visit page_with_token user, '/'
529       find("#projects-menu").click
530       find(".dropdown-menu a", text: my_project['name']).click
531       assert page.has_text?(my_collection['name']), 'Collection not found in project'
532
533       within('tr', text: my_collection['name']) do
534         find('input[type=checkbox]').click
535       end
536
537       click_button 'Selection'
538       within('.selection-action-container') do
539         click_link 'Create new collection with selected collections'
540       end
541
542       # now in the new collection page
543       if expect_collection_in_aproject
544         assert page.has_text?("Created new collection in the project #{my_project['name']}"),
545                               'Not found flash message that new collection is created in aproject'
546       else
547         assert page.has_text?("Created new collection in your Home project"),
548                               'Not found flash message that new collection is created in Home project'
549       end
550       assert page.has_text?('Content hash'), 'Not found content hash in collection page'
551     end
552   end
553
554   [
555     ["jobs", "/jobs"],
556     ["pipelines", "/pipeline_instances"],
557     ["collections", "/collections"]
558   ].each do |target,path|
559     test "Test dashboard button all #{target}" do
560       visit page_with_token 'active', '/'
561       click_link "All #{target}"
562       assert_equal path, current_path
563     end
564   end
565
566   def scroll_setup(project_name,
567                    total_nbr_items,
568                    item_list_parameter,
569                    sorted = false,
570                    sort_parameters = nil)
571     project_uuid = api_fixture('groups')[project_name]['uuid']
572     visit page_with_token 'user1_with_load', '/projects/' + project_uuid
573
574     assert(page.has_text?("#{item_list_parameter.humanize} (#{total_nbr_items})"), "Number of #{item_list_parameter.humanize} did not match the input amount")
575
576     click_link item_list_parameter.humanize
577     wait_for_ajax
578
579     if sorted
580       find("th[data-sort-order='#{sort_parameters.gsub(/\s/,'')}']").click
581       wait_for_ajax
582     end
583   end
584
585   def scroll_items_check(nbr_items,
586                          fixture_prefix,
587                          item_list_parameter,
588                          item_selector,
589                          sorted = false)
590     items = []
591     for i in 1..nbr_items
592       items << "#{fixture_prefix}#{i}"
593     end
594
595     verify_items = items.dup
596     unexpected_items = []
597     item_count = 0
598     within(".arv-project-#{item_list_parameter}") do
599       page.execute_script "window.scrollBy(0,999000)"
600       begin
601         wait_for_ajax
602       rescue
603       end
604
605       # Visit all rows. If not all expected items are found, retry
606       found_items = page.all(item_selector)
607       item_count = found_items.count
608
609       previous = nil
610       (0..item_count-1).each do |i|
611         # Found row text using the fixture string e.g. "Show Collection_#{n} "
612         item_name = found_items[i].text.split[1]
613         if !items.include? item_name
614           unexpected_items << item_name
615         else
616           verify_items.delete item_name
617         end
618         if sorted
619           # check sort order
620           assert_operator( previous.downcase, :<=, item_name.downcase) if previous
621           previous = item_name
622         end
623       end
624
625       assert_equal true, unexpected_items.empty?, "Found unexpected #{item_list_parameter.humanize} #{unexpected_items.inspect}"
626       assert_equal nbr_items, item_count, "Found different number of #{item_list_parameter.humanize}"
627       assert_equal true, verify_items.empty?, "Did not find all the #{item_list_parameter.humanize}"
628     end
629   end
630
631   [
632     ['project_with_10_collections', 10],
633     ['project_with_201_collections', 201], # two pages of data
634   ].each do |project_name, nbr_items|
635     test "scroll collections tab for #{project_name} with #{nbr_items} objects" do
636       item_list_parameter = "Data_collections"
637       scroll_setup project_name,
638                    nbr_items,
639                    item_list_parameter
640       scroll_items_check nbr_items,
641                          "Collection_",
642                          item_list_parameter,
643                          'tr[data-kind="arvados#collection"]'
644     end
645   end
646
647   [
648     ['project_with_10_collections', 10],
649     ['project_with_201_collections', 201], # two pages of data
650   ].each do |project_name, nbr_items|
651     test "scroll collections tab for #{project_name} with #{nbr_items} objects with ascending sort (case insensitive)" do
652       item_list_parameter = "Data_collections"
653       scroll_setup project_name,
654                    nbr_items,
655                    item_list_parameter,
656                    true,
657                    "collections.name"
658       scroll_items_check nbr_items,
659                          "Collection_",
660                          item_list_parameter,
661                          'tr[data-kind="arvados#collection"]',
662                          true
663     end
664   end
665
666   [
667     ['project_with_10_pipelines', 10, 0],
668     ['project_with_2_pipelines_and_60_jobs', 2, 60],
669     ['project_with_25_pipelines', 25, 0],
670   ].each do |project_name, num_pipelines, num_jobs|
671     test "scroll pipeline instances tab for #{project_name} with #{num_pipelines} pipelines and #{num_jobs} jobs" do
672       item_list_parameter = "Jobs_and_pipelines"
673       scroll_setup project_name,
674                    num_pipelines + num_jobs,
675                    item_list_parameter
676       # check the general scrolling and the pipelines
677       scroll_items_check num_pipelines,
678                          "pipeline_",
679                          item_list_parameter,
680                          'tr[data-kind="arvados#pipelineInstance"]'
681       # Check job count separately
682       jobs_found = page.all('tr[data-kind="arvados#job"]')
683       found_job_count = jobs_found.count
684       assert_equal num_jobs, found_job_count, 'Did not find expected number of jobs'
685     end
686   end
687
688   # Move button accessibility
689   [
690     ['admin', true],
691     ['active', true],  # project owner
692     ['project_viewer', false],
693     ].each do |user, can_move|
694     test "#{user} can move subproject under another user's Home #{can_move}" do
695       project = api_fixture('groups')['aproject']
696       collection = api_fixture('collections')['collection_to_move_around_in_aproject']
697
698       # verify the project move button
699       visit page_with_token user, "/projects/#{project['uuid']}"
700       if can_move
701         assert page.has_link? 'Move project...'
702       else
703         assert page.has_no_link? 'Move project...'
704       end
705     end
706   end
707
708   test "error while loading tab" do
709     original_arvados_v1_base = Rails.configuration.arvados_v1_base
710
711     visit page_with_token 'active', '/projects/' + api_fixture('groups')['aproject']['uuid']
712
713     # Point to a bad api server url to generate error
714     Rails.configuration.arvados_v1_base = "https://[100::f]:1/"
715     click_link 'Other objects'
716     within '#Other_objects' do
717       # Error
718       assert_selector('a', text: 'Reload tab')
719
720       # Now point back to the orig api server and reload tab
721       Rails.configuration.arvados_v1_base = original_arvados_v1_base
722       click_link 'Reload tab'
723       assert_no_selector('a', text: 'Reload tab')
724       assert_selector('button', text: 'Selection')
725       within '.selection-action-container' do
726         assert_selector 'tr[data-kind="arvados#trait"]'
727       end
728     end
729   end
730
731 end