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