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