Browse Source

Refactoring: Port System > Objects browser tests to capybara.

Martin Gruner 3 years ago
parent
commit
3be8f6d032

+ 0 - 12
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

+ 1 - 1
spec/system/system/sla_spec.rb → 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'

+ 1 - 1
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

+ 351 - 103
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'
+RSpec.describe 'System > Objects', type: :system 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
+
+        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
+
+    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
+
+  context 'when creating but then discarding fields again' do
+    before do
+      visit '/#system/object_manager'
+    end
+
+    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
+
+  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
+
+        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
+
+          # 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
+
+          # 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
+
+    ['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 'verifies option creation order of new tree select options' do
-
-    # 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
-    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)
+  context 'when creating and modifying tree select fields', db_strategy: :reset do
+
+    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
+
+    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'
+
+      # 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'
+
+      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
+
+      # 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
 
-  it 'checks smart defaults for select field' do
-    page.find('.js-new').click
+  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
 
-    fill_in 'Name', with: 'select1'
-    find('input[name=display]').set('select1')
+    before do
+      create(:overview, condition: {
+               "ticket.#{object_attribute.name}" => {
+                 operator: 'is',
+                 value:    'dummy',
+               },
+             })
+      visit '/#system/object_manager'
+    end
 
-    page.find('select[name=data_type]').select('Select')
+    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
 
-    page.first('div.js-add').click
-    page.first('div.js-add').click
-    page.first('div.js-add').click
+  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 }
 
-    counter = 0
-    page.all('.js-key').each do |field|
-      field.set(counter)
-      counter += 1
+    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
 
-    page.all('.js-value')[-2].set('special 2')
-    page.find('.js-submit').click
+    it 'preserves the sorting correctly' do
+      object_attribute
+      page.refresh
+      visit '/#system/object_manager'
+      click 'tbody tr:last-child'
 
-    expected_data_options = {
-      '0' => '0',
-      '1' => '1',
-      '2' => 'special 2',
-    }
+      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)
 
-    expect(ObjectManager::Attribute.last.data_option['options']).to eq(expected_data_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
 
-  it 'checks smart defaults for boolean field' do
-    page.find('.js-new').click
+  context 'when checking selection options removal', db_strategy: :reset do
 
-    fill_in 'Name', with: 'bool1'
-    find('input[name=display]').set('bool1')
+    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 } } } }
 
-    page.find('select[name=data_type]').select('Boolean')
-    page.find('.js-valueFalse').set('HELL NOO')
-    page.find('.js-submit').click
+    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
 
-    expected_data_options = {
-      true  => 'yes',
-      false => 'HELL NOO',
-    }
+    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
 
-    expect(ObjectManager::Attribute.last.data_option['options']).to eq(expected_data_options)
+  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
 
-  it 'checks default boolean value visibility' do
-    page.find('.js-new').click
+  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
 
-    fill_in 'Name', with: 'bool1'
-    find('input[name=display]').set('Bool 1')
+      expected_data_options = {
+        '0' => '0',
+        '1' => '1',
+        '2' => 'special 2',
+      }
+
+      expect(ObjectManager::Attribute.last.data_option['options']).to eq(expected_data_options)
+    end
 
-    page.find('select[name=data_type]').select('Boolean')
-    choose('data_option::default', option: 'true')
-    page.find('.js-submit').click
+    it 'checks smart defaults for boolean field' do
+      fill_in 'Name', with: 'bool1'
+      find('input[name=display]').set('bool1')
 
-    td = page.find(:css, 'td', text: 'bool1')
-    tr = td.find(:xpath, './parent::tr')
+      page.find('select[name=data_type]').select('Boolean')
+      page.find('.js-valueFalse').set('HELL NOO')
+      page.find('.js-submit').click
 
-    tr.click
+      expected_data_options = {
+        true  => 'yes',
+        false => 'HELL NOO',
+      }
 
-    expect(page).to have_checked_field('data_option::default', with: 'true')
+      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

+ 0 - 933
test/browser/admin_object_manager_test.rb

@@ -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

+ 0 - 211
test/browser/admin_object_manager_tree_select_test.rb

@@ -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