1 require 'integration_helper'
2 require 'helpers/share_object_helper'
4 class ProjectsTest < ActionDispatch::IntegrationTest
5 include ShareObjectHelper
11 test 'Check collection count for A Project in the tab pane titles' do
12 project_uuid = api_fixture('groups')['aproject']['uuid']
13 visit page_with_token 'active', '/projects/' + project_uuid
15 collection_count = page.all("[data-pk*='collection']").count
16 assert_selector '#Data_collections-tab span', text: "(#{collection_count})"
19 test 'Find a project and edit its description' do
20 visit page_with_token 'active', '/'
21 find("#projects-menu").click
22 find(".dropdown-menu a", text: "A Project").click
23 within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
24 find('span', text: api_fixture('groups')['aproject']['name']).click
25 within('.arv-description-as-subtitle') do
26 find('.fa-pencil').click
27 find('.editable-input textarea').set('I just edited this.')
28 find('.editable-submit').click
33 assert(find?('.container-fluid', text: 'I just edited this.'),
34 "Description update did not survive page refresh")
37 test 'Find a project and edit description to textile description' do
38 visit page_with_token 'active', '/'
39 find("#projects-menu").click
40 find(".dropdown-menu a", text: "A Project").click
41 within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
42 find('span', text: api_fixture('groups')['aproject']['name']).click
43 within('.arv-description-as-subtitle') do
44 find('.fa-pencil').click
45 find('.editable-input textarea').set('<p>*Textile description for A project* - "take me home":/ </p><p>And a new paragraph in description.</p>')
46 find('.editable-submit').click
53 assert_no_text '*Textile description for A project*'
54 assert(find?('.container-fluid', text: 'Textile description for A project'),
55 "Description update did not survive page refresh")
56 assert(find?('.container-fluid', text: 'And a new paragraph in description'),
57 "Description did not contain the expected new paragraph")
58 assert(page.has_link?("take me home"), "link not found in description")
60 click_link 'take me home'
63 assert(page.has_text?('Active pipelines'), 'Active pipelines - not found on dashboard')
66 test 'Find a project and edit description to html description' do
67 visit page_with_token 'active', '/'
68 find("#projects-menu").click
69 find(".dropdown-menu a", text: "A Project").click
70 within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
71 find('span', text: api_fixture('groups')['aproject']['name']).click
72 within('.arv-description-as-subtitle') do
73 find('.fa-pencil').click
74 find('.editable-input textarea').set('<br>Textile description for A project</br> - <a href="/">take me home</a>')
75 find('.editable-submit').click
80 assert(find?('.container-fluid', text: 'Textile description for A project'),
81 "Description update did not survive page refresh")
82 assert(!find?('.container-fluid', text: '<br>Textile description for A project</br>'),
83 "Textile description is displayed with uninterpreted formatting characters")
84 assert(page.has_link?("take me home"),"link not found in description")
85 click_link 'take me home'
86 assert page.has_text?('Active pipelines')
89 test 'Find a project and edit description to textile description with link to object' do
90 visit page_with_token 'active', '/'
91 find("#projects-menu").click
92 find(".dropdown-menu a", text: "A Project").click
93 within('.container-fluid', text: api_fixture('groups')['aproject']['name']) do
94 find('span', text: api_fixture('groups')['aproject']['name']).click
95 within('.arv-description-as-subtitle') do
96 find('.fa-pencil').click
97 find('.editable-input textarea').set('*Textile description for A project* - "go to sub-project":' + api_fixture('groups')['asubproject']['uuid'] + "'")
98 find('.editable-submit').click
103 assert(find?('.container-fluid', text: 'Textile description for A project'),
104 "Description update did not survive page refresh")
105 assert(!find?('.container-fluid', text: '*Textile description for A project*'),
106 "Textile description is displayed with uninterpreted formatting characters")
107 assert(page.has_link?("go to sub-project"), "link not found in description")
108 click_link 'go to sub-project'
109 assert(page.has_text?(api_fixture('groups')['asubproject']['name']), 'sub-project name not found after clicking link')
112 test 'Add a new name, then edit it, without creating a duplicate' do
113 project_uuid = api_fixture('groups')['aproject']['uuid']
114 specimen_uuid = api_fixture('traits')['owned_by_aproject_with_no_name']['uuid']
115 visit page_with_token 'active', '/projects/' + project_uuid
116 click_link 'Other objects'
117 within '.selection-action-container' do
118 # Wait for the tab to load:
119 assert_selector 'tr[data-kind="arvados#trait"]'
120 within first('tr', text: 'Trait') do
121 find(".fa-pencil").click
122 find('.editable-input input').set('Now I have a name.')
123 find('.glyphicon-ok').click
124 assert_selector '.editable', text: 'Now I have a name.'
125 find(".fa-pencil").click
126 find('.editable-input input').set('Now I have a new name.')
127 find('.glyphicon-ok').click
130 assert_selector '.editable', text: 'Now I have a new name.'
133 click_link 'Other objects'
134 within '.selection-action-container' do
135 find '.editable', text: 'Now I have a new name.'
136 assert_no_selector '.editable', text: 'Now I have a name.'
140 test 'Create a project and move it into a different project' do
141 visit page_with_token 'active', '/projects'
142 find("#projects-menu").click
143 find(".dropdown-menu a", text: "Home").click
144 find('.btn', text: "Add a subproject").click
147 find('.fa-pencil').click
148 find('.editable-input input').set('Project 1234')
149 find('.glyphicon-ok').click
154 find("#projects-menu").click
155 find(".dropdown-menu a", text: "Home").click
156 find('.btn', text: "Add a subproject").click
158 find('.fa-pencil').click
159 find('.editable-input input').set('Project 5678')
160 find('.glyphicon-ok').click
164 click_link 'Move project...'
165 find('.selectable', text: 'Project 1234').click
166 find('.modal-footer a,button', text: 'Move').click
169 # Wait for the page to refresh and show the new parent in Sharing panel
171 assert(page.has_link?("Project 1234"),
172 "Project 5678 should now be inside project 1234")
175 test "project viewer can't see project sharing tab" do
176 show_object_using('project_viewer', 'groups', 'aproject', 'A Project')
177 assert(page.has_no_link?("Sharing"),
178 "read-only project user sees sharing tab")
181 test "project owner can manage sharing for another user" do
182 add_user = api_fixture('users')['future_project_user']
183 new_name = ["first_name", "last_name"].map { |k| add_user[k] }.join(" ")
185 show_object_using('active', 'groups', 'aproject', 'A Project')
187 add_share_and_check("users", new_name, add_user)
188 modify_share_and_check(new_name)
191 test "project owner can manage sharing for another group" do
192 new_name = api_fixture('groups')['future_project_viewing_group']['name']
194 show_object_using('active', 'groups', 'aproject', 'A Project')
196 add_share_and_check("groups", new_name)
197 modify_share_and_check(new_name)
200 test "'share with group' listing does not offer projects" do
201 show_object_using('active', 'groups', 'aproject', 'A Project')
203 click_on "Share with groups"
204 good_uuid = api_fixture("groups")["private"]["uuid"]
205 assert(page.has_selector?(".selectable[data-object-uuid=\"#{good_uuid}\"]"),
206 "'share with groups' listing missing owned user group")
207 bad_uuid = api_fixture("groups")["asubproject"]["uuid"]
208 assert(page.has_no_selector?(".selectable[data-object-uuid=\"#{bad_uuid}\"]"),
209 "'share with groups' listing includes project")
213 ['Move',api_fixture('collections')['collection_to_move_around_in_aproject'],
214 api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
215 ['Remove',api_fixture('collections')['collection_to_move_around_in_aproject'],
216 api_fixture('groups')['aproject']],
217 ['Copy',api_fixture('collections')['collection_to_move_around_in_aproject'],
218 api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
219 ['Remove',api_fixture('collections')['collection_in_aproject_with_same_name_as_in_home_project'],
220 api_fixture('groups')['aproject'],nil,true],
221 ].each do |action, my_collection, src, dest=nil, expect_name_change=nil|
222 test "selection #{action} -> #{expect_name_change.inspect} for project" do
223 perform_selection_action src, dest, my_collection, action
227 assert page.has_text?(my_collection['name']), 'Collection not found in src project after copy'
228 visit page_with_token 'active', '/'
229 find("#projects-menu").click
230 find(".dropdown-menu a", text: dest['name']).click
231 assert page.has_text?(my_collection['name']), 'Collection not found in dest project after copy'
234 assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after move'
235 visit page_with_token 'active', '/'
236 find("#projects-menu").click
237 find(".dropdown-menu a", text: dest['name']).click
238 assert page.has_text?(my_collection['name']), 'Collection not found in dest project after move'
241 assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after remove'
242 visit page_with_token 'active', '/'
243 find("#projects-menu").click
244 find(".dropdown-menu a", text: "Home").click
245 assert page.has_text?(my_collection['name']), 'Collection not found in home project after remove'
246 if expect_name_change
247 assert page.has_text?(my_collection['name']+' removed from ' + src['name']),
248 'Collection with update name is not found in home project after remove'
254 def perform_selection_action src, dest, item, action
255 visit page_with_token 'active', '/'
256 find("#projects-menu").click
257 find(".dropdown-menu a", text: src['name']).click
258 assert page.has_text?(item['name']), 'Collection not found in src project'
260 within('tr', text: item['name']) do
261 find('input[type=checkbox]').click
264 click_button 'Selection'
266 within('.selection-action-container') do
267 assert page.has_text?("Compare selected"), "Compare selected link text not found"
268 assert page.has_link?("Copy selected"), "Copy selected link not found"
269 assert page.has_link?("Move selected"), "Move selected link not found"
270 assert page.has_link?("Remove selected"), "Remove selected link not found"
272 click_link "#{action} selected"
275 # select the destination project if a Copy or Move action is being performed
276 if action == 'Copy' || action == 'Move'
277 within(".modal-container") do
278 find('.selectable', text: dest['name']).click
279 find('.modal-footer a,button', text: action).click
285 # Test copy action state. It should not be available when a subproject is selected.
286 test "copy action is disabled when a subproject is selected" do
287 my_project = api_fixture('groups')['aproject']
288 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
289 my_subproject = api_fixture('groups')['asubproject']
291 # verify that selection options are disabled on the project until an item is selected
292 visit page_with_token 'active', '/'
293 find("#projects-menu").click
294 find(".dropdown-menu a", text: my_project['name']).click
296 click_button 'Selection'
297 within('.selection-action-container') do
298 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
299 assert_selector 'li.disabled', text: 'Compare selected'
300 assert_selector 'li.disabled', text: 'Copy selected'
301 assert_selector 'li.disabled', text: 'Move selected'
302 assert_selector 'li.disabled', text: 'Remove selected'
305 # select collection and verify links are enabled
306 visit page_with_token 'active', '/'
307 find("#projects-menu").click
308 find(".dropdown-menu a", text: my_project['name']).click
309 assert page.has_text?(my_collection['name']), 'Collection not found in project'
311 within('tr', text: my_collection['name']) do
312 find('input[type=checkbox]').click
315 click_button 'Selection'
316 within('.selection-action-container') do
317 assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
318 assert_selector 'li', text: 'Create new collection with selected collections'
319 assert_selector 'li.disabled', text: 'Compare selected'
320 assert_no_selector 'li.disabled', text: 'Copy selected'
321 assert_selector 'li', text: 'Copy selected'
322 assert_no_selector 'li.disabled', text: 'Move selected'
323 assert_selector 'li', text: 'Move selected'
324 assert_no_selector 'li.disabled', text: 'Remove selected'
325 assert_selector 'li', text: 'Remove selected'
328 # select subproject and verify that copy action is disabled
329 visit page_with_token 'active', '/'
330 find("#projects-menu").click
331 find(".dropdown-menu a", text: my_project['name']).click
333 click_link 'Subprojects'
334 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
336 within('tr', text: my_subproject['name']) do
337 find('input[type=checkbox]').click
340 click_button 'Selection'
341 within('.selection-action-container') do
342 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
343 assert_selector 'li.disabled', text: 'Compare selected'
344 assert_selector 'li.disabled', text: 'Copy selected'
345 assert_no_selector 'li.disabled', text: 'Move selected'
346 assert_selector 'li', text: 'Move selected'
347 assert_no_selector 'li.disabled', text: 'Remove selected'
348 assert_selector 'li', text: 'Remove selected'
351 # select subproject and a collection and verify that copy action is still disabled
352 visit page_with_token 'active', '/'
353 find("#projects-menu").click
354 find(".dropdown-menu a", text: my_project['name']).click
356 click_link 'Subprojects'
357 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
359 within('tr', text: my_subproject['name']) do
360 find('input[type=checkbox]').click
363 click_link 'Data collections'
364 assert page.has_text?(my_collection['name']), 'Collection not found in project'
366 within('tr', text: my_collection['name']) do
367 find('input[type=checkbox]').click
370 click_link 'Subprojects'
371 click_button 'Selection'
372 within('.selection-action-container') do
373 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
374 assert_selector 'li.disabled', text: 'Compare selected'
375 assert_selector 'li.disabled', text: 'Copy selected'
376 assert_no_selector 'li.disabled', text: 'Move selected'
377 assert_selector 'li', text: 'Move selected'
378 assert_no_selector 'li.disabled', text: 'Remove selected'
379 assert_selector 'li', text: 'Remove selected'
383 # When project tabs are switched, only options applicable to the current tab's selections are enabled.
384 test "verify selection options when tabs are switched" do
385 my_project = api_fixture('groups')['aproject']
386 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
387 my_subproject = api_fixture('groups')['asubproject']
389 # select subproject and a collection and verify that copy action is still disabled
390 visit page_with_token 'active', '/'
391 find("#projects-menu").click
392 find(".dropdown-menu a", text: my_project['name']).click
394 # Select a sub-project
395 click_link 'Subprojects'
396 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
398 within('tr', text: my_subproject['name']) do
399 find('input[type=checkbox]').click
402 # Select a collection
403 click_link 'Data collections'
404 assert page.has_text?(my_collection['name']), 'Collection not found in project'
406 within('tr', text: my_collection['name']) do
407 find('input[type=checkbox]').click
410 # Go back to Subprojects tab
411 click_link 'Subprojects'
412 click_button 'Selection'
413 within('.selection-action-container') do
414 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
415 assert_selector 'li.disabled', text: 'Compare selected'
416 assert_selector 'li.disabled', text: 'Copy selected'
417 assert_no_selector 'li.disabled', text: 'Move selected'
418 assert_selector 'li', text: 'Move selected'
419 assert_no_selector 'li.disabled', text: 'Remove selected'
420 assert_selector 'li', text: 'Remove selected'
423 # Close the dropdown by clicking outside it.
424 find('.dropdown-toggle', text: 'Selection').find(:xpath, '..').click
426 # Go back to Data collections tab
427 find('.nav-tabs a', text: 'Data collections').click
428 click_button 'Selection'
429 within('.selection-action-container') do
430 assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
431 assert_selector 'li', text: 'Create new collection with selected collections'
432 assert_selector 'li.disabled', text: 'Compare selected'
433 assert_no_selector 'li.disabled', text: 'Copy selected'
434 assert_selector 'li', text: 'Copy selected'
435 assert_no_selector 'li.disabled', text: 'Move selected'
436 assert_selector 'li', text: 'Move selected'
437 assert_no_selector 'li.disabled', text: 'Remove selected'
438 assert_selector 'li', text: 'Remove selected'
442 # "Move selected" and "Remove selected" options should not be available when current user cannot write to the project
443 test "move selected and remove selected actions not available when current user cannot write to project" do
444 my_project = api_fixture('groups')['anonymously_accessible_project']
445 visit page_with_token 'active', "/projects/#{my_project['uuid']}"
447 click_button 'Selection'
448 within('.selection-action-container') do
449 assert_selector 'li', text: 'Create new collection with selected collections'
450 assert_selector 'li', text: 'Compare selected'
451 assert_selector 'li', text: 'Copy selected'
452 assert_no_selector 'li', text: 'Move selected'
453 assert_no_selector 'li', text: 'Remove selected'
459 ['project_viewer', false],
460 ].each do |user, expect_collection_in_aproject|
461 test "combine selected collections into new collection #{user} #{expect_collection_in_aproject}" do
462 my_project = api_fixture('groups')['aproject']
463 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
465 visit page_with_token user, '/'
466 find("#projects-menu").click
467 find(".dropdown-menu a", text: my_project['name']).click
468 assert page.has_text?(my_collection['name']), 'Collection not found in project'
470 within('tr', text: my_collection['name']) do
471 find('input[type=checkbox]').click
474 click_button 'Selection'
475 within('.selection-action-container') do
476 click_link 'Create new collection with selected collections'
479 # now in the new collection page
480 if expect_collection_in_aproject
481 assert page.has_text?("Created new collection in the project #{my_project['name']}"),
482 'Not found flash message that new collection is created in aproject'
484 assert page.has_text?("Created new collection in your Home project"),
485 'Not found flash message that new collection is created in Home project'
487 assert page.has_text?('Content hash'), 'Not found content hash in collection page'
493 ["pipelines", "/pipeline_instances"],
494 ["collections", "/collections"]
495 ].each do |target,path|
496 test "Test dashboard button all #{target}" do
497 visit page_with_token 'active', '/'
498 click_link "All #{target}"
499 assert_equal path, current_path
503 def scroll_setup(project_name,
507 sort_parameters = nil)
508 project_uuid = api_fixture('groups')[project_name]['uuid']
509 visit page_with_token 'user1_with_load', '/projects/' + project_uuid
511 assert(page.has_text?("#{item_list_parameter.humanize} (#{total_nbr_items})"), "Number of #{item_list_parameter.humanize} did not match the input amount")
513 click_link item_list_parameter.humanize
517 find("th[data-sort-order='#{sort_parameters.gsub(/\s/,'')}']").click
522 def scroll_items_check(nbr_items,
528 for i in 1..nbr_items
529 items << "#{fixture_prefix}#{i}"
532 verify_items = items.dup
533 unexpected_items = []
535 within(".arv-project-#{item_list_parameter}") do
536 page.execute_script "window.scrollBy(0,999000)"
542 # Visit all rows. If not all expected items are found, retry
543 found_items = page.all(item_selector)
544 item_count = found_items.count
547 (0..item_count-1).each do |i|
548 # Found row text using the fixture string e.g. "Show Collection_#{n} "
549 item_name = found_items[i].text.split[1]
550 if !items.include? item_name
551 unexpected_items << item_name
553 verify_items.delete item_name
557 assert_operator( previous.downcase, :<=, item_name.downcase) if previous
562 assert_equal true, unexpected_items.empty?, "Found unexpected #{item_list_parameter.humanize} #{unexpected_items.inspect}"
563 assert_equal nbr_items, item_count, "Found different number of #{item_list_parameter.humanize}"
564 assert_equal true, verify_items.empty?, "Did not find all the #{item_list_parameter.humanize}"
569 ['project_with_10_collections', 10],
570 ['project_with_201_collections', 201], # two pages of data
571 ].each do |project_name, nbr_items|
572 test "scroll collections tab for #{project_name} with #{nbr_items} objects" do
573 item_list_parameter = "Data_collections"
574 scroll_setup project_name,
577 scroll_items_check nbr_items,
580 'tr[data-kind="arvados#collection"]'
585 ['project_with_10_collections', 10],
586 ['project_with_201_collections', 201], # two pages of data
587 ].each do |project_name, nbr_items|
588 test "scroll collections tab for #{project_name} with #{nbr_items} objects with ascending sort (case insensitive)" do
589 item_list_parameter = "Data_collections"
590 scroll_setup project_name,
595 scroll_items_check nbr_items,
598 'tr[data-kind="arvados#collection"]',
604 ['project_with_10_pipelines', 10, 0],
605 ['project_with_2_pipelines_and_60_jobs', 2, 60],
606 ['project_with_25_pipelines', 25, 0],
607 ].each do |project_name, num_pipelines, num_jobs|
608 test "scroll pipeline instances tab for #{project_name} with #{num_pipelines} pipelines and #{num_jobs} jobs" do
609 item_list_parameter = "Jobs_and_pipelines"
610 scroll_setup project_name,
611 num_pipelines + num_jobs,
613 # check the general scrolling and the pipelines
614 scroll_items_check num_pipelines,
617 'tr[data-kind="arvados#pipelineInstance"]'
618 # Check job count separately
619 jobs_found = page.all('tr[data-kind="arvados#job"]')
620 found_job_count = jobs_found.count
621 assert_equal num_jobs, found_job_count, 'Did not find expected number of jobs'
625 # Move button accessibility
628 ['active', true], # project owner
629 ['project_viewer', false],
630 ].each do |user, can_move|
631 test "#{user} can move subproject under another user's Home #{can_move}" do
632 project = api_fixture('groups')['aproject']
633 collection = api_fixture('collections')['collection_to_move_around_in_aproject']
635 # verify the project move button
636 visit page_with_token user, "/projects/#{project['uuid']}"
638 assert page.has_link? 'Move project...'
640 assert page.has_no_link? 'Move project...'
645 test "error while loading tab" do
646 original_arvados_v1_base = Rails.configuration.arvados_v1_base
648 visit page_with_token 'active', '/projects/' + api_fixture('groups')['aproject']['uuid']
650 # Point to a bad api server url to generate error
651 Rails.configuration.arvados_v1_base = "https://[100::f]:1/"
652 click_link 'Other objects'
653 within '#Other_objects' do
655 assert_selector('a', text: 'Reload tab')
657 # Now point back to the orig api server and reload tab
658 Rails.configuration.arvados_v1_base = original_arvados_v1_base
659 click_link 'Reload tab'
660 assert_no_selector('a', text: 'Reload tab')
661 assert_selector('button', text: 'Selection')
662 within '.selection-action-container' do
663 assert_selector 'tr[data-kind="arvados#trait"]'
668 test "add new project using projects dropdown" do
669 # verify that selection options are disabled on the project until an item is selected
670 visit page_with_token 'active', '/'
673 find("#projects-menu").click
674 click_link 'Add a new project'
675 assert_text 'New project'
676 assert_text 'No description provided'
678 # Add one more new project
679 find("#projects-menu").click
680 click_link 'Add a new project'
681 match = /New project \(\d\)/.match page.text
682 assert match, 'Expected project name not found'
683 assert_text 'No description provided'
686 test "first tab loads data when visiting other tab directly" do
687 # As of 2014-12-19, the first tab of project#show uses infinite scrolling.
688 # Make sure that it loads data even if we visit another tab directly.
689 need_selenium 'to land on specified tab using {url}#Advanced'
690 project = api_fixture("groups", "aproject")
691 visit(page_with_token("active_trustedclient",
692 "/projects/#{project['uuid']}#Advanced"))
693 assert_text("API response")
694 find("#page-wrapper .nav-tabs :first-child a").click
695 assert_text("bytes Collection")