#!/usr/bin/python3 # # Copyright (C) 2021 Red Hat, Inc. # SPDX-License-Identifier: LGPL-2.1-or-later from anacondalib import VirtInstallMachineCase, pixel_tests_ignore from bugzilla_mock import ( install_mock_bugzilla, set_mock_bugzilla_bugs, uninstall_mock_bugzilla, ) from installer import Installer from testlib import nondestructive, test_main # pylint: disable=import-error from utils import get_pretty_name @nondestructive class TestBasic(VirtInstallMachineCase): def testNavigation(self): """ Description: Verifies that all steps in the installer are accessible via 'Next' button Expected results: - All steps are reachable by clicking on the 'Next' button """ b = self.browser m = self.machine i = Installer(b, m) i.open() self.assertIn( b.attr("#app .pf-v6-c-page", "data-debug").lower(), ["false", "true"] ) i.check_prerelease_info() # Do not start the installation in non-destructive tests as this performs non revertible changes # with the pages basically empty of common elements (as those are provided by the top-level installer widget) # we at least iterate over them to check this works as expected i.reach(i.steps.REVIEW) # Ensure that the 'actual' UI process is running/ self.assertIn("/usr/libexec/anaconda/webui-desktop", m.execute("ps aux")) def testSidebarNavigation(self): """ Description: Verifies navigation to previous steps using the sidebar Expected results: - All previous steps are reachable by clicking on the sidebar - Later steps are disabled in the sidebar """ b = self.browser m = self.machine i = Installer(b, m) i.open() i.check_prerelease_info() # Test that clicking on current step does not break navigation i.click_step_on_sidebar() i.reach(i.steps.REVIEW) # Test going back steps = [ i.steps.ACCOUNTS, i.steps.STORAGE_CONFIGURATION, i.steps.INSTALLATION_METHOD, i.steps.LANGUAGE, ] for step in steps: if step not in i.steps.hidden_steps: i.click_step_on_sidebar(step) i.reach(i.steps.REVIEW) # Check disabling of later steps when going back i.reach_on_sidebar(i.steps.LANGUAGE) for step in [ i.steps.ACCOUNTS, i.steps.STORAGE_CONFIGURATION, i.steps.INSTALLATION_METHOD, i.steps.REVIEW, ]: i.check_sidebar_step_disabled(step) def testAboutModal(self): """ Description: Test the About modal Expected results: - The About modal is shown when clicking on the "About" item in the kebab menu - The About modal contains the correct information - The About modal can be closed """ b = self.browser m = self.machine i = Installer(b, m) i.open() # Obtain pretty name and versions from the CLI pretty_name = get_pretty_name(m) backend_version = m.execute("anaconda --version | cut -d ' ' -f 2 | tail -1").strip() webui_version = m.execute("cat /usr/local/share/cockpit/anaconda-webui/VERSION.txt").strip().split()[0] # Click on the kebab b.click("#toggle-kebab") # Click on the "About" item from the dropdown b.click("#about-modal-dropdown-item-about") # Expect PRETTY_NAME to be shown in modal title b.wait_in_text("#about-modal-title", pretty_name) # Expect "Powered by Anaconda" to be shown in modal subtitle b.wait_in_text("#about-modal-subtitle", "Powered by Anaconda") # Expect About modal body to be shown b.wait_in_text("#backend-dt", "Anaconda") b.wait_in_text("#backend-dd", backend_version) b.wait_in_text("#webui-dt", "Anaconda WebUI") b.wait_in_text("#webui-dd", webui_version) # Expect button link for Anaconda project page to be shown b.wait_in_text("#anaconda-page-button", "Anaconda project page") # Pixel test the language step b.assert_pixels( ".pf-v6-c-about-modal-box", "about-modal", ignore=[*pixel_tests_ignore, "#backend-dd","#webui-dd", "#about-modal-title"], ) # Close about modal b.click(".pf-v6-c-button[aria-label='Close Dialog']") b.wait_not_present("#about-modal") def testReportIssue(self): """ Description: Test the Report Issue modal Expected results: - The Report Issue modal is shown when clicking on the "Report issue" item in the kebab menu - The Report Issue modal contains the correct information - The Report Issue modal can be closed """ b = self.browser m = self.machine i = Installer(b, m) i.open() b.wait_not_present("#user-issue-bz-report-modal") b.click("#toggle-kebab") b.click("#about-modal-dropdown-item-report") b.wait_visible("#user-issue-bz-report-modal") b.click("#user-issue-dialog-cancel-btn") b.wait_not_present("#user-issue-bz-report-modal") def testJsErrorHandling(self): """ Description: Test that the Error modal is shown when a JS error occurs Setup: - Trigger a JS error Expected results: - The Error modal is shown - The Error modal contains the correct information - The Journal contains the exception """ b = self.browser m = self.machine i = Installer(b, m) i.open() b.wait_not_present("#critical-error-bz-report-modal") b.eval_js("window.setTimeout(function() { myNonExistingFunction()}, 0);") b.wait_in_text("#critical-error-bz-report-modal-details", "myNonExistingFunction is not defined") b.wait_visible("button:contains('Next'):disabled") b.assert_pixels( "#critical-error-bz-report-modal", "js-error-modal", ignore=["#critical-error-bz-report-modal-review-log"] ) # Check the exception is present in the journal self.assertIn( "myNonExistingFunction is not defined", m.execute("journalctl -b -t anaconda-webui") ) def _open_critical_error_report_step1(self): b = self.browser i = Installer(b, self.machine) i.open() b.wait_not_present("#critical-error-bz-report-modal") b.eval_js("window.setTimeout(function() { myNonExistingFunction()}, 0);") b.wait_in_text("#critical-error-bz-report-modal-details", "myNonExistingFunction is not defined") b.wait_visible("#critical-error-bugzilla-apikey") def testBugzillaDuplicateDetection(self): """ Description: Test duplicate detection in the Bugzilla reporting flow Setup: - Install a mock python-bugzilla package that returns canned open bugs - Trigger a JS error to open the critical-error report modal Expected results: - After API key validation, potential duplicates are shown - Users can continue to create a new report - Back navigation returns to the duplicate list when matches exist - When no duplicates are found, the duplicates step is skipped """ b = self.browser m = self.machine dialog = "#critical-error-bz-report-modal" mock_bugs = [ { "id": 2428210, "summary": "WebUI: org.fedoraproject.Anaconda.BootloaderInstallationError: boot loader install failed", "status": "NEW", }, { "id": 2491005, "summary": ( "Installation of the system failed: Installing boot loader" " org.fedoraproject.Anaconda.BootloaderInstallationError:" " boot loader install failed" ), "status": "NEW", }, { "id": 2485664, "summary": ( "Installation of the system failed: Installing boot loader" " org.fedoraproject.Anaconda.BootloaderInstallationError:" " boot loader install failed" ), "status": "NEW", }, ] install_mock_bugzilla(m, mock_bugs) self.addCleanup(uninstall_mock_bugzilla, m) self._open_critical_error_report_step1() # Step 1: enter API key and continue b.set_input_text("#critical-error-bugzilla-apikey", "fake-valid-api-key") b.wait_visible(f"{dialog} button:contains('Next'):not([disabled])") b.click(f"{dialog} button:contains('Next')") # Step 2: duplicates list b.wait_visible("#critical-error-duplicates-alert") b.wait_in_text("#critical-error-duplicates-alert", "Potential duplicate bugs found") b.wait_visible("#critical-error-duplicates-list") b.wait_in_text("#critical-error-duplicate-2428210", "#2428210") b.wait_in_text("#critical-error-duplicate-2428210", "[NEW]") b.wait_in_text("#critical-error-duplicate-2491005", "#2491005") b.wait_in_text("#critical-error-duplicate-2485664", "#2485664") b.wait_visible("#critical-error-continue-new-btn") # Continue to create a new report (step 3) b.click("#critical-error-continue-new-btn") b.wait_visible("#critical-error-bug-summary") b.wait_not_present("#critical-error-duplicates-list") b.wait_visible(f"{dialog} button:contains('Report issue')") # Back returns to the duplicates step when matches exist b.click(f"{dialog} button:contains('Back')") b.wait_visible("#critical-error-duplicates-list") b.wait_not_present("#critical-error-bug-summary") # Back from duplicates returns to API key entry b.click(f"{dialog} button:contains('Back')") b.wait_visible("#critical-error-bugzilla-apikey") b.wait_not_present("#critical-error-duplicates-list") # No duplicates: skip straight to bug details set_mock_bugzilla_bugs(m, []) b.set_input_text("#critical-error-bugzilla-apikey", "fake-valid-api-key") b.click(f"{dialog} button:contains('Next')") b.wait_visible("#critical-error-bug-summary") b.wait_not_present("#critical-error-duplicates-list") b.wait_visible(f"{dialog} button:contains('Report issue')") # Back skips the empty duplicates step and returns to API key entry b.click(f"{dialog} button:contains('Back')") b.wait_visible("#critical-error-bugzilla-apikey") b.wait_not_present("#critical-error-bug-summary") if __name__ == '__main__': test_main()