1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
#!/usr/bin/python3 -cimport os, sys; os.execv(os.path.dirname(sys.argv[1]) + "/../common/pywrap", sys.argv)
#
# Copyright (C) 2013 Red Hat, Inc.
# SPDX-License-Identifier: LGPL-2.1-or-later
import time
import testlib
@testlib.skipBeiboot("no local overrides/config in beiboot mode")
@testlib.nondestructive
class TestMenu(testlib.MachineCase):
def testDarkThemeSwitcher(self):
b = self.browser
def switch_style(style_sel, prevPage="system", pixel_test=False):
b.switch_to_top()
b.click("#toggle-menu")
if pixel_test:
b.wait_visible("#toggle-menu-menu")
b.assert_pixels_in_current_layout("#toggle-menu-menu", "shell-toggle-menu")
b.click(style_sel)
b.enter_page(f"/{prevPage}")
self.login_and_go("/system")
switch_style("#dark", pixel_test=True)
b._wait_present("html.pf-v6-theme-dark")
switch_style("#light")
b.wait_not_present("html.pf-v6-theme-dark")
# Test overriding, switching only works on Chromium
if b.browser == "chromium":
# Light theme overrides browser defaults
b._set_emulated_media_theme("dark")
b.wait_not_present("html.pf-v6-theme-dark")
switch_style("#auto")
b._wait_present("html.pf-v6-theme-dark")
b._set_emulated_media_theme("light")
b.wait_not_present("html.pf-v6-theme-dark")
switch_style("#dark")
b._wait_present("html.pf-v6-theme-dark")
def testBasic(self):
b = self.browser
m = self.machine
# Add a link with a hash in it to test that this works
m.execute("mkdir -p /usr/local/share/cockpit/systemd; cp -rp /usr/share/cockpit/systemd/* /usr/local/share/cockpit/systemd")
m.execute(
"""sed -i '/"menu"/a "memory": { "label": "Memory", "path": "#/memory" },' /usr/local/share/cockpit/systemd/manifest.json""")
self.addCleanup(m.execute, "rm -r /usr/local/share/cockpit/systemd")
self.login_and_go("/system")
b.switch_to_top()
b.click('#toggle-docs')
b.click('button:contains("About Web Console")')
b.wait_in_text('#about-cockpit-modal', 'Cockpit is an interactive Linux server admin interface')
if not m.ostree_image:
pkgname = "cockpit" if m.image == "arch" else "cockpit-bridge"
b.wait_visible(f'#about-cockpit-modal:contains("{pkgname}")')
b.assert_pixels('.pf-v6-c-modal-box:has(#about-cockpit-modal)', "about-cockpit-modal",
mock={".pf-v6-c-content--dd": "v1234"})
b.click('.pf-v6-c-about-modal-box__close button')
b.wait_not_present('#about-cockpit-modal')
# Clicking inside the iframed pages should close the docs menu
b.click("#toggle-docs")
b.wait_visible("#toggle-docs-menu")
b.assert_pixels("#toggle-docs-menu", "shell-docs-menu")
b.enter_page("/system")
b.focus("#overview main")
b.switch_to_top()
b.wait_not_present("#toggle-docs-menu")
# Check that we can use a link with a hash in it
b.click_system_menu("/system/#/memory")
# Ensure that our tests pick up unhandled JS exceptions
b.switch_to_top()
b.go("/playground/exception")
# Test that subpages are correctly shown in the navigation (twice - once that only one page is shown as active)
b.wait_in_text("#host-apps .pf-m-current", "Development")
b.enter_page("/playground/exception")
b.click("button")
# UI should show the crash
b.switch_to_top()
b.wait_visible("#navbar-oops")
# normally called at the end of the test, should fail due to the oops
with self.assertRaisesRegex(AssertionError, "Cockpit shows an Oops"):
self.check_browser_errors()
# don't actually fail this test
b.allow_oops = True
def testSessionTimeout(self):
b = self.browser
m = self.machine
m.execute("printf '[Session]\nIdleTimeout = 1\n' >> /etc/cockpit/cockpit.conf")
# does not time out immediately
self.login_and_go()
time.sleep(20)
self.assertFalse(b.is_present("#session-timeout-modal"))
b.wait_visible("#hosts-sel")
# a mouse event resets the timer
b.enter_page("/system")
b.mouse("#system_information_hardware_text", "mousemove", 24, 24)
b.switch_to_top()
# 30s before the 1 min timeout the dialog pops up
time.sleep(35)
with b.wait_timeout(3):
b.wait_visible("#session-timeout-modal")
self.assertGreater(int(b.text("#session-timeout-modal .pf-v6-c-modal-box__body").split()[-2]), 15)
# click on "Continue session"
b.click("#session-timeout-modal footer button")
b.wait_not_present("#session-timeout-modal")
# now wait for timeout dialog again, but don't click; instead, wait for the full minute
time.sleep(30)
with b.wait_timeout(8):
b.wait_popup("session-timeout-modal")
self.assertGreater(int(b.text("#session-timeout-modal .pf-v6-c-modal-box__body").split()[-2]), 20)
time.sleep(30)
# that logs you out
b.wait_visible("#login")
b.wait_visible("#login-info-message")
b.wait_text("#login-info-message", "You have been logged out due to inactivity.")
def testKeyboardNavigation(self):
b = self.browser
self.login_and_go()
# initially shows host switcher
b.wait_visible("#hosts-sel")
self.assertEqual(b.eval_js("document.activeElement.tagName"), "BODY")
# press Tab once → "Skip to content" skiplink
b.key("Tab")
b.wait_js_cond("document.activeElement.parentElement.classList.contains('pf-v6-c-skip-to-content')")
self.assertEqual(b.eval_js("document.activeElement.textContent"), "Skip to content")
self.assertEqual(b.eval_js("document.activeElement.getAttribute('href')"), "#content")
b.key("Enter")
b.wait_js_cond("document.activeElement.getAttribute('id') === 'content'")
self.assertEqual(b.eval_js("document.activeElement.tagName"), "DIV")
self.assertEqual(b.eval_js("document.activeElement.getAttribute('id')"), "content")
# reset
b.reload()
b.wait_visible("#hosts-sel")
b.wait_text("#super-user-indicator", "Administrative access")
# press Tab twice → "Skip main navigation" skiplink
b.key("Tab")
self.assertEqual(b.eval_js("document.activeElement.textContent"), "Skip to content")
b.key("Tab")
self.assertEqual(b.eval_js("document.activeElement.textContent"), "Skip main navigation")
b.key("Enter")
b.wait_js_cond("document.activeElement.tagName === 'NAV'")
self.assertEqual(b.eval_js("document.activeElement.getAttribute('id')"), "hosts-sel")
# actually skips the page menu and goes on to top nav bar; where exactly depends on whether
# the host switcher is enabled.
b.key("Tab")
if self.multihost_enabled:
b.wait_js_cond("document.activeElement.getAttribute('id') === 'host-toggle'")
b.key("Tab")
b.wait_js_cond("document.activeElement.textContent === 'Administrative access'")
# reset
b.reload()
b.wait_visible("#hosts-sel")
# without skip links, tabbing goes through page menu
b.key("Tab", repeat=5)
# different browsers behave a bit different here -- Firefox is at "Overview", Chromium at "Logs"
b.wait_js_cond("document.activeElement.classList.contains('pf-v6-c-nav__link')")
def testCustomLandingPage(self):
b = self.browser
m = self.machine
# # Make the logs page the default page
m.write("/etc/cockpit/systemd.override.json", '{"menu":{"index":{"order":100},"logs":{"order":1}}}')
self.login_and_go()
b.wait_js_cond('window.location.pathname == "/system/logs"')
if __name__ == '__main__':
testlib.test_main()
|