From 3be8f6d0321254799bd71c86985e769a873ed9d3 Mon Sep 17 00:00:00 2001 From: Martin Gruner Date: Tue, 21 Sep 2021 09:29:59 +0200 Subject: [PATCH] Refactoring: Port System > Objects browser tests to capybara. --- script/build/test_slice_tests.sh | 12 - spec/system/{system => manage}/sla_spec.rb | 2 +- spec/system/system/maintenance_spec.rb | 2 +- spec/system/system/object_manager_spec.rb | 462 +++++++-- test/browser/admin_object_manager_test.rb | 933 ------------------ .../admin_object_manager_tree_select_test.rb | 211 ---- 6 files changed, 357 insertions(+), 1265 deletions(-) rename spec/system/{system => manage}/sla_spec.rb (98%) delete mode 100644 test/browser/admin_object_manager_test.rb delete mode 100644 test/browser/admin_object_manager_tree_select_test.rb diff --git a/script/build/test_slice_tests.sh b/script/build/test_slice_tests.sh index 1d949bd97..ab85a1e08 100755 --- a/script/build/test_slice_tests.sh +++ b/script/build/test_slice_tests.sh @@ -14,8 +14,6 @@ if [ "$LEVEL" == '1' ]; then rm test/browser/admin_channel_email_test.rb rm test/browser/admin_calendar_sla_test.rb rm test/browser/admin_drag_drop_to_new_group_test.rb - rm test/browser/admin_object_manager_test.rb - rm test/browser/admin_object_manager_tree_select_test.rb rm test/browser/admin_overview_test.rb rm test/browser/admin_permissions_granular_vs_full_test.rb rm test/browser/admin_role_test.rb @@ -84,8 +82,6 @@ elif [ "$LEVEL" == '2' ]; then rm test/browser/admin_channel_email_test.rb rm test/browser/admin_calendar_sla_test.rb rm test/browser/admin_drag_drop_to_new_group_test.rb - rm test/browser/admin_object_manager_test.rb - rm test/browser/admin_object_manager_tree_select_test.rb rm test/browser/admin_overview_test.rb rm test/browser/admin_permissions_granular_vs_full_test.rb #rm test/browser/admin_role_test.rb @@ -154,8 +150,6 @@ elif [ "$LEVEL" == '3' ]; then rm test/browser/admin_channel_email_test.rb rm test/browser/admin_calendar_sla_test.rb rm test/browser/admin_drag_drop_to_new_group_test.rb - rm test/browser/admin_object_manager_test.rb - rm test/browser/admin_object_manager_tree_select_test.rb rm test/browser/admin_overview_test.rb rm test/browser/admin_permissions_granular_vs_full_test.rb rm test/browser/admin_role_test.rb @@ -224,8 +218,6 @@ elif [ "$LEVEL" == '4' ]; then rm test/browser/admin_channel_email_test.rb rm test/browser/admin_calendar_sla_test.rb rm test/browser/admin_drag_drop_to_new_group_test.rb - rm test/browser/admin_object_manager_test.rb - rm test/browser/admin_object_manager_tree_select_test.rb rm test/browser/admin_overview_test.rb rm test/browser/admin_permissions_granular_vs_full_test.rb rm test/browser/admin_role_test.rb @@ -293,8 +285,6 @@ elif [ "$LEVEL" == '5' ]; then # test/browser/admin_channel_email_test.rb # test/browser/admin_calendar_sla_test.rb # rm test/browser/admin_drag_drop_to_new_group_test.rb - # test/browser/admin_object_manager_test.rb - # test/browser/admin_object_manager_tree_select_test.rb # test/browser/admin_overview_test.rb # rm test/browser/admin_permissions_granular_vs_full_test.rb rm test/browser/admin_role_test.rb @@ -365,8 +355,6 @@ elif [ "$LEVEL" == '6' ]; then rm test/browser/admin_channel_email_test.rb rm test/browser/admin_calendar_sla_test.rb rm test/browser/admin_drag_drop_to_new_group_test.rb - rm test/browser/admin_object_manager_test.rb - rm test/browser/admin_object_manager_tree_select_test.rb rm test/browser/admin_overview_test.rb rm test/browser/admin_permissions_granular_vs_full_test.rb rm test/browser/admin_role_test.rb diff --git a/spec/system/system/sla_spec.rb b/spec/system/manage/sla_spec.rb similarity index 98% rename from spec/system/system/sla_spec.rb rename to spec/system/manage/sla_spec.rb index 9fe68616e..e667856ef 100644 --- a/spec/system/system/sla_spec.rb +++ b/spec/system/manage/sla_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'System > Sla', type: :system do +RSpec.describe 'Manage > Sla', type: :system do before do ensure_websocket do visit 'manage/slas' diff --git a/spec/system/system/maintenance_spec.rb b/spec/system/system/maintenance_spec.rb index da16bcce7..edf7fa097 100644 --- a/spec/system/system/maintenance_spec.rb +++ b/spec/system/system/maintenance_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Manage > Maintenance', type: :system do +RSpec.describe 'System > Maintenance', type: :system do context 'when maintenance login is used' do context 'when maintenance login will be activated', authenticated_as: :authenticate do def authenticate diff --git a/spec/system/system/object_manager_spec.rb b/spec/system/system/object_manager_spec.rb index 3bd5c1fa8..105799d0c 100644 --- a/spec/system/system/object_manager_spec.rb +++ b/spec/system/system/object_manager_spec.rb @@ -2,139 +2,387 @@ require 'rails_helper' -# https://github.com/zammad/zammad/issues/266 -RSpec.describe 'Admin Panel > Objects', type: :system do - before do - visit '/#system/object_manager' - end +RSpec.describe 'System > Objects', type: :system do - it 'verifies option creation order of new tree select options' do + context 'when trying to create invalid attributes' do + RSpec.shared_examples 'cannot create new object attribute' do |name, error_message| + context "when trying to create a new attibute '#{name}'" do + before do + visit '/#system/object_manager' + page.find('.js-new').click + end - # create new field - page.find('.js-new').click - - # set meta information - fill_in 'Name', with: 'tree1' - fill_in 'Display', with: 'tree1' - page.find('select[name=data_type]').select('Tree Select') - - # create 3 childs - first_add_child = page.first('div.js-addChild') - first_add_child.click - first_add_child.click - first_add_child.click - - # create 1 top level node sibling - page.first('div.js-addRow').click - - # create 3 childs for the new top level node - page.all('div.js-addChild').last.click - page.all('div.js-addChild').last.click - page.all('div.js-addChild').last.click - - # create new top level nodes by first and second top level node - add_rows = page.all('div.js-addRow') - add_rows[0].click - add_rows[4].click - - # add numbers to all inputs to verify order in config later - number = 1 - page.all('input.js-key').each do |input| - input.send_keys(number) - number += 1 + it "fails with '#{error_message}'" do + within '.modal' do + fill_in 'name', with: name || 'fallback' + fill_in 'display', with: 'Not allowed' + click '.js-submit' + expect(find('.js-alert')).to have_text(error_message) + end + end + end end - page.find('.js-submit').click - expected_data_options = { 'options' => - [{ 'name' => '1', - 'value' => '1', - 'children' => [{ 'name' => '2', 'value' => '1::2' }, { 'name' => '3', 'value' => '1::3' }, { 'name' => '4', 'value' => '1::4' }] }, - { 'name' => '5', 'value' => '5' }, - { 'name' => '6', - 'value' => '6', - 'children' => - [{ 'name' => '7', - 'value' => '6::7', - 'children' => [{ 'name' => '8', 'value' => '6::7::8', 'children' => [{ 'name' => '9', 'value' => '6::7::8::9' }] }] }] }, - { 'name' => '10', 'value' => '10' }], - 'default' => '', - 'null' => true, - 'relation' => '', - 'nulloption' => true, - 'maxlength' => 255 } - - expect(ObjectManager::Attribute.last.data_option).to eq(expected_data_options) + include_examples 'cannot create new object attribute', 'customer_id', 'Object already exists!' + ['some_other_id', 'some_other_ids', 'some spaces'].each do |name| + include_examples 'cannot create new object attribute', name, 'are not allowed' + end end - it 'checks smart defaults for select field' do - page.find('.js-new').click - - fill_in 'Name', with: 'select1' - find('input[name=display]').set('select1') - - page.find('select[name=data_type]').select('Select') - - page.first('div.js-add').click - page.first('div.js-add').click - page.first('div.js-add').click - - counter = 0 - page.all('.js-key').each do |field| - field.set(counter) - counter += 1 + context 'when creating but then discarding fields again' do + before do + visit '/#system/object_manager' end - page.all('.js-value')[-2].set('special 2') - page.find('.js-submit').click - - expected_data_options = { - '0' => '0', - '1' => '1', - '2' => 'special 2', - } - - expect(ObjectManager::Attribute.last.data_option['options']).to eq(expected_data_options) + it 'discards the changes again' do + page.find('.js-new').click + within '.modal' do + fill_in 'name', with: 'new_field' + fill_in 'display', with: 'New field' + click '.js-submit' + end + click '.js-discard' + expect(page).to have_no_css('.js-discard') + end end - it 'checks smart defaults for boolean field' do - page.find('.js-new').click + context 'when creating and removing a field with migration', db_strategy: :reset do + RSpec.shared_examples 'create and remove field with migration' do |data_type| + context "for data_type '#{data_type}'" do + before do + visit '/#system/object_manager' + end - fill_in 'Name', with: 'bool1' - find('input[name=display]').set('bool1') + it 'creates and removes the field correctly' do + # Create + page.find('.js-new').click + within '.modal' do + fill_in 'name', with: 'new_field' + fill_in 'display', with: 'New field' + select data_type, from: 'data_type' + click '.js-submit' + end + expect(page).to have_text('New field') + expect(page).to have_text('Database Update required') + click '.js-execute', wait: 7.minutes + expect(page).to have_text('Zammad need a restart') + page.refresh - page.find('select[name=data_type]').select('Boolean') - page.find('.js-valueFalse').set('HELL NOO') - page.find('.js-submit').click + # Update + click 'tbody tr:last-child' + within '.modal' do + fill_in 'display', with: 'New field updated' + click '.js-submit' + end + expect(page).to have_text('New field updated') + expect(page).to have_text('Database Update required') + click '.js-execute', wait: 7.minutes + expect(page).to have_text('please reload your browser') + page.refresh - expected_data_options = { - true => 'yes', - false => 'HELL NOO', - } + # Delete + click 'tbody tr:last-child .js-delete' + expect(page).to have_text('Database Update required') + click '.js-execute', wait: 7.minutes + expect(page).to have_text('Zammad need a restart') + expect(page).to have_no_text('New field updated') + end + end + end - expect(ObjectManager::Attribute.last.data_option['options']).to eq(expected_data_options) + ['Text', 'Select', 'Integer', 'Datetime', 'Date', 'Boolean', 'Tree Select'].each do |data_type| + include_examples 'create and remove field with migration', data_type + end end - it 'checks default boolean value visibility' do - page.find('.js-new').click + context 'when creating and modifying tree select fields', db_strategy: :reset do - fill_in 'Name', with: 'bool1' - find('input[name=display]').set('Bool 1') + let(:object_attribute) do + attribute = create(:object_manager_attribute_tree_select, name: 'undeletable_field', display: 'Undeletable Field', position: 999) + ObjectManager::Attribute.migration_execute + attribute + end - page.find('select[name=data_type]').select('Boolean') - choose('data_option::default', option: 'true') - page.find('.js-submit').click + it 'creates and updates the fields correctly' do + # Create the field via API. + object_attribute + visit '/#system/object_manager' + page.refresh + click 'tbody tr:last-child' - td = page.find(:css, 'td', text: 'bool1') - tr = td.find(:xpath, './parent::tr') + # Add two new attributes to the field. + 2.times do |i| + click '.modal tbody tr:last-child .js-addRow' + find('.modal tbody tr:last-child .js-key').fill_in(with: "new tree option #{i}") + end + click '.js-submit' - tr.click + expect(page).to have_text('Database Update required') + click '.js-execute', wait: 7.minutes + expect(page).to have_text('please reload your browser') + page.refresh - expect(page).to have_checked_field('data_option::default', with: 'true') + # Check that the attributes were correctly saved. + expect(ObjectManager::Attribute.last.data_option[:options][-2..]).to eq([{ 'name' => 'new tree option 0', 'value' => 'new tree option 0' }, { 'name' => 'new tree option 1', 'value' => 'new tree option 1' }]) + end + end + + context 'when trying to delete undeletable fields', db_strategy: :reset do + let(:object_attribute) do + attribute = create(:object_manager_attribute_text, name: 'undeletable_field', display: 'Undeletable Field', position: 999) + ObjectManager::Attribute.migration_execute + attribute + end + + before do + create(:overview, condition: { + "ticket.#{object_attribute.name}" => { + operator: 'is', + value: 'dummy', + }, + }) + visit '/#system/object_manager' + end + + it 'field referenced by an overview is not deletable' do + expect(page).to have_text(object_attribute.display) + expect(page).to have_css('tbody tr:last-child span.is-disabled .icon-trash') + end + end + + context 'when checking field sorting', db_strategy: :reset do + # lexicographically ordered list of option strings + let(:options) { %w[0 000.000 1 100.100 100.200 2 200.100 200.200 3 ä b n ö p sr ß st t ü v] } + let(:options_hash) { options.reverse.collect { |o| [o, o] }.to_h } + + let(:object_attribute) do + attribute = create(:object_manager_attribute_select, data_option: { options: options_hash, default: 0 }, position: 999) + ObjectManager::Attribute.migration_execute + attribute + end + + it 'preserves the sorting correctly' do + object_attribute + page.refresh + visit '/#system/object_manager' + click 'tbody tr:last-child' + + sorted_dialog_values = all('table.settings-list tbody tr td:first-child input').map(&:value).reject { |x| x == '' } + expect(sorted_dialog_values).to eq(options) + + visit '/#ticket/create' + sorted_ticket_values = all("select[name=#{object_attribute.name}] option").map(&:value).reject { |x| x == '' } + expect(sorted_ticket_values).to eq(options) + end + end + + context 'when checking selection options removal', db_strategy: :reset do + + let(:options) { %w[äöü cat delete dog ß].index_with { |x| "#{x.capitalize} Display" } } + let(:options_no_dog) { options.except('dog') } + let(:options_no_dog_no_delete) { options_no_dog.except('delete') } + let(:screens) { { 'create_middle' => { 'ticket.agent'=>{ 'shown' => true, 'required' => false, 'item_class' => 'column' } }, 'edit' => { 'ticket.agent'=>{ 'shown' => true, 'required' => false } } } } + + let(:object_attribute) do + attribute = create(:object_manager_attribute_select, data_option: { options: options, default: 0 }, screens: screens, position: 999) + ObjectManager::Attribute.migration_execute + attribute + end + + it 'handles removed options correctly' do + object_attribute + page.refresh + + # Make sure option is present in the first place. + ticket = create(:ticket, group: Group.find_by(name: 'Users'), object_attribute.name => 'delete') + visit "/#ticket/zoom/#{ticket.id}" + sorted_ticket_values = all("select[name=#{object_attribute.name}] option").map(&:value).reject { |x| x == '' } + expect(sorted_ticket_values).to eq(options.keys) + expect(find("select[name=#{object_attribute.name}] option:checked").value).to eq('delete') + expect(find("select[name=#{object_attribute.name}] option:checked").text).to eq('Delete Display') + + # Remove 'delete' and 'dog' options from field via GUI to make sure that the :historical_options attribute is saved. + visit '/#system/object_manager' + click 'tbody tr:last-child' + within '.modal' do + 2.times { find('tr:nth-child(3) .icon-trash').click } + click '.js-submit' + end + expect(page).to have_text('Database Update required') + click '.js-execute', wait: 7.minutes + expect(page).to have_text('please reload your browser') + sleep 1 # Not sure why this is neede to pick up the new config in subsequent screens. + page.refresh + + # Make sure option is still available in already saved ticket, even though the option was removed from the object attribute. + # This is done via the :historical_options. + visit "/#ticket/zoom/#{ticket.id}" + sorted_ticket_values = all("select[name=#{object_attribute.name}] option").map(&:value).reject { |x| x == '' } + expect(sorted_ticket_values).to eq(options_no_dog.keys) + expect(find("select[name=#{object_attribute.name}] option:checked").value).to eq('delete') + expect(find("select[name=#{object_attribute.name}] option:checked").text).to eq('Delete Display') + + # Make sure deleted option is missing for new tickets. + visit '/#ticket/create' + sorted_ticket_values = all("select[name=#{object_attribute.name}] option").map(&:value).reject { |x| x == '' } + expect(sorted_ticket_values).to eq(options_no_dog_no_delete.keys) + end + end + + context 'when checking boolean user attributes', db_strategy: :reset do + let(:organization_object_attribute) do + attribute = create(:object_manager_attribute_boolean, object_name: 'Organization', data_option: { default: true, options: { true => 'organization:true', false => 'organization:false' } }, screens: screens, position: 999) + ObjectManager::Attribute.migration_execute + attribute + end + let(:user_object_attribute) do + attribute = create(:object_manager_attribute_boolean, object_name: 'User', data_option: { default: true, options: { true => 'user:true', false => 'user:false' } }, screens: screens, position: 999) + ObjectManager::Attribute.migration_execute + attribute + end + let(:organization) { create(:organization, organization_object_attribute.name => false) } + let(:customer) { create(:customer, user_object_attribute.name => false, organization: organization) } + + let(:screens) { { 'create' => { 'ticket.agent'=>{ 'shown' => true, 'required' => false, 'item_class' => 'column' } }, 'edit' => { 'ticket.agent'=>{ 'shown' => true, 'required' => false } }, 'view' => { 'ticket.agent'=>{ 'shown' => true, 'required' => false } } } } + let(:ticket) { create(:ticket, group: Group.find_by(name: 'Users'), customer: customer) } + + it 'shows user and organization attributes even if they are set to false' do + organization_object_attribute + user_object_attribute + page.refresh + visit "/#ticket/zoom/#{ticket.id}" + click('.content.active .tabsSidebar-tab[data-tab="organization"]') + expect(page).to have_text('organization:false') + click('.content.active .tabsSidebar-tab[data-tab="customer"]') + expect(page).to have_text('user:false') + end + end + + context 'when creating new fields' do + before do + visit '/#system/object_manager' + page.find('.js-new').click + end + + it 'verifies option creation order of new tree select options' do + # set meta information + fill_in 'Name', with: 'tree1' + fill_in 'Display', with: 'tree1' + page.find('select[name=data_type]').select('Tree Select') + + # create 3 childs + first_add_child = page.first('div.js-addChild') + first_add_child.click + first_add_child.click + first_add_child.click + + # create 1 top level node sibling + page.first('div.js-addRow').click + + # create 3 childs for the new top level node + page.all('div.js-addChild').last.click + page.all('div.js-addChild').last.click + page.all('div.js-addChild').last.click + + # create new top level nodes by first and second top level node + add_rows = page.all('div.js-addRow') + add_rows[0].click + add_rows[4].click + + # add numbers to all inputs to verify order in config later + number = 1 + page.all('input.js-key').each do |input| + input.send_keys(number) + number += 1 + end + + page.find('.js-submit').click + expected_data_options = { 'options' => + [{ 'name' => '1', + 'value' => '1', + 'children' => [{ 'name' => '2', 'value' => '1::2' }, { 'name' => '3', 'value' => '1::3' }, { 'name' => '4', 'value' => '1::4' }] }, + { 'name' => '5', 'value' => '5' }, + { 'name' => '6', + 'value' => '6', + 'children' => + [{ 'name' => '7', + 'value' => '6::7', + 'children' => [{ 'name' => '8', 'value' => '6::7::8', 'children' => [{ 'name' => '9', 'value' => '6::7::8::9' }] }] }] }, + { 'name' => '10', 'value' => '10' }], + 'default' => '', + 'null' => true, + 'relation' => '', + 'nulloption' => true, + 'maxlength' => 255 } + + expect(ObjectManager::Attribute.last.data_option).to eq(expected_data_options) + end + + it 'checks smart defaults for select field' do + fill_in 'Name', with: 'select1' + find('input[name=display]').set('select1') + + page.find('select[name=data_type]').select('Select') + + page.first('div.js-add').click + page.first('div.js-add').click + page.first('div.js-add').click + + counter = 0 + page.all('.js-key').each do |field| + field.set(counter) + counter += 1 + end + + page.all('.js-value')[-2].set('special 2') + page.find('.js-submit').click + + expected_data_options = { + '0' => '0', + '1' => '1', + '2' => 'special 2', + } + + expect(ObjectManager::Attribute.last.data_option['options']).to eq(expected_data_options) + end + + it 'checks smart defaults for boolean field' do + fill_in 'Name', with: 'bool1' + find('input[name=display]').set('bool1') + + page.find('select[name=data_type]').select('Boolean') + page.find('.js-valueFalse').set('HELL NOO') + page.find('.js-submit').click + + expected_data_options = { + true => 'yes', + false => 'HELL NOO', + } + + expect(ObjectManager::Attribute.last.data_option['options']).to eq(expected_data_options) + end + + it 'checks default boolean value visibility' do + fill_in 'Name', with: 'bool1' + find('input[name=display]').set('Bool 1') + + page.find('select[name=data_type]').select('Boolean') + choose('data_option::default', option: 'true') + page.find('.js-submit').click + + td = page.find(:css, 'td', text: 'bool1') + tr = td.find(:xpath, './parent::tr') + + tr.click + + expect(page).to have_checked_field('data_option::default', with: 'true') + end end # https://github.com/zammad/zammad/issues/3647 context 'when setting Min/Max values for integer' do before do + visit '/#system/object_manager' page.find('.js-new').click in_modal disappears: false do diff --git a/test/browser/admin_object_manager_test.rb b/test/browser/admin_object_manager_test.rb deleted file mode 100644 index d4a9c4c77..000000000 --- a/test/browser/admin_object_manager_test.rb +++ /dev/null @@ -1,933 +0,0 @@ -# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/ - -require 'browser_test_helper' - -class AdminObjectManagerTest < TestCase - - def test_basic_a - - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - # already existing - object_manager_attribute_create( - data: { - name: 'customer_id', - display: 'Customer Should Not Creatable', - data_type: 'Text', - }, - error: 'already exists' - ) - - # invalid name - object_manager_attribute_create( - data: { - name: 'some_other_id', - display: 'Should Not Creatable', - data_type: 'Text', - }, - error: 'are not allowed' - ) - - # invalid name - object_manager_attribute_create( - data: { - name: 'some_other_ids', - display: 'Should Not Creatable', - data_type: 'Text', - }, - error: 'are not allowed' - ) - - # invalid name - object_manager_attribute_create( - data: { - name: 'some spaces', - display: 'Should Not Creatable', - data_type: 'Text', - }, - error: 'are not allowed' - ) - - # valid name - object_manager_attribute_create( - data: { - name: 'browser_test1', - display: 'Browser Test 1', - data_type: 'Text', - }, - ) - - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - - # create new ticket - ticket_create( - data: { - customer: 'nico', - group: 'Users', - priority: '2 normal', - state: 'open', - title: 'ticket attribute test #1', - body: 'ticket attribute test #1', - }, - # custom_data_select: { - # key1: 'some value', - # }, - custom_data_input: { - browser_test1: 'some value öäüß', - }, - disable_group_check: true, - ) - - # update ticket - ticket_update( - data: {}, - # custom_data_select: { - # key1: 'some value', - # }, - custom_data_input: { - browser_test1: 'some value ABC', - }, - ) - - # discard new attribute - click(css: 'a[href="#manage"]') - click(css: 'a[href="#system/object_manager"]') - watch_for( - css: '.content.active table', - value: 'browser_test1', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - object_manager_attribute_delete( - data: { - name: 'browser_test1', - }, - ) - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - watch_for( - css: '.content.active table', - value: 'browser_test1', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - match_not( - css: '.content.active table', - value: 'browser_test1', - ) - end - - def test_basic_b - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - object_manager_attribute_create( - data: { - name: 'browser_test2', - display: 'Browser Test 2', - data_type: 'Select', - data_option: { - options: { - 'aa' => 'AA', - 'bb' => 'BB', - }, - }, - }, - ) - - object_manager_attribute_discard_changes - - sleep 4 - - object_manager_attribute_create( - data: { - name: 'browser_test2', - display: 'Browser Test 2', - data_type: 'Text', - # data_option: { - # default: 'xxx', - # }, - }, - ) - object_manager_attribute_create( - data: { - name: 'browser_test3', - display: 'Browser Test 3', - data_type: 'Select', - data_option: { - options: { - 'aa' => 'AA', - 'bb' => 'BB', - 'cc' => 'CC', - }, - }, - }, - ) - - object_manager_attribute_create( - data: { - name: 'browser_test4', - display: 'Browser Test 4', - data_type: 'Integer', - # data_option: { - # default: 'xxx', - # min: 15, - # max: 99, - # }, - }, - ) - - object_manager_attribute_create( - data: { - name: 'browser_test5', - display: 'Browser Test 5', - data_type: 'Datetime', - # data_option: { - # future: true, - # past: true, - # diff: 24 - # }, - }, - ) - - object_manager_attribute_create( - data: { - name: 'browser_test6', - display: 'Browser Test 6', - data_type: 'Date', - # data_option: { - # future: true, - # past: true, - # diff: 24 - # }, - }, - ) - - # rubocop:disable Lint/BooleanSymbol - object_manager_attribute_create( - data: { - name: 'browser_test7', - display: 'Browser Test 7', - data_type: 'Boolean', - data_option: { - options: { - true: 'YES', - false: 'NO', - }, - # default: true, - }, - }, - ) - # rubocop:enable Lint/BooleanSymbol - - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - - # create new ticket - ticket_create( - data: { - customer: 'nico', - group: 'Users', - priority: '2 normal', - state: 'open', - title: 'ticket attribute test all #1', - body: 'ticket attribute test all #1', - }, - custom_data_select: { - browser_test3: 'CC', - browser_test7: 'NO', - }, - custom_data_input: { - browser_test2: 'some value öäüß', - browser_test4: '25', - }, - disable_group_check: true, - ) - - ticket_verify( - data: { - title: 'ticket attribute test all #1', - custom_data_select: { - browser_test3: 'CC', - browser_test7: 'NO', - }, - custom_data_input: { - browser_test2: 'some value öäüß', - browser_test4: '25', - }, - }, - ) - - object_manager_attribute_delete( - data: { - name: 'browser_test2', - }, - ) - object_manager_attribute_delete( - data: { - name: 'browser_test3', - }, - ) - object_manager_attribute_delete( - data: { - name: 'browser_test4', - }, - ) - object_manager_attribute_delete( - data: { - name: 'browser_test5', - }, - ) - object_manager_attribute_delete( - data: { - name: 'browser_test6', - }, - ) - object_manager_attribute_delete( - data: { - name: 'browser_test7', - }, - ) - sleep 1 - object_manager_attribute_migrate - - match_not( - css: '.content.active', - value: 'Database Update required', - ) - match_not( - css: '.content.active table', - value: 'browser_test2', - ) - match_not( - css: '.content.active table', - value: 'browser_test3', - ) - match_not( - css: '.content.active table', - value: 'browser_test4', - ) - match_not( - css: '.content.active table', - value: 'browser_test5', - ) - match_not( - css: '.content.active table', - value: 'browser_test6', - ) - match_not( - css: '.content.active table', - value: 'browser_test7', - ) - end - - def test_basic_c - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - # valid name - object_manager_attribute_create( - data: { - name: 'browser_update_test1', - display: 'Browser Update Test 1', - data_type: 'Text', - }, - ) - - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - - # valid name - object_manager_attribute_update( - data: { - name: 'browser_update_test1', - display: 'Browser Update Test 2', - data_type: 'Text', - }, - ) - - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'configuration of Zammad has changed', - ) - click(css: '.modal .js-submit') - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - - object_manager_attribute_delete( - data: { - name: 'browser_update_test1', - }, - ) - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - watch_for( - css: '.content.active table', - value: 'browser_update_test1', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - match_not( - css: '.content.active table', - value: 'browser_update_test1', - ) - - end - - def test_that_attributes_with_references_should_have_a_disabled_delete_button - @browser = instance = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - - tasks_close_all - - # create two new attributes - object_manager_attribute_create( - data: { - name: 'deletable_attribute', - display: 'Deletable Attribute', - data_type: 'Text', - }, - ) - - object_manager_attribute_create( - data: { - name: 'undeletable_attribute', - display: 'Undeletable Attribute', - data_type: 'Text', - }, - ) - - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - - # create a new overview that references the undeletable_attribute - overview_create( - browser: instance, - data: { - name: 'test_overview', - roles: ['Agent'], - selector: { - 'Undeletable Attribute' => 'DUMMY', - }, - 'order::direction' => 'down', - 'text_input' => true, - } - ) - click( - browser: instance, - css: 'a[href="#manage"]', - mute_log: true, - ) - click( - browser: instance, - css: '.content.active a[href="#system/object_manager"]', - mute_log: true, - ) - - 30.times do - deletable_attribute = instance.find_elements(xpath: '//td[text()="deletable_attribute"]/following-sibling::*[2]')[0] - break if deletable_attribute - - sleep 1 - end - - sleep 1 - deletable_attribute = instance.find_elements(xpath: '//td[text()="deletable_attribute"]/following-sibling::*[2]')[0] - assert_not_nil(deletable_attribute) - deletable_attribute_html = deletable_attribute.attribute('innerHTML') - assert(deletable_attribute_html.include?('title="Delete"')) - assert(deletable_attribute_html.include?('href="#"')) - assert(deletable_attribute_html.exclude?('cannot be deleted')) - - undeletable_attribute = instance.find_elements(xpath: '//td[text()="undeletable_attribute"]/following-sibling::*[2]')[0] - assert_not_nil(undeletable_attribute) - undeletable_attribute_html = undeletable_attribute.attribute('innerHTML') - assert(undeletable_attribute_html.include?('Overview')) - assert(undeletable_attribute_html.include?('test_overview')) - assert(undeletable_attribute_html.include?('cannot be deleted')) - assert(undeletable_attribute_html.exclude?('href="#"')) - end - - def test_proper_sorting_of_select_attributes - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - # lexicographically ordered list of option strings - options = %w[0 000.000 1 100.100 100.200 2 200.100 200.200 3 ä b n ö p sr ß st t ü v] - options_hash = options.reverse.collect { |o| [o, o] }.to_h - - object_manager_attribute_create( - data: { - name: 'select_attributes_sorting_test', - display: 'Select Attributes Sorting Test', - data_type: 'Select', - data_option: { options: options_hash }, - }, - ) - sleep 2 - - # open the select attribute that we just created - execute(js: "$(\".content.active td:contains('select_attributes_sorting_test')\").first().click()") - sleep 3 - - unsorted_locations = options.map do |key| - [get_location(xpath: "//input[@value='#{key}']").y, key] - end - log("unsorted_locations = #{unsorted_locations.inspect}") - sorted_locations = unsorted_locations.sort_by(&:first).map(&:second) - log("sorted_locations = #{sorted_locations.inspect}") - assert_equal options, sorted_locations - - # close the attribute modal - click(css: '.modal button.js-submit') - - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - watch_for( - css: '.content.active table', - value: 'select_attributes_sorting_test', - ) - - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 7.minutes, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - - # create a new ticket and check whether the select attributes are correctly sorted or not - click( - css: 'a[href="#ticket/create"]', - mute_log: true, - ) - - watch_for( - css: 'select[name="select_attributes_sorting_test"]', - ) - - select_element = @browser.find_elements(css: 'select[name="select_attributes_sorting_test"]')[0] - unsorted_options = select_element.find_elements(xpath: './*').map(&:text).reject { |x| x == '-' } - log unsorted_options.inspect - assert_equal options, unsorted_options - - object_manager_attribute_delete( - data: { - name: 'select_attributes_sorting_test', - }, - ) - object_manager_attribute_migrate - end - - def test_deleted_select_attributes - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - - options = %w[äöü cat delete dog ß].index_with { |x| "#{x.capitalize} Display" } - options_no_dog = options.except('dog') - options_no_dog_no_delete = options_no_dog.except('delete') - - tasks_close_all - - object_manager_attribute_create( - data: { - name: 'select_attributes_delete_test', - display: 'Select Attributes Delete Test', - data_type: 'Select', - data_option: { - options: options, - }, - }, - ) - object_manager_attribute_migrate - - ticket_create( - data: { - customer: 'nico', - group: 'Users', - title: 'select_attributes_delete_test', - body: 'select_attributes_delete_test', - }, - custom_data_select: { - select_attributes_delete_test: 'Delete Display', - }, - disable_group_check: true, - ) - - watch_for( - css: '.content.active select[name="select_attributes_delete_test"]', - ) - - # confirm that all options and their display values are there and are in the correct order - select_element = @browser.find_elements(css: '.content.active select[name="select_attributes_delete_test"]')[0] - unsorted_options = select_element.find_elements(xpath: './*').map { |o| o.attribute('value') }.reject { |x| x == '' } - assert_equal options.keys, unsorted_options - unsorted_display_options = select_element.find_elements(xpath: './*').map(&:text).reject { |x| x == '-' } - assert_equal options.values, unsorted_display_options - - # confirm that the "delete" option is selected and that its display text is indeed "Delete Display" - selected_option = select_element.find_elements(css: 'option:checked')[0] - assert_equal 'delete', selected_option.attribute('value') - assert_equal 'Delete Display', selected_option.text - - object_manager_attribute_update( - data: { - name: 'select_attributes_delete_test', - data_option: { - options: options_no_dog_no_delete, - }, - }, - ) - object_manager_attribute_migrate - - screenshot(comment: 'deleted_select_attributes_before_click') - - # open the previously created ticket and verify its attribute selection - click( - xpath: '//a/div[contains(text(),"select_attributes_delete_test")]', - ) - # confirm that all options and their display values are there and are in the correct order - select_element = @browser.find_elements(css: '.content.active select[name="select_attributes_delete_test"]')[0] - unsorted_options = select_element.find_elements(xpath: './*').map { |o| o.attribute('value') }.reject { |x| x == '' } - assert_equal options_no_dog.keys, unsorted_options - unsorted_display_options = select_element.find_elements(xpath: './*').map(&:text).reject { |x| x == '-' } - assert_equal options_no_dog.values, unsorted_display_options - - # confirm that the "delete" option is still selected and that its display text is still indeed "Delete Display" - selected_option = select_element.find_elements(css: 'option:checked')[0] - assert_equal 'delete', selected_option.attribute('value') - assert_equal 'Delete Display', selected_option.text - - # create a new ticket and check that the deleted options no longer appear - click( - css: 'a[href="#ticket/create"]', - mute_log: true, - ) - - watch_for( - css: 'select[name="select_attributes_delete_test"]', - ) - - select_element = @browser.find_elements(css: 'select[name="select_attributes_delete_test"]')[0] - unsorted_options = select_element.find_elements(xpath: './*').map { |o| o.attribute('value') }.reject { |x| x == '' } - assert_equal options_no_dog_no_delete.keys, unsorted_options - unsorted_display_options = select_element.find_elements(xpath: './*').map(&:text).reject { |x| x == '-' } - assert_equal options_no_dog_no_delete.values, unsorted_display_options - - object_manager_attribute_delete( - data: { - name: 'select_attributes_delete_test', - }, - ) - object_manager_attribute_migrate - end - - # verify fix for issue #2233 - Boolean object set to false is not visible - # verify fix for issue #2277 - Note is not shown for customer / organisations if it's empty - def test_false_boolean_attributes_gets_displayed_for_organizations - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - object_manager_attribute_create( - data: { - object: 'Organization', - name: 'bool_test', - display: 'bool_test', - data_type: 'Boolean', - data_option: { - options: { - # rubocop:disable Lint/BooleanSymbol - true: 'YES', - false: 'NO', - # rubocop:enable Lint/BooleanSymbol - } - }, - }, - ) - object_manager_attribute_create( - data: { - object: 'Organization', - name: 'text_test', - display: 'text_test', - data_type: 'Text', - }, - ) - object_manager_attribute_migrate - - ticket_open_by_title(title: 'select') - - click(css: '.content.active .tabsSidebar-tab[data-tab="organization"]') - click(css: '.content.active .sidebar[data-tab="organization"] .js-actions .dropdown-toggle') - click(css: '.content.active .sidebar[data-tab="organization"] .js-actions [data-type="organization-edit"]') - - modal_ready - select(css: '.content.active .modal select[name="bool_test"]', value: 'NO') - click(css: '.content.active .modal .js-submit') - modal_disappear - - watch_for( - css: '.content.active .sidebar[data-tab="organization"] .sidebar-content', - value: 'bool_test', - ) - match_not( - css: '.content.active .sidebar[data-tab="organization"] .sidebar-content', - value: 'text_test', - ) - match( - css: '.content.active .sidebar[data-tab="organization"] .sidebar-content', - value: 'note', - ) - - object_manager_attribute_delete( - data: { - object: 'Organization', - name: 'bool_test', - }, - ) - object_manager_attribute_delete( - data: { - object: 'Organization', - name: 'text_test', - }, - ) - object_manager_attribute_migrate - end - - # verify fix for issue #2233 - Boolean object set to false is not visible - # verify fix for issue #2277 - Note is not shown for customer / organisations if it's empty - def test_false_boolean_attributes_gets_displayed_for_users - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - object_manager_attribute_create( - data: { - object: 'User', - name: 'bool_test', - display: 'bool_test', - data_type: 'Boolean', - data_option: { - options: { - # rubocop:disable Lint/BooleanSymbol - true: 'YES', - false: 'NO', - # rubocop:enable Lint/BooleanSymbol - } - }, - }, - ) - object_manager_attribute_create( - data: { - object: 'User', - name: 'text_test', - display: 'text_test', - data_type: 'Text', - }, - ) - object_manager_attribute_migrate - - ticket_open_by_title(title: 'select') - - click(css: '.content.active .tabsSidebar-tab[data-tab="customer"]') - click(css: '.content.active .sidebar[data-tab="customer"] .js-actions .dropdown-toggle') - click(css: '.content.active .sidebar[data-tab="customer"] .js-actions [data-type="customer-edit"]') - - modal_ready - select(css: '.content.active .modal select[name="bool_test"]', value: 'NO') - click(css: '.content.active .modal .js-submit') - modal_disappear - - watch_for( - css: '.content.active .sidebar[data-tab="customer"] .sidebar-content', - value: 'bool_test', - ) - match_not( - css: '.content.active .sidebar[data-tab="customer"] .sidebar-content', - value: 'text_test', - ) - match( - css: '.content.active .sidebar[data-tab="customer"] .sidebar-content', - value: 'note', - ) - - object_manager_attribute_delete( - data: { - object: 'User', - name: 'bool_test', - }, - ) - object_manager_attribute_delete( - data: { - object: 'User', - name: 'text_test', - }, - ) - object_manager_attribute_migrate - end -end diff --git a/test/browser/admin_object_manager_tree_select_test.rb b/test/browser/admin_object_manager_tree_select_test.rb deleted file mode 100644 index c4cdd5fb2..000000000 --- a/test/browser/admin_object_manager_tree_select_test.rb +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/ - -require 'browser_test_helper' - -class AdminObjectManagerTreeSelectTest < TestCase - - def test_basic_a - - @browser = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - object_manager_attribute_create( - data: { - name: 'browser_test_tree_select1', - display: 'Browser Test TreeSelect1', - data_type: 'Tree Select', - data_option: { - options: { - 'Incident' => { - 'Hardware' => { - 'Monitor' => {}, - 'Mouse' => {}, - 'Keyboard' => {}, - }, - 'Softwareproblem' => { - 'CRM' => {}, - 'EDI' => {}, - 'SAP' => { - 'Authentication' => {}, - 'Not reachable' => {}, - }, - 'MS Office' => { - 'Excel' => {}, - 'PowerPoint' => {}, - 'Word' => {}, - 'Outlook' => {}, - }, - }, - }, - 'Service request' => { - 'New software requirement' => {}, - 'New hardware' => {}, - 'Consulting' => {}, - }, - 'Change request' => {}, - }, - }, - }, - ) - - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 240, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - - # discard new attribute - click(css: 'a[href="#manage"]') - click(css: 'a[href="#system/object_manager"]') - watch_for( - css: '.content.active table', - value: 'browser_test_tree_select1', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - object_manager_attribute_delete( - data: { - name: 'browser_test_tree_select1', - }, - ) - watch_for( - css: '.content.active', - value: 'Database Update required', - ) - watch_for( - css: '.content.active table', - value: 'browser_test_tree_select1', - ) - click(css: '.content.active .tab-pane.active div.js-execute') - watch_for( - css: '.modal', - value: 'restart', - ) - watch_for_disappear( - css: '.modal', - timeout: 240, - ) - sleep 5 - watch_for( - css: '.content.active', - ) - match_not( - css: '.content.active', - value: 'Database Update required', - ) - match_not( - css: '.content.active table', - value: 'browser_test_tree_select1', - ) - end - - # verify the fix for issue #2206 - Unable to modify tree_select attributes with fresh 2.6 - def test_modify_tree_select_attributes - @browser = instance = browser_instance - login( - username: 'admin@example.com', - password: 'test', - url: browser_url, - ) - tasks_close_all - - object_manager_attribute_create( - data: { - name: 'browser_test_tree_select2', - display: 'Browser Test TreeSelect2', - data_type: 'Tree Select', - data_option: { - options: { - 'Incident' => { - 'Hardware' => { - 'Monitor' => {}, - 'Mouse' => {}, - }, - }, - 'Service request' => { - 'New software requirement' => {}, - 'New hardware' => {}, - }, - 'Change request' => {}, - }, - }, - }, - ) - object_manager_attribute_migrate - - # open the newly created tree_select and add some new options - object_manager_attribute_update( - data: { - name: 'browser_test_tree_select2', - }, - do_not_submit: true, - ) - - # add two new first level entries - 2.times do |i| - instance.find_elements(css: '.modal .js-treeTable .js-key').last.click - - element = instance.find_elements(css: '.modal .js-treeTable .js-key').last - element.clear - element.send_keys("new tree option #{i}") - end - - click( - css: '.modal button.js-submit' - ) - modal_disappear - - object_manager_attribute_migrate - - # open the tree select again and check that the newly added options are there - watch_for( - css: '.content.active table', - value: 'browser_test_tree_select2', - ) - object_manager_attribute_update( - data: { - name: 'browser_test_tree_select2', - }, - do_not_submit: true, - ) - 2.times do |i| - exists( - css: '.modal .js-treeTable', - value: "new tree option #{i}", - ) - end - modal_close - - # clean up and confirm the deletion of newly created attributes - object_manager_attribute_delete( - data: { - name: 'browser_test_tree_select2', - }, - ) - object_manager_attribute_migrate - - match_not( - css: '.content.active table', - value: 'browser_test_tree_select2', - ) - end -end