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'
246 def perform_selection_action src, dest, item, action
247 visit page_with_token 'active', '/'
248 find("#projects-menu").click
249 find(".dropdown-menu a", text: src['name']).click
250 assert page.has_text?(item['name']), 'Collection not found in src project'
252 within('tr', text: item['name']) do
253 find('input[type=checkbox]').click
256 click_button 'Selection'
258 within('.selection-action-container') do
259 assert page.has_text?("Compare selected"), "Compare selected link text not found"
260 assert page.has_link?("Copy selected"), "Copy selected link not found"
261 assert page.has_link?("Move selected"), "Move selected link not found"
262 assert page.has_link?("Remove selected"), "Remove selected link not found"
264 click_link "#{action} selected"
267 # select the destination project if a Copy or Move action is being performed
268 if action == 'Copy' || action == 'Move'
269 within(".modal-container") do
270 find('.selectable', text: dest['name']).click
271 find('.modal-footer a,button', text: action).click
277 # Test copy action state. It should not be available when a subproject is selected.
278 test "copy action is disabled when a subproject is selected" do
279 my_project = api_fixture('groups')['aproject']
280 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
281 my_subproject = api_fixture('groups')['asubproject']
283 # verify that selection options are disabled on the project until an item is selected
284 visit page_with_token 'active', '/'
285 find("#projects-menu").click
286 find(".dropdown-menu a", text: my_project['name']).click
288 click_button 'Selection'
289 within('.selection-action-container') do
290 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
291 assert_selector 'li.disabled', text: 'Compare selected'
292 assert_selector 'li.disabled', text: 'Copy selected'
293 assert_selector 'li.disabled', text: 'Move selected'
294 assert_selector 'li.disabled', text: 'Remove selected'
297 # select collection and verify links are enabled
298 visit page_with_token 'active', '/'
299 find("#projects-menu").click
300 find(".dropdown-menu a", text: my_project['name']).click
301 assert page.has_text?(my_collection['name']), 'Collection not found in project'
303 within('tr', text: my_collection['name']) do
304 find('input[type=checkbox]').click
307 click_button 'Selection'
308 within('.selection-action-container') do
309 assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
310 assert_selector 'li', text: 'Create new collection with selected collections'
311 assert_selector 'li.disabled', text: 'Compare selected'
312 assert_no_selector 'li.disabled', text: 'Copy selected'
313 assert_selector 'li', text: 'Copy selected'
314 assert_no_selector 'li.disabled', text: 'Move selected'
315 assert_selector 'li', text: 'Move selected'
316 assert_no_selector 'li.disabled', text: 'Remove selected'
317 assert_selector 'li', text: 'Remove selected'
320 # select subproject and verify that copy action is disabled
321 visit page_with_token 'active', '/'
322 find("#projects-menu").click
323 find(".dropdown-menu a", text: my_project['name']).click
325 click_link 'Subprojects'
326 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
328 within('tr', text: my_subproject['name']) do
329 find('input[type=checkbox]').click
332 click_button 'Selection'
333 within('.selection-action-container') do
334 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
335 assert_selector 'li.disabled', text: 'Compare selected'
336 assert_selector 'li.disabled', text: 'Copy selected'
337 assert_no_selector 'li.disabled', text: 'Move selected'
338 assert_selector 'li', text: 'Move selected'
339 assert_no_selector 'li.disabled', text: 'Remove selected'
340 assert_selector 'li', text: 'Remove selected'
343 # select subproject and a collection and verify that copy action is still disabled
344 visit page_with_token 'active', '/'
345 find("#projects-menu").click
346 find(".dropdown-menu a", text: my_project['name']).click
348 click_link 'Subprojects'
349 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
351 within('tr', text: my_subproject['name']) do
352 find('input[type=checkbox]').click
355 click_link 'Data collections'
356 assert page.has_text?(my_collection['name']), 'Collection not found in project'
358 within('tr', text: my_collection['name']) do
359 find('input[type=checkbox]').click
362 click_link 'Subprojects'
363 click_button 'Selection'
364 within('.selection-action-container') do
365 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
366 assert_selector 'li.disabled', text: 'Compare selected'
367 assert_selector 'li.disabled', text: 'Copy selected'
368 assert_no_selector 'li.disabled', text: 'Move selected'
369 assert_selector 'li', text: 'Move selected'
370 assert_no_selector 'li.disabled', text: 'Remove selected'
371 assert_selector 'li', text: 'Remove selected'
375 # When project tabs are switched, only options applicable to the current tab's selections are enabled.
376 test "verify selection options when tabs are switched" do
377 my_project = api_fixture('groups')['aproject']
378 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
379 my_subproject = api_fixture('groups')['asubproject']
381 # select subproject and a collection and verify that copy action is still disabled
382 visit page_with_token 'active', '/'
383 find("#projects-menu").click
384 find(".dropdown-menu a", text: my_project['name']).click
386 # Select a sub-project
387 click_link 'Subprojects'
388 assert page.has_text?(my_subproject['name']), 'Subproject not found in project'
390 within('tr', text: my_subproject['name']) do
391 find('input[type=checkbox]').click
394 # Select a collection
395 click_link 'Data collections'
396 assert page.has_text?(my_collection['name']), 'Collection not found in project'
398 within('tr', text: my_collection['name']) do
399 find('input[type=checkbox]').click
402 # Go back to Subprojects tab
403 click_link 'Subprojects'
404 click_button 'Selection'
405 within('.selection-action-container') do
406 assert_selector 'li.disabled', text: 'Create new collection with selected collections'
407 assert_selector 'li.disabled', text: 'Compare selected'
408 assert_selector 'li.disabled', text: 'Copy selected'
409 assert_no_selector 'li.disabled', text: 'Move selected'
410 assert_selector 'li', text: 'Move selected'
411 assert_no_selector 'li.disabled', text: 'Remove selected'
412 assert_selector 'li', text: 'Remove selected'
415 # Close the dropdown by clicking outside it.
416 find('.dropdown-toggle', text: 'Selection').find(:xpath, '..').click
418 # Go back to Data collections tab
419 find('.nav-tabs a', text: 'Data collections').click
420 click_button 'Selection'
421 within('.selection-action-container') do
422 assert_no_selector 'li.disabled', text: 'Create new collection with selected collections'
423 assert_selector 'li', text: 'Create new collection with selected collections'
424 assert_selector 'li.disabled', text: 'Compare selected'
425 assert_no_selector 'li.disabled', text: 'Copy selected'
426 assert_selector 'li', text: 'Copy selected'
427 assert_no_selector 'li.disabled', text: 'Move selected'
428 assert_selector 'li', text: 'Move selected'
429 assert_no_selector 'li.disabled', text: 'Remove selected'
430 assert_selector 'li', text: 'Remove selected'
434 # "Move selected" and "Remove selected" options should not be available when current user cannot write to the project
435 test "move selected and remove selected actions not available when current user cannot write to project" do
436 my_project = api_fixture('groups')['anonymously_accessible_project']
437 visit page_with_token 'active', "/projects/#{my_project['uuid']}"
439 click_button 'Selection'
440 within('.selection-action-container') do
441 assert_selector 'li', text: 'Create new collection with selected collections'
442 assert_selector 'li', text: 'Compare selected'
443 assert_selector 'li', text: 'Copy selected'
444 assert_no_selector 'li', text: 'Move selected'
445 assert_no_selector 'li', text: 'Remove selected'
451 ['project_viewer', false],
452 ].each do |user, expect_collection_in_aproject|
453 test "combine selected collections into new collection #{user} #{expect_collection_in_aproject}" do
454 my_project = api_fixture('groups')['aproject']
455 my_collection = api_fixture('collections')['collection_to_move_around_in_aproject']
457 visit page_with_token user, '/'
458 find("#projects-menu").click
459 find(".dropdown-menu a", text: my_project['name']).click
460 assert page.has_text?(my_collection['name']), 'Collection not found in project'
462 within('tr', text: my_collection['name']) do
463 find('input[type=checkbox]').click
466 click_button 'Selection'
467 within('.selection-action-container') do
468 click_link 'Create new collection with selected collections'
471 # now in the new collection page
472 if expect_collection_in_aproject
473 assert page.has_text?("Created new collection in the project #{my_project['name']}"),
474 'Not found flash message that new collection is created in aproject'
476 assert page.has_text?("Created new collection in your Home project"),
477 'Not found flash message that new collection is created in Home project'
479 assert page.has_text?('Content hash'), 'Not found content hash in collection page'
485 ["pipelines", "/pipeline_instances"],
486 ["collections", "/collections"]
487 ].each do |target,path|
488 test "Test dashboard button all #{target}" do
489 visit page_with_token 'active', '/'
490 click_link "All #{target}"
491 assert_equal path, current_path
495 def scroll_setup(project_name,
499 sort_parameters = nil)
500 project_uuid = api_fixture('groups')[project_name]['uuid']
501 visit page_with_token 'user1_with_load', '/projects/' + project_uuid
503 assert(page.has_text?("#{item_list_parameter.humanize} (#{total_nbr_items})"), "Number of #{item_list_parameter.humanize} did not match the input amount")
505 click_link item_list_parameter.humanize
509 find("th[data-sort-order='#{sort_parameters.gsub(/\s/,'')}']").click
514 def scroll_items_check(nbr_items,
520 for i in 1..nbr_items
521 items << "#{fixture_prefix}#{i}"
524 verify_items = items.dup
525 unexpected_items = []
527 within(".arv-project-#{item_list_parameter}") do
528 page.execute_script "window.scrollBy(0,999000)"
534 # Visit all rows. If not all expected items are found, retry
535 found_items = page.all(item_selector)
536 item_count = found_items.count
539 (0..item_count-1).each do |i|
540 # Found row text using the fixture string e.g. "Show Collection_#{n} "
541 item_name = found_items[i].text.split[1]
542 if !items.include? item_name
543 unexpected_items << item_name
545 verify_items.delete item_name
549 assert_operator( previous.downcase, :<=, item_name.downcase) if previous
554 assert_equal true, unexpected_items.empty?, "Found unexpected #{item_list_parameter.humanize} #{unexpected_items.inspect}"
555 assert_equal nbr_items, item_count, "Found different number of #{item_list_parameter.humanize}"
556 assert_equal true, verify_items.empty?, "Did not find all the #{item_list_parameter.humanize}"
561 ['project_with_10_collections', 10],
562 ['project_with_201_collections', 201], # two pages of data
563 ].each do |project_name, nbr_items|
564 test "scroll collections tab for #{project_name} with #{nbr_items} objects" do
565 item_list_parameter = "Data_collections"
566 scroll_setup project_name,
569 scroll_items_check nbr_items,
572 'tr[data-kind="arvados#collection"]'
577 ['project_with_10_collections', 10],
578 ['project_with_201_collections', 201], # two pages of data
579 ].each do |project_name, nbr_items|
580 test "scroll collections tab for #{project_name} with #{nbr_items} objects with ascending sort (case insensitive)" do
581 item_list_parameter = "Data_collections"
582 scroll_setup project_name,
587 scroll_items_check nbr_items,
590 'tr[data-kind="arvados#collection"]',
596 ['project_with_10_pipelines', 10, 0],
597 ['project_with_2_pipelines_and_60_jobs', 2, 60],
598 ['project_with_25_pipelines', 25, 0],
599 ].each do |project_name, num_pipelines, num_jobs|
600 test "scroll pipeline instances tab for #{project_name} with #{num_pipelines} pipelines and #{num_jobs} jobs" do
601 item_list_parameter = "Jobs_and_pipelines"
602 scroll_setup project_name,
603 num_pipelines + num_jobs,
605 # check the general scrolling and the pipelines
606 scroll_items_check num_pipelines,
609 'tr[data-kind="arvados#pipelineInstance"]'
610 # Check job count separately
611 jobs_found = page.all('tr[data-kind="arvados#job"]')
612 found_job_count = jobs_found.count
613 assert_equal num_jobs, found_job_count, 'Did not find expected number of jobs'
617 # Move button accessibility
620 ['active', true], # project owner
621 ['project_viewer', false],
622 ].each do |user, can_move|
623 test "#{user} can move subproject under another user's Home #{can_move}" do
624 project = api_fixture('groups')['aproject']
625 collection = api_fixture('collections')['collection_to_move_around_in_aproject']
627 # verify the project move button
628 visit page_with_token user, "/projects/#{project['uuid']}"
630 assert page.has_link? 'Move project...'
632 assert page.has_no_link? 'Move project...'
637 test "error while loading tab" do
638 original_arvados_v1_base = Rails.configuration.arvados_v1_base
640 visit page_with_token 'active', '/projects/' + api_fixture('groups')['aproject']['uuid']
642 # Point to a bad api server url to generate error
643 Rails.configuration.arvados_v1_base = "https://[100::f]:1/"
644 click_link 'Other objects'
645 within '#Other_objects' do
647 assert_selector('a', text: 'Reload tab')
649 # Now point back to the orig api server and reload tab
650 Rails.configuration.arvados_v1_base = original_arvados_v1_base
651 click_link 'Reload tab'
652 assert_no_selector('a', text: 'Reload tab')
653 assert_selector('button', text: 'Selection')
654 within '.selection-action-container' do
655 assert_selector 'tr[data-kind="arvados#trait"]'
660 test "add new project using projects dropdown" do
661 # verify that selection options are disabled on the project until an item is selected
662 visit page_with_token 'active', '/'
665 find("#projects-menu").click
666 click_link 'Add a new project'
667 assert_text 'New project'
668 assert_text 'No description provided'
670 # Add one more new project
671 find("#projects-menu").click
672 click_link 'Add a new project'
673 match = /New project \(\d\)/.match page.text
674 assert match, 'Expected project name not found'
675 assert_text 'No description provided'
678 test "first tab loads data when visiting other tab directly" do
679 # As of 2014-12-19, the first tab of project#show uses infinite scrolling.
680 # Make sure that it loads data even if we visit another tab directly.
681 need_selenium 'to land on specified tab using {url}#Advanced'
682 project = api_fixture("groups", "aproject")
683 visit(page_with_token("active_trustedclient",
684 "/projects/#{project['uuid']}#Advanced"))
685 assert_text("API response")
686 find("#page-wrapper .nav-tabs :first-child a").click
687 assert_text("bytes Collection")