<?php /* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ require_once dirname(__FILE__) . '/../../include/CWebTest.php'; require_once dirname(__FILE__).'/../../include/helpers/CDataHelper.php'; require_once dirname(__FILE__).'/../behaviors/CMessageBehavior.php'; require_once dirname(__FILE__).'/../behaviors/CTableBehavior.php'; /** * @backup widget, profiles * * @dataSource AllItemValueTypes * * @onBefore prepareData */ class testDashboardWebMonitoringWidget extends testWidgets { protected static $dashboardid; protected static $groupids; protected static $update_widget = 'Update Web monitoring widget'; const DEFAULT_DASHBOARD = 'Dashboard for Web monitoring widget test'; const DASHBOARD_FOR_WIDGET_ACTIONS = 'Dashboard for Web monitoring widget create/update test'; /** * Attach MessageBehavior and TableBehavior to the test. * * @return array */ public function getBehaviors() { return [ CMessageBehavior::class, CTableBehavior::class ]; } /** * Create data for autotests which use WebWidget. * * @return array */ public function prepareData() { // Create a Dashboard and pages for widgets. $dashboards = CDataHelper::call('dashboard.create', [ [ 'name' => self::DEFAULT_DASHBOARD, 'pages' => [ [ 'name' => 'Layout' ] ] ], [ 'name' => self::DASHBOARD_FOR_WIDGET_ACTIONS, 'pages' => [ [ 'name' => 'Actions', 'widgets' => [ [ 'name' => 'Update Web monitoring widget', 'type' => 'web', 'x' => 0, 'y' => 0, 'width' => 18, 'height' => 4 ], [ 'name' => 'WebMonitoring for delete', 'type' => 'web', 'x' => 18, 'y' => 0, 'width' => 18, 'height' => 4 ], [ 'name' => 'WebMonitoring for cancel', 'type' => 'web', 'x' => 36, 'y' => 0, 'width' => 18, 'height' => 4 ] ] ] ] ] ]); self::$dashboardid = CDataHelper::getIds('name'); // Create hostgroups for hosts. CDataHelper::call('hostgroup.create', [ ['name' => 'First Group for Web Monitoring check'], ['name' => 'Second Group for Web Monitoring check'] ]); self::$groupids = CDataHelper::getIds('name'); // Create hosts. CDataHelper::createHosts([ [ 'host' => 'First host for Web Monitoring widget', 'groups' => [ 'groupid' => self::$groupids['First Group for Web Monitoring check'] ] ], [ 'host' => 'Second host for Web Monitoring widget', 'groups' => [ 'groupid' => self::$groupids['Second Group for Web Monitoring check'] ] ] ]); } public static function getWidgetData() { return [ // #0 Name and show header. [ [ 'check_dialog_properties' => true, 'fields' => [ 'Show header' => true, 'Name' => 'Name and show header name' ] ] ], // #1 Empty name added. [ [ 'fields' => [ 'Name' => '' ] ] ], // #2 Empty fields. [ [ 'fields' => [] ] ], // #3 Tag OR selector and spaces. [ [ 'fields' => [ 'Name' => 'Hello World', 'Scenario tags' => 'Or', 'Refresh interval' => '2 minutes' ] ] ], // #4 Show Maintenance and triming applied. [ [ 'fields' => [ 'Show header' => false, 'Name' => ' Happy case ', 'Refresh interval' => '10 minutes', 'Show hosts in maintenance' => true ], 'trim' => true ] ], // #5 Special symbols in name and no maintenance. [ [ 'fields' => [ 'Name' => '🙂,кирилица, 2-4-8 bytes symbols, "],*,a[x=": "],*,a[x="/\|', 'Refresh interval' => '1 minute', 'Show hosts in maintenance' => false ] ] ], // #6 No refresh. [ [ 'fields' => [ 'Show header' => false, 'Refresh interval' => 'No refresh' ] ] ], // #7 Host groups. [ [ 'fields' => [ 'Host groups' => [ 'First Group for Web Monitoring check', 'Second Group for Web Monitoring check' ], 'Refresh interval' => '30 seconds' ] ] ], // #8 Host group and exclude host group. [ [ 'fields' => [ 'Host groups' => 'First Group for Web Monitoring check', 'Exclude host groups' => 'Second Group for Web Monitoring check', 'Refresh interval' => '30 seconds' ] ] ], // #9 Hosts. [ [ 'fields' => [ 'Hosts' => [ 'First host for Web Monitoring widget', 'Second host for Web Monitoring widget' ], 'Refresh interval' => '30 seconds' ] ] ], // #10 Hosts and host groups. [ [ 'fields' => [ 'Name' => STRING_255, 'Show header' => true, 'Host groups' => [ 'First Group for Web Monitoring check', 'Second Group for Web Monitoring check' ], 'Hosts' => [ 'First host for Web Monitoring widget', 'Second host for Web Monitoring widget' ], 'Refresh interval' => '10 minutes' ] ] ], // #11 Tags. [ [ 'fields' => [ 'Name' => 'Check tags table', 'Refresh interval' => '1 minute' ], 'Scenario tags' => [ ['name' => 'empty value', 'operator' => 'Equals', 'value' => ''], ['name' => '', 'operator' => 'Does not contain', 'value' => 'empty tag'], ['name' => 'Check host tag with operator - Equals ⚠️', 'operator' => 'Equals', 'value' => 'Warning ⚠️'], ['name' => 'Check host tag with operator - Exists', 'operator' => 'Exists'], ['name' => 'Check host tag with operator - Contains ❌', 'operator' => 'Contains', 'value' => 'tag value ❌'], ['name' => 'Check host tag with operator - Does not exist', 'operator' => 'Does not exist'], ['name' => 'Check host tag with operator - Does not equal', 'operator' => 'Does not equal', 'value' => 'Average'], ['name' => 'Check host tag with operator - Does not contain', 'operator' => 'Does not contain', 'value' => 'Disaster'] ] ] ] ]; } public static function getCancelData() { return [ // #0 Cancel creating widget with saving the dashboard. [ [ 'cancel_form' => true, 'create_widget' => true, 'save_dashboard' => true ] ], // #1 Cancel updating widget with saving the dashboard. [ [ 'cancel_form' => true, 'create_widget' => false, 'save_dashboard' => true ] ], // #2 Create widget without saving the dashboard. [ [ 'cancel_form' => false, 'create_widget' => true, 'save_dashboard' => false ] ], // #3 Update widget without saving the dashboard. [ [ 'cancel_form' => false, 'create_widget' => false, 'save_dashboard' => false ] ] ]; } /** * Perform Web Monitoring widget creation or update and verify the result. * * @param boolean $update updating is performed */ protected function checkWidgetForm($data, $update = false) { $data['fields']['Name'] = ($data['fields'] === []) ? '' : CTestArrayHelper::get($data, 'fields.Name', 'Web monitoring '.microtime()); $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='. self::$dashboardid[self::DASHBOARD_FOR_WIDGET_ACTIONS])->waitUntilReady(); $dashboard = CDashboardElement::find()->one(); $old_widget_count = $dashboard->getWidgets()->count(); $form = $update ? $dashboard->getWidget(self::$update_widget)->edit()->asForm() : $dashboard->edit()->addWidget()->asForm(); $form->fill(['Type' => CFormElement::RELOADABLE_FILL('Web monitoring')]); if (array_key_exists('tags', $data)) { foreach ($data['tags'] as $entity => $values) { $this->setTagSelector('id:tags_table_'.$entity.'_tags'); $this->setTags($values); } } $form->fill($data['fields']); if (array_key_exists('group_by', $data)) { $this->getGroupByTable()->fill($data['group_by']); } $values = $form->getFields()->filter(CElementFilter::VISIBLE)->asValues(); $form->submit(); // Trim leading and trailing spaces from expected results if necessary. if (CTestArrayHelper::get($data, 'trim', false)) { $data = CTestArrayHelper::trim($data); } else { // If name is empty string it is replaced by default widget name "Web monitoring". $header = ($data['fields']['Name'] === '') ? 'Web monitoring' : $data['fields']['Name']; if ($update) { self::$update_widget = $header; } COverlayDialogElement::ensureNotPresent(); $widget = $dashboard->getWidget($header); // Save Dashboard to ensure that widget is correctly saved. $dashboard->save()->waitUntilReady(); $this->assertMessage(TEST_GOOD, 'Dashboard updated'); // Check widgets count. $this->assertEquals($old_widget_count + ($update ? 0 : 1), $dashboard->getWidgets()->count()); // Check new widget update interval. $refresh = (CTestArrayHelper::get($data['fields'], 'Refresh interval') === 'Default (1 minute)') ? '1 minute' : (CTestArrayHelper::get($data['fields'], 'Refresh interval', '1 minute')); $this->assertEquals($refresh, $widget->getRefreshInterval()); // Check new widget form fields and values in frontend. $saved_form = $widget->edit(); $this->assertEquals($values, $saved_form->getFields()->filter(CElementFilter::VISIBLE)->asValues()); $saved_form->checkValue($data['fields']); if (array_key_exists('tags', $data)) { foreach ($data['tags'] as $entity => $values) { $this->setTagSelector('id:tags_table_'.$entity.'_tags'); $this->assertTags($values); } } // Close widget window and cancel editing the dashboard. COverlayDialogElement::find()->one()->close(); $dashboard->cancelEditing(); } } /** * Function for checking cancelling form or submitting without any changes. * * @param boolean $cancel true if cancel scenario, false if form is submitted * @param boolean $create true if create scenario, false if update * @param boolean $save_dashboard true if dashboard will be saved, false if not */ protected function checkNoChanges($cancel = false, $create = false, $save_dashboard = true) { $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid=' .self::$dashboardid[self::DASHBOARD_FOR_WIDGET_ACTIONS])->waitUntilReady(); $dashboard = CDashboardElement::find()->one()->waitUntilReady(); $dashboard->invalidate(); $dashboard = CDashboardElement::find()->one(); $old_widget_count = $dashboard->getWidgets()->count(); $dashboard->edit(); $form = $create ? $dashboard->addWidget()->asForm() : $dashboard->getWidget(self::$update_widget)->edit(); $dialog = COverlayDialogElement::find()->one()->waitUntilReady(); if ($create) { $form->fill(['Type' => CFormElement::RELOADABLE_FILL('Web monitoring')]); } else { $values = $form->getValues(); } if ($cancel || !$save_dashboard) { $form->fill( [ 'Name' => 'Update Web monitoring widget', 'Refresh interval' => '10 minutes' ] ); } if ($cancel) { $dialog->query('button:Cancel')->one()->click(); } else { $form->submit(); } COverlayDialogElement::ensureNotPresent(); if (!$cancel) { $dashboard->getWidget($save_dashboard ? self::$update_widget : 'Update Web monitoring widget')->waitUntilReady(); } if ($save_dashboard) { $dashboard->save(); $this->assertMessage(TEST_GOOD, 'Dashboard updated'); } else { $dashboard->cancelEditing(); } $this->assertEquals($old_widget_count, $dashboard->getWidgets()->count()); // Check that updating widget form values did not change in frontend. if (!$create && !$save_dashboard) { $this->assertEquals($values, $dashboard->getWidget(self::$update_widget)->edit()->getValues()); COverlayDialogElement::find()->one()->close(); } } /** * Check Web monitoring widget layout. */ public function testDashboardWebMonitoringWidget_Layout() { // Open the create form. $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='. self::$dashboardid[self::DEFAULT_DASHBOARD])->waitUntilReady(); $dashboard = CDashboardElement::find()->one(); $dialog = $dashboard->edit()->addWidget(); $this->assertEquals('Add widget', $dialog->getTitle()); $form = $dialog->asForm(); $form->fill(['Type' => CFormElement::RELOADABLE_FILL('Web monitoring')]); // Check fields presence and default values. $form->checkValue([ 'Name' => '', 'Refresh interval' => 'Default (1 minute)', 'Show header' => true, 'Host groups'=> '', 'Exclude host groups'=> '', 'Hosts'=> '', 'Scenario tags' => 'And/Or', 'Show hosts in maintenance' => true ]); $this->assertTrue($form->getField('Name')->isAttributePresent(['maxlength' => '255', 'placeholder' => 'default'])); // Check dropdown options. $this->assertEquals($form->getField('Refresh interval')->getOptions()->asText(), [ 'Default (1 minute)', 'No refresh', '10 seconds', '30 seconds', '1 minute', '2 minutes', '10 minutes', '15 minutes' ]); $popup_menu_selector = 'xpath:.//button[contains(@class, "zi-chevron-down")]'; $host_groups = ['Host groups', 'Widget']; $hosts = ['Hosts', 'Widget', 'Dashboard']; foreach (['Host groups', 'Hosts'] as $label) { $field = $form->getField($label); // Check Select dropdown menu button. $menu_button = $field->query($popup_menu_selector)->asPopupButton()->one(); $this->assertEquals(($label === 'Host groups') ? $host_groups : $hosts, $menu_button->getMenu()->getItems()->asText() ); // After selecting Dashboard from dropdown menu, check hint and field value. if ($label === 'Hosts') { $menu_button->select('Dashboard'); $form->checkValue(['Hosts' => 'Dashboard']); $this->assertTrue($field->query('xpath:.//span[@data-hintbox-contents="Dashboard is used as data source."]') ->one()->isVisible() ); } // After selecting Widget from dropdown menu, check overlay dialog appearance and title. $menu_button->select('Widget'); $dialogs = COverlayDialogElement::find()->all(); $this->assertEquals('Widget', $dialogs->last()->waitUntilReady()->getTitle()); $dialogs->last()->close(true); } // After clicking on Select button, check overlay dialog appearance and title. foreach (['Host groups','Hosts'] as $label) { $field = $form->getField($label); $field->query('button:Select')->waitUntilCLickable()->one()->click(); $dialogs = COverlayDialogElement::find()->all(); $label = ($label === 'Item patterns') ? 'Items' : $label; $this->assertEquals($label, $dialogs->last()->waitUntilReady()->getTitle()); $dialogs->last()->close(true); } // Check that close button is present and clickable. $this->assertTrue($dialog->query('class:btn-overlay-close')->one()->isClickable()); // Check if footer buttons are present and clickable. $this->assertEquals(['Add', 'Cancel'], $dialog->getFooter()->query('button')->all() ->filter(CElementFilter::CLICKABLE)->asText() ); } /** * Check Web monitoring widget layout. * * @dataProvider getWidgetData * */ public function testDashboardWebMonitoringWidget_Create($data) { $this->checkWidgetForm($data); } /** * @dataProvider getWidgetData */ public function testDashboardWebMonitoringWidget_Update($data) { $this->checkWidgetForm($data, true); } /** * Test opening Web monitoring form and saving with no changes made. */ public function testDashboardWebMonitoringWidget_SimpleUpdate() { $this->checkNoChanges(); } /** * @dataProvider getCancelData */ public function testDashboardWebMonitoringWidget_Cancel($data) { $this->checkNoChanges($data['cancel_form'], $data['create_widget'], $data['save_dashboard']); } /** * Delete Web monitoring widget check. */ public function testDashboardWebMonitoringWidget_Delete() { $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='. self::$dashboardid[self::DASHBOARD_FOR_WIDGET_ACTIONS])->waitUntilReady(); $dashboard = CDashboardElement::find()->one()->edit(); $widget = $dashboard->getWidget('WebMonitoring for delete'); $dashboard->deleteWidget('WebMonitoring for delete'); $widget->waitUntilNotPresent(); $dashboard->save(); $this->assertMessage(TEST_GOOD, 'Dashboard updated'); // Check that widget is not present on dashboard. $this->assertFalse($dashboard->getWidget('WebMonitoring for delete', false)->isValid()); $this->assertEquals(0, CDBHelper::getCount('SELECT * FROM widget_field wf'. ' LEFT JOIN widget w'. ' ON w.widgetid=wf.widgetid'. ' WHERE w.name='.zbx_dbstr('WebMonitoring for delete') ) ); } }