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 def open_groups_sharing(project_name="aproject", token_name="active")
176 project = api_fixture("groups", project_name)
177 visit(page_with_token(token_name, "/projects/#{project['uuid']}"))
179 click_on "Share with groups"
182 def group_name(group_key)
183 api_fixture("groups", group_key, "name")
186 test "projects not publicly sharable when anonymous browsing disabled" do
187 Rails.configuration.anonymous_user_token = false
189 # Check for a group we do expect first, to make sure the modal's loaded.
190 assert_selector(".modal-container .selectable",
191 text: group_name("all_users"))
192 assert_no_selector(".modal-container .selectable",
193 text: group_name("anonymous_group"))
196 test "projects publicly sharable when anonymous browsing enabled" do
197 Rails.configuration.anonymous_user_token = "testonlytoken"
199 assert_selector(".modal-container .selectable",
200 text: group_name("anonymous_group"))
203 test "project viewer can't see project sharing tab" do
204 show_object_using('project_viewer', 'groups', 'aproject', 'A Project')
205 assert(page.has_no_link?("Sharing"),
206 "read-only project user sees sharing tab")
209 test "project owner can manage sharing for another user" do
210 add_user = api_fixture('users')['future_project_user']
211 new_name = ["first_name", "last_name"].map { |k| add_user[k] }.join(" ")
213 show_object_using('active', 'groups', 'aproject', 'A Project')
215 add_share_and_check("users", new_name, add_user)
216 modify_share_and_check(new_name)
219 test "project owner can manage sharing for another group" do
220 new_name = api_fixture('groups')['future_project_viewing_group']['name']
222 show_object_using('active', 'groups', 'aproject', 'A Project')
224 add_share_and_check("groups", new_name)
225 modify_share_and_check(new_name)
228 test "'share with group' listing does not offer projects" do
229 show_object_using('active', 'groups', 'aproject', 'A Project')
231 click_on "Share with groups"
232 good_uuid = api_fixture("groups")["private"]["uuid"]
233 assert(page.has_selector?(".selectable[data-object-uuid=\"#{good_uuid}\"]"),
234 "'share with groups' listing missing owned user group")
235 bad_uuid = api_fixture("groups")["asubproject"]["uuid"]
236 assert(page.has_no_selector?(".selectable[data-object-uuid=\"#{bad_uuid}\"]"),
237 "'share with groups' listing includes project")
241 ['Move',api_fixture('collections')['collection_to_move_around_in_aproject'],
242 api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
243 ['Remove',api_fixture('collections')['collection_to_move_around_in_aproject'],
244 api_fixture('groups')['aproject']],
245 ['Copy',api_fixture('collections')['collection_to_move_around_in_aproject'],
246 api_fixture('groups')['aproject'],api_fixture('groups')['asubproject']],
247 ['Remove',api_fixture('collections')['collection_in_aproject_with_same_name_as_in_home_project'],
248 api_fixture('groups')['aproject'],nil,true],
249 ].each do |action, my_collection, src, dest=nil, expect_name_change=nil|
250 test "selection #{action} -> #{expect_name_change.inspect} for project" do
251 perform_selection_action src, dest, my_collection, action
255 assert page.has_text?(my_collection['name']), 'Collection not found in src project after copy'
256 visit page_with_token 'active', '/'
257 find("#projects-menu").click
258 find(".dropdown-menu a", text: dest['name']).click
259 assert page.has_text?(my_collection['name']), 'Collection not found in dest project after copy'
262 assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after move'
263 visit page_with_token 'active', '/'
264 find("#projects-menu").click
265 find(".dropdown-menu a", text: dest['name']).click
266 assert page.has_text?(my_collection['name']), 'Collection not found in dest project after move'
269 assert page.has_no_text?(my_collection['name']), 'Collection still found in src project after remove'
274 def perform_selection_action src, dest, item, action
275 visit page_with_token 'active', '/'
276 find("#projects-menu").click
277 find(".dropdown-menu a", text: src['name']).click
278 assert page.has_text?(item['name']), 'Collection not found in src project'
280 within('tr', text: item['name']) do
281 find('input[type=checkbox]').click
284 click_button 'Selection'
286 within('.selection-action-container') do
287 assert page.has_text?("Compare selected"), "Compare selected link text not found"
288 assert page.has_link?("Copy selected"), "Copy selected link not found"
289 assert page.has_link?("Move selected"), "Move selected link not found"
290 assert page.has_link?("Remove selected"), "Remove selected link not found"
292 click_link "#{action} selected"
295 # select the destination project if a Copy or Move action is being performed
296 if action == 'Copy' || action == 'Move'
297 within(".modal-container") do
298 find('.selectable', text: dest['name']).click
299 find('.modal-footer a,button', text: action).click
305 # Test copy action state. It should not be available when a subproject is selected.
306 test "copy action is disabled when a subproject is selected" do
307 my_project = api_fixture('groups')['aproject']
308 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
309 my_subproject = api_fixture('groups')['asubproject']
311 # verify that selection options are disabled on the project until an item is selected
312 visit page_with_token 'active', '/'
313 find("#projects-menu").click
314 find(".dropdown-menu a", text: my_project['name']).click
316 click_button 'Selection'
317 within('.selection-action-container') do
318 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
319 assert_selector 'li.disabled', text: 'Compare selected'
320 assert_selector 'li.disabled', text: 'Copy selected'
321 assert_selector 'li.disabled', text: 'Move selected'
322 assert_selector 'li.disabled', text: 'Remove selected'
325 # select collection and verify links are enabled
326 visit page_with_token 'active', '/'
327 find("#projects-menu").click
328 find(".dropdown-menu a", text: my_project['name']).click
329 assert page.has_text?(my_collection['name']), 'Collection not found in project'
331 within('tr', text: my_collection['name']) do
332 find('input[type=checkbox]').click
335 click_button 'Selection'
336 within('.selection-action-container') do
337 assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
338 assert_selector 'li', text: 'Create new collection with selected collections'
339 assert_selector 'li.disabled', text: 'Compare selected'
340 assert_no_selector 'li.disabled', text: 'Copy selected'
341 assert_selector 'li', text: 'Copy selected'
342 assert_no_selector 'li.disabled', text: 'Move selected'
343 assert_selector 'li', text: 'Move selected'
344 assert_no_selector 'li.disabled', text: 'Remove selected'
345 assert_selector 'li', text: 'Remove selected'
348 # select subproject and verify that copy action is disabled
349 visit page_with_token 'active', '/'
350 find("#projects-menu").click
351 find(".dropdown-menu a", text: my_project['name']).click
353 click_link 'Subprojects'
354 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
356 within('tr', text: my_subproject['name']) do
357 find('input[type=checkbox]').click
360 click_button 'Selection'
361 within('.selection-action-container') do
362 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
363 assert_selector 'li.disabled', text: 'Compare selected'
364 assert_selector 'li.disabled', text: 'Copy selected'
365 assert_no_selector 'li.disabled', text: 'Move selected'
366 assert_selector 'li', text: 'Move selected'
367 assert_no_selector 'li.disabled', text: 'Remove selected'
368 assert_selector 'li', text: 'Remove selected'
371 # select subproject and a collection and verify that copy action is still disabled
372 visit page_with_token 'active', '/'
373 find("#projects-menu").click
374 find(".dropdown-menu a", text: my_project['name']).click
376 click_link 'Subprojects'
377 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
379 within('tr', text: my_subproject['name']) do
380 find('input[type=checkbox]').click
383 click_link 'Data collections'
384 assert page.has_text?(my_collection['name']), 'Collection not found in project'
386 within('tr', text: my_collection['name']) do
387 find('input[type=checkbox]').click
390 click_link 'Subprojects'
391 click_button 'Selection'
392 within('.selection-action-container') do
393 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
394 assert_selector 'li.disabled', text: 'Compare selected'
395 assert_selector 'li.disabled', text: 'Copy selected'
396 assert_no_selector 'li.disabled', text: 'Move selected'
397 assert_selector 'li', text: 'Move selected'
398 assert_no_selector 'li.disabled', text: 'Remove selected'
399 assert_selector 'li', text: 'Remove selected'
403 # When project tabs are switched, only options applicable to the current tab's selections are enabled.
404 test "verify selection options when tabs are switched" do
405 my_project = api_fixture('groups')['aproject']
406 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
407 my_subproject = api_fixture('groups')['asubproject']
409 # select subproject and a collection and verify that copy action is still disabled
410 visit page_with_token 'active', '/'
411 find("#projects-menu").click
412 find(".dropdown-menu a", text: my_project['name']).click
414 # Select a sub-project
415 click_link 'Subprojects'
416 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
418 within('tr', text: my_subproject['name']) do
419 find('input[type=checkbox]').click
422 # Select a collection
423 click_link 'Data collections'
424 assert page.has_text?(my_collection['name']), 'Collection not found in project'
426 within('tr', text: my_collection['name']) do
427 find('input[type=checkbox]').click
430 # Go back to Subprojects tab
431 click_link 'Subprojects'
432 click_button 'Selection'
433 within('.selection-action-container') do
434 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
435 assert_selector 'li.disabled', text: 'Compare selected'
436 assert_selector 'li.disabled', text: 'Copy selected'
437 assert_no_selector 'li.disabled', text: 'Move selected'
438 assert_selector 'li', text: 'Move selected'
439 assert_no_selector 'li.disabled', text: 'Remove selected'
440 assert_selector 'li', text: 'Remove selected'
443 # Close the dropdown by clicking outside it.
444 find('.dropdown-toggle', text: 'Selection').find(:xpath, '..').click
446 # Go back to Data collections tab
447 find('.nav-tabs a', text: 'Data collections').click
448 click_button 'Selection'
449 within('.selection-action-container') do
450 assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
451 assert_selector 'li', text: 'Create new collection with selected collections'
452 assert_selector 'li.disabled', text: 'Compare selected'
453 assert_no_selector 'li.disabled', text: 'Copy selected'
454 assert_selector 'li', text: 'Copy selected'
455 assert_no_selector 'li.disabled', text: 'Move selected'
456 assert_selector 'li', text: 'Move selected'
457 assert_no_selector 'li.disabled', text: 'Remove selected'
458 assert_selector 'li', text: 'Remove selected'
462 # "Move selected" and "Remove selected" options should not be available when current user cannot write to the project
463 test "move selected and remove selected actions not available when current user cannot write to project" do
464 my_project = api_fixture('groups')['anonymously_accessible_project']
465 visit page_with_token 'active', "/projects/#{my_project['uuid']}"
467 click_button 'Selection'
468 within('.selection-action-container') do
469 assert_selector 'li', text: 'Create new collection with selected collections'
470 assert_selector 'li', text: 'Compare selected'
471 assert_selector 'li', text: 'Copy selected'
472 assert_no_selector 'li', text: 'Move selected'
473 assert_no_selector 'li', text: 'Remove selected'
479 ['project_viewer', false],
480 ].each do |user, expect_collection_in_aproject|
481 test "combine selected collections into new collection #{user} #{expect_collection_in_aproject}" do
482 my_project = api_fixture('groups')['aproject']
483 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
485 visit page_with_token user, '/'
486 find("#projects-menu").click
487 find(".dropdown-menu a", text: my_project['name']).click
488 assert page.has_text?(my_collection['name']), 'Collection not found in project'
490 within('tr', text: my_collection['name']) do
491 find('input[type=checkbox]').click
494 click_button 'Selection'
495 within('.selection-action-container') do
496 click_link 'Create new collection with selected collections'
499 # now in the new collection page
500 if expect_collection_in_aproject
501 assert page.has_text?("Created new collection in the project #{my_project['name']}"),
502 'Not found flash message that new collection is created in aproject'
504 assert page.has_text?("Created new collection in your Home project"),
505 'Not found flash message that new collection is created in Home project'
507 assert page.has_text?('Content hash'), 'Not found content hash in collection page'
513 ["pipelines", "/pipeline_instances"],
514 ["collections", "/collections"]
515 ].each do |target,path|
516 test "Test dashboard button all #{target}" do
517 visit page_with_token 'active', '/'
518 click_link "All #{target}"
519 assert_equal path, current_path
523 def scroll_setup(project_name,
527 sort_parameters = nil)
528 project_uuid = api_fixture('groups')[project_name]['uuid']
529 visit page_with_token 'user1_with_load', '/projects/' + project_uuid
531 assert(page.has_text?("#{item_list_parameter.humanize} (#{total_nbr_items})"), "Number of #{item_list_parameter.humanize} did not match the input amount")
533 click_link item_list_parameter.humanize
537 find("th[data-sort-order='#{sort_parameters.gsub(/\s/,'')}']").click
542 def scroll_items_check(nbr_items,
548 for i in 1..nbr_items
549 items << "#{fixture_prefix}#{i}"
552 verify_items = items.dup
553 unexpected_items = []
555 within(".arv-project-#{item_list_parameter}") do
556 page.execute_script "window.scrollBy(0,999000)"
562 # Visit all rows. If not all expected items are found, retry
563 found_items = page.all(item_selector)
564 item_count = found_items.count
567 (0..item_count-1).each do |i|
568 # Found row text using the fixture string e.g. "Show Collection_#{n} "
569 item_name = found_items[i].text.split[1]
570 if !items.include? item_name
571 unexpected_items << item_name
573 verify_items.delete item_name
577 assert_operator( previous.downcase, :<=, item_name.downcase) if previous
582 assert_equal true, unexpected_items.empty?, "Found unexpected #{item_list_parameter.humanize} #{unexpected_items.inspect}"
583 assert_equal nbr_items, item_count, "Found different number of #{item_list_parameter.humanize}"
584 assert_equal true, verify_items.empty?, "Did not find all the #{item_list_parameter.humanize}"
589 ['project_with_10_collections', 10],
590 ['project_with_201_collections', 201], # two pages of data
591 ].each do |project_name, nbr_items|
592 test "scroll collections tab for #{project_name} with #{nbr_items} objects" do
593 item_list_parameter = "Data_collections"
594 scroll_setup project_name,
597 scroll_items_check nbr_items,
600 'tr[data-kind="arvados#collection"]'
605 ['project_with_10_collections', 10],
606 ['project_with_201_collections', 201], # two pages of data
607 ].each do |project_name, nbr_items|
608 test "scroll collections tab for #{project_name} with #{nbr_items} objects with ascending sort (case insensitive)" do
609 item_list_parameter = "Data_collections"
610 scroll_setup project_name,
615 scroll_items_check nbr_items,
618 'tr[data-kind="arvados#collection"]',
624 ['project_with_10_pipelines', 10, 0],
625 ['project_with_2_pipelines_and_60_jobs', 2, 60],
626 ['project_with_25_pipelines', 25, 0],
627 ].each do |project_name, num_pipelines, num_jobs|
628 test "scroll pipeline instances tab for #{project_name} with #{num_pipelines} pipelines and #{num_jobs} jobs" do
629 item_list_parameter = "Jobs_and_pipelines"
630 scroll_setup project_name,
631 num_pipelines + num_jobs,
633 # check the general scrolling and the pipelines
634 scroll_items_check num_pipelines,
637 'tr[data-kind="arvados#pipelineInstance"]'
638 # Check job count separately
639 jobs_found = page.all('tr[data-kind="arvados#job"]')
640 found_job_count = jobs_found.count
641 assert_equal num_jobs, found_job_count, 'Did not find expected number of jobs'
645 # Move button accessibility
648 ['active', true], # project owner
649 ['project_viewer', false],
650 ].each do |user, can_move|
651 test "#{user} can move subproject under another user's Home #{can_move}" do
652 project = api_fixture('groups')['aproject']
653 collection = api_fixture('collections')['collection_to_move_around_in_aproject']
655 # verify the project move button
656 visit page_with_token user, "/projects/#{project['uuid']}"
658 assert page.has_link? 'Move project...'
660 assert page.has_no_link? 'Move project...'
665 test "error while loading tab" do
666 original_arvados_v1_base = Rails.configuration.arvados_v1_base
668 visit page_with_token 'active', '/projects/' + api_fixture('groups')['aproject']['uuid']
670 # Point to a bad api server url to generate error
671 Rails.configuration.arvados_v1_base = "https://[100::f]:1/"
672 click_link 'Other objects'
673 within '#Other_objects' do
675 assert_selector('a', text: 'Reload tab')
677 # Now point back to the orig api server and reload tab
678 Rails.configuration.arvados_v1_base = original_arvados_v1_base
679 click_link 'Reload tab'
680 assert_no_selector('a', text: 'Reload tab')
681 assert_selector('button', text: 'Selection')
682 within '.selection-action-container' do
683 assert_selector 'tr[data-kind="arvados#trait"]'
688 test "add new project using projects dropdown" do
689 # verify that selection options are disabled on the project until an item is selected
690 visit page_with_token 'active', '/'
693 find("#projects-menu").click
694 click_link 'Add a new project'
695 assert_text 'New project'
696 assert_text 'No description provided'
698 # Add one more new project
699 find("#projects-menu").click
700 click_link 'Add a new project'
701 match = /New project \(\d\)/.match page.text
702 assert match, 'Expected project name not found'
703 assert_text 'No description provided'
706 test "first tab loads data when visiting other tab directly" do
707 # As of 2014-12-19, the first tab of project#show uses infinite scrolling.
708 # Make sure that it loads data even if we visit another tab directly.
709 need_selenium 'to land on specified tab using {url}#Advanced'
710 project = api_fixture("groups", "aproject")
711 visit(page_with_token("active_trustedclient",
712 "/projects/#{project['uuid']}#Advanced"))
713 assert_text("API response")
714 find("#page-wrapper .nav-tabs :first-child a").click
715 assert_text("Collection modified at")