Add 'apps/arv-web/' from commit 'f9732ad8460d013c2f28363655d0d1b91894dca5'
[arvados.git] / apps / workbench / test / integration / projects_test.rb
1 require 'integration_helper'
2
3 class ProjectsTest < ActionDispatch::IntegrationTest
4   setup do
5     need_javascript
6   end
7
8   test 'Check collection count for A Project in the tab pane titles' do
9     project_uuid = api_fixture('groups')['aproject']['uuid']
10     visit page_with_token 'active', '/projects/' + project_uuid
11     wait_for_ajax
12     collection_count = page.all("[data-pk*='collection']").count
13     assert_selector '#Data_collections-tab span', text: "(#{collection_count})"
14   end
15
16   test 'Find a project and edit its description' do
17     visit page_with_token 'active', '/'
18     find("#projects-menu").click
19     find(".dropdown-menu a", text: "A Project").click
20     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
21       find('span', text: api_fixture('groups')['aproject']['name']).click
22       within('.arv-description-as-subtitle') do
23         find('.fa-pencil').click
24         find('.editable-input textarea').set('I just edited this.')
25         find('.editable-submit').click
26       end
27       wait_for_ajax
28     end
29     visit current_path
30     assert(find?('.container-fluid', text: 'I just edited this.'),
31            "Description update did not survive page refresh")
32   end
33
34   test 'Find a project and edit description to textile description' do
35     visit page_with_token 'active', '/'
36     find("#projects-menu").click
37     find(".dropdown-menu a", text: "A Project").click
38     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
39       find('span', text: api_fixture('groups')['aproject']['name']).click
40       within('.arv-description-as-subtitle') do
41         find('.fa-pencil').click
42         find('.editable-input textarea').set('<p>*Textile description for A project* - "take me home":/ </p><p>And a new paragraph in description.</p>')
43         find('.editable-submit').click
44       end
45       wait_for_ajax
46     end
47
48     # visit project page
49     visit current_path
50     assert_no_text '*Textile description for A project*'
51     assert(find?('.container-fluid', text: 'Textile description for A project'),
52            "Description update did not survive page refresh")
53     assert(find?('.container-fluid', text: 'And a new paragraph in description'),
54            "Description did not contain the expected new paragraph")
55     assert(page.has_link?("take me home"), "link not found in description")
56
57     click_link 'take me home'
58
59     # now in dashboard
60     assert(page.has_text?('Active pipelines'), 'Active pipelines - not found on dashboard')
61   end
62
63   test 'Find a project and edit description to html description' do
64     visit page_with_token 'active', '/'
65     find("#projects-menu").click
66     find(".dropdown-menu a", text: "A Project").click
67     within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
68       find('span', text: api_fixture('groups')['aproject']['name']).click
69       within('.arv-description-as-subtitle') do
70         find('.fa-pencil').click
71         find('.editable-input textarea').set('<br>Textile description for A project</br> - <a href="/">take me home</a>')
72         find('.editable-submit').click
73       end
74       wait_for_ajax
75     end
76     visit current_path
77     assert(find?('.container-fluid', text: 'Textile description for A project'),
78            "Description update did not survive page refresh")
79     assert(!find?('.container-fluid', text: '<br>Textile description for A project</br>'),
80            "Textile description is displayed with uninterpreted formatting characters")
81     assert(page.has_link?("take me home"),"link not found in description")
82     click_link 'take me home'
83     assert page.has_text?('Active pipelines')
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("#projects-menu").click
89     find(".dropdown-menu a", text: "A Project").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       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("#projects-menu").click
140     find(".dropdown-menu a", text: "Home").click
141     find('.btn', text: "Add a subproject").click
142
143     within('h2') do
144       find('.fa-pencil').click
145       find('.editable-input input').set('Project 1234')
146       find('.glyphicon-ok').click
147     end
148     wait_for_ajax
149
150     visit '/projects'
151     find("#projects-menu").click
152     find(".dropdown-menu a", text: "Home").click
153     find('.btn', text: "Add a subproject").click
154     within('h2') do
155       find('.fa-pencil').click
156       find('.editable-input input').set('Project 5678')
157       find('.glyphicon-ok').click
158     end
159     wait_for_ajax
160
161     click_link 'Move project...'
162     find('.selectable', text: 'Project 1234').click
163     find('.modal-footer a,button', text: 'Move').click
164     wait_for_ajax
165
166     # Wait for the page to refresh and show the new parent in Sharing panel
167     click_link 'Sharing'
168     assert(page.has_link?("Project 1234"),
169            "Project 5678 should now be inside project 1234")
170   end
171
172   def show_project_using(auth_key, proj_key='aproject')
173     project_uuid = api_fixture('groups')[proj_key]['uuid']
174     visit(page_with_token(auth_key, "/projects/#{project_uuid}"))
175     assert(page.has_text?("A Project"), "not on expected project page")
176   end
177
178   def share_rows
179     find('#project_sharing').all('tr')
180   end
181
182   def add_share_and_check(share_type, name, obj=nil)
183     assert(page.has_no_text?(name), "project is already shared with #{name}")
184     start_share_count = share_rows.size
185     click_on("Share with #{share_type}")
186     within(".modal-container") do
187       # Order is important here: we should find something that appears in the
188       # modal before we make any assertions about what's not in the modal.
189       # Otherwise, the not-included assertions might falsely pass because
190       # the modal hasn't loaded yet.
191       find(".selectable", text: name).click
192       assert(has_no_selector?(".modal-dialog-preview-pane"),
193              "preview pane available in sharing dialog")
194       if share_type == 'users' and obj and obj['email']
195         assert(page.has_text?(obj['email']), "Did not find user's email")
196       end
197       assert_raises(Capybara::ElementNotFound,
198                     "Projects pulldown available from sharing dialog") do
199         click_on "All projects"
200       end
201       click_on "Add"
202     end
203     using_wait_time(Capybara.default_wait_time * 3) do
204       assert(page.has_link?(name),
205              "new share was not added to sharing table")
206       assert_equal(start_share_count + 1, share_rows.size,
207                    "new share did not add row to sharing table")
208     end
209   end
210
211   def modify_share_and_check(name)
212     start_rows = share_rows
213     link_row = start_rows.select { |row| row.has_text?(name) }
214     assert_equal(1, link_row.size, "row with new permission not found")
215     within(link_row.first) do
216       click_on("Read")
217       select("Write", from: "share_change_level")
218       click_on("editable-submit")
219       assert(has_link?("Write"),
220              "failed to change access level on new share")
221       click_on "Revoke"
222       if Capybara.current_driver == :selenium
223         page.driver.browser.switch_to.alert.accept
224       else
225         # poltergeist returns true for confirm(), so we don't need to accept.
226       end
227     end
228     wait_for_ajax
229     using_wait_time(Capybara.default_wait_time * 3) do
230       assert(page.has_no_text?(name),
231              "new share row still exists after being revoked")
232       assert_equal(start_rows.size - 1, share_rows.size,
233                    "revoking share did not remove row from sharing table")
234     end
235   end
236
237   test "project viewer can't see project sharing tab" do
238     show_project_using("project_viewer")
239     assert(page.has_no_link?("Sharing"),
240            "read-only project user sees sharing tab")
241   end
242
243   test "project owner can manage sharing for another user" do
244     add_user = api_fixture('users')['future_project_user']
245     new_name = ["first_name", "last_name"].map { |k| add_user[k] }.join(" ")
246
247     show_project_using("active")
248     click_on "Sharing"
249     add_share_and_check("users", new_name, add_user)
250     modify_share_and_check(new_name)
251   end
252
253   test "project owner can manage sharing for another group" do
254     new_name = api_fixture('groups')['future_project_viewing_group']['name']
255
256     show_project_using("active")
257     click_on "Sharing"
258     add_share_and_check("groups", new_name)
259     modify_share_and_check(new_name)
260   end
261
262   test "'share with group' listing does not offer projects" do
263     show_project_using("active")
264     click_on "Sharing"
265     click_on "Share with groups"
266     good_uuid = api_fixture("groups")["private"]["uuid"]
267     assert(page.has_selector?(".selectable[data-object-uuid=\"#{good_uuid}\"]"),
268            "'share with groups' listing missing owned user group")
269     bad_uuid = api_fixture("groups")["asubproject"]["uuid"]
270     assert(page.has_no_selector?(".selectable[data-object-uuid=\"#{bad_uuid}\"]"),
271            "'share with groups' listing includes project")
272   end
273
274   [
275     ['Move',api_fixture('collections')['collection_to_move_around_in_aproject'],
276       api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
277     ['Remove',api_fixture('collections')['collection_to_move_around_in_aproject'],
278       api_fixture('groups')['aproject']],
279     ['Copy',api_fixture('collections')['collection_to_move_around_in_aproject'],
280       api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
281     ['Remove',api_fixture('collections')['collection_in_aproject_with_same_name_as_in_home_project'],
282       api_fixture('groups')['aproject'],nil,true],
283   ].each do |action, my_collection, src, dest=nil, expect_name_change=nil|
284     test "selection #{action} -> #{expect_name_change.inspect} for project" do
285       perform_selection_action src, dest, my_collection, action
286
287       case action
288       when 'Copy'
289         assert page.has_text?(my_collection['name']), 'Collection not found in src project after copy'
290         visit page_with_token 'active', '/'
291         find("#projects-menu").click
292         find(".dropdown-menu a", text: dest['name']).click
293         assert page.has_text?(my_collection['name']), 'Collection not found in dest project after copy'
294
295       when 'Move'
296         assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after move'
297         visit page_with_token 'active', '/'
298         find("#projects-menu").click
299         find(".dropdown-menu a", text: dest['name']).click
300         assert page.has_text?(my_collection['name']), 'Collection not found in dest project after move'
301
302       when 'Remove'
303         assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after remove'
304         visit page_with_token 'active', '/'
305         find("#projects-menu").click
306         find(".dropdown-menu a", text: "Home").click
307         assert page.has_text?(my_collection['name']), 'Collection not found in home project after remove'
308         if expect_name_change
309           assert page.has_text?(my_collection['name']+' removed from ' + src['name']),
310             'Collection with update name is not found in home project after remove'
311         end
312       end
313     end
314   end
315
316   def perform_selection_action src, dest, item, action
317     visit page_with_token 'active', '/'
318     find("#projects-menu").click
319     find(".dropdown-menu a", text: src['name']).click
320     assert page.has_text?(item['name']), 'Collection not found in src project'
321
322     within('tr', text: item['name']) do
323       find('input[type=checkbox]').click
324     end
325
326     click_button 'Selection'
327
328     within('.selection-action-container') do
329       assert page.has_text?("Compare selected"), "Compare selected link text not found"
330       assert page.has_link?("Copy selected"), "Copy selected link not found"
331       assert page.has_link?("Move selected"), "Move selected link not found"
332       assert page.has_link?("Remove selected"), "Remove selected link not found"
333
334       click_link "#{action} selected"
335     end
336
337     # select the destination project if a Copy or Move action is being performed
338     if action == 'Copy' || action == 'Move'
339       within(".modal-container") do
340         find('.selectable', text: dest['name']).click
341         find('.modal-footer a,button', text: action).click
342         wait_for_ajax
343       end
344     end
345   end
346
347   # Test copy action state. It should not be available when a subproject is selected.
348   test "copy action is disabled when a subproject is selected" do
349     my_project = api_fixture('groups')['aproject']
350     my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
351     my_subproject = api_fixture('groups')['asubproject']
352
353     # verify that selection options are disabled on the project until an item is selected
354     visit page_with_token 'active', '/'
355     find("#projects-menu").click
356     find(".dropdown-menu a", text: my_project['name']).click
357
358     click_button 'Selection'
359     within('.selection-action-container') do
360       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
361       assert_selector 'li.disabled', text: 'Compare selected'
362       assert_selector 'li.disabled', text: 'Copy selected'
363       assert_selector 'li.disabled', text: 'Move selected'
364       assert_selector 'li.disabled', text: 'Remove selected'
365     end
366
367     # select collection and verify links are enabled
368     visit page_with_token 'active', '/'
369     find("#projects-menu").click
370     find(".dropdown-menu a", text: my_project['name']).click
371     assert page.has_text?(my_collection['name']), 'Collection not found in project'
372
373     within('tr', text: my_collection['name']) do
374       find('input[type=checkbox]').click
375     end
376
377     click_button 'Selection'
378     within('.selection-action-container') do
379       assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
380       assert_selector 'li', text: 'Create new collection with selected collections'
381       assert_selector 'li.disabled', text: 'Compare selected'
382       assert_no_selector 'li.disabled', text: 'Copy selected'
383       assert_selector 'li', text: 'Copy selected'
384       assert_no_selector 'li.disabled', text: 'Move selected'
385       assert_selector 'li', text: 'Move selected'
386       assert_no_selector 'li.disabled', text: 'Remove selected'
387       assert_selector 'li', text: 'Remove selected'
388     end
389
390     # select subproject and verify that copy action is disabled
391     visit page_with_token 'active', '/'
392     find("#projects-menu").click
393     find(".dropdown-menu a", text: my_project['name']).click
394
395     click_link 'Subprojects'
396     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
397
398     within('tr', text: my_subproject['name']) do
399       find('input[type=checkbox]').click
400     end
401
402     click_button 'Selection'
403     within('.selection-action-container') do
404       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
405       assert_selector 'li.disabled', text: 'Compare selected'
406       assert_selector 'li.disabled', text: 'Copy selected'
407       assert_no_selector 'li.disabled', text: 'Move selected'
408       assert_selector 'li', text: 'Move selected'
409       assert_no_selector 'li.disabled', text: 'Remove selected'
410       assert_selector 'li', text: 'Remove selected'
411     end
412
413     # select subproject and a collection and verify that copy action is still disabled
414     visit page_with_token 'active', '/'
415     find("#projects-menu").click
416     find(".dropdown-menu a", text: my_project['name']).click
417
418     click_link 'Subprojects'
419     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
420
421     within('tr', text: my_subproject['name']) do
422       find('input[type=checkbox]').click
423     end
424
425     click_link 'Data collections'
426     assert page.has_text?(my_collection['name']), 'Collection not found in project'
427
428     within('tr', text: my_collection['name']) do
429       find('input[type=checkbox]').click
430     end
431
432     click_link 'Subprojects'
433     click_button 'Selection'
434     within('.selection-action-container') do
435       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
436       assert_selector 'li.disabled', text: 'Compare selected'
437       assert_selector 'li.disabled', text: 'Copy selected'
438       assert_no_selector 'li.disabled', text: 'Move selected'
439       assert_selector 'li', text: 'Move selected'
440       assert_no_selector 'li.disabled', text: 'Remove selected'
441       assert_selector 'li', text: 'Remove selected'
442     end
443   end
444
445   # When project tabs are switched, only options applicable to the current tab's selections are enabled.
446   test "verify selection options when tabs are switched" do
447     my_project = api_fixture('groups')['aproject']
448     my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
449     my_subproject = api_fixture('groups')['asubproject']
450
451     # select subproject and a collection and verify that copy action is still disabled
452     visit page_with_token 'active', '/'
453     find("#projects-menu").click
454     find(".dropdown-menu a", text: my_project['name']).click
455
456     # Select a sub-project
457     click_link 'Subprojects'
458     assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
459
460     within('tr', text: my_subproject['name']) do
461       find('input[type=checkbox]').click
462     end
463
464     # Select a collection
465     click_link 'Data collections'
466     assert page.has_text?(my_collection['name']), 'Collection not found in project'
467
468     within('tr', text: my_collection['name']) do
469       find('input[type=checkbox]').click
470     end
471
472     # Go back to Subprojects tab
473     click_link 'Subprojects'
474     click_button 'Selection'
475     within('.selection-action-container') do
476       assert_selector 'li.disabled', text: 'Create new collection with selected collections'
477       assert_selector 'li.disabled', text: 'Compare selected'
478       assert_selector 'li.disabled', text: 'Copy selected'
479       assert_no_selector 'li.disabled', text: 'Move selected'
480       assert_selector 'li', text: 'Move selected'
481       assert_no_selector 'li.disabled', text: 'Remove selected'
482       assert_selector 'li', text: 'Remove selected'
483     end
484
485     # Close the dropdown by clicking outside it.
486     find('.dropdown-toggle', text: 'Selection').find(:xpath, '..').click
487
488     # Go back to Data collections tab
489     find('.nav-tabs a', text: 'Data collections').click
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     need_selenium 'to land on specified tab using {url}#Advanced'
752     project = api_fixture("groups", "aproject")
753     visit(page_with_token("active_trustedclient",
754                           "/projects/#{project['uuid']}#Advanced"))
755     assert_text("API response")
756     find("#page-wrapper .nav-tabs :first-child a").click
757     assert_text("bytes Collection")
758   end
759 end