from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from apps.applets.models import Applet from apps.lyric.models import User from .base import FunctionalTest def _setup_palette_applet(): Applet.objects.get_or_create( slug="palette", defaults={"name": "Palette", "context": "dashboard"}, ) class PalettePreviewTest(FunctionalTest): """Clicking a swatch previews the palette on the whole body.""" def setUp(self): super().setUp() _setup_palette_applet() User.objects.get_or_create(email="preview@test.io") self.create_pre_authenticated_session("preview@test.io") self.browser.get(self.live_server_url) def _click_non_active_swatch(self): swatch = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".palette-item:not(:has(.swatch.active)) .swatch", ) ) swatch.click() return swatch def test_clicking_swatch_adds_preview_class_to_body(self): swatch = self._click_non_active_swatch() palette_name = swatch.get_attribute("data-palette") self.wait_for( lambda: self.assertIn( palette_name, self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) def test_body_has_only_preview_palette_during_preview(self): # Original palette class is swapped out — only the preview class is on body swatch = self._click_non_active_swatch() palette_name = swatch.get_attribute("data-palette") self.wait_for( lambda: self.assertIn( palette_name, self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) self.wait_for( lambda: self.assertNotIn( "palette-default", self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) def test_clicking_elsewhere_reverts_body_to_original_palette(self): swatch = self._click_non_active_swatch() palette_name = swatch.get_attribute("data-palette") self.wait_for( lambda: self.assertIn( palette_name, self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) # Click outside the applet self.browser.find_element(By.CSS_SELECTOR, "h1, h2").click() self.wait_for( lambda: self.assertNotIn( palette_name, self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) # Original palette restored self.assertIn( "palette-default", self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) def test_swatch_gets_previewing_class_on_click(self): self._click_non_active_swatch() self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".swatch.previewing") ) def test_previewing_class_removed_on_dismiss(self): self._click_non_active_swatch() self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".swatch.previewing") ) self.browser.find_element(By.CSS_SELECTOR, "h1, h2").click() self.wait_for( lambda: self.assertEqual( len(self.browser.find_elements(By.CSS_SELECTOR, ".swatch.previewing")), 0, ) ) def test_auto_dismiss_after_ten_seconds(self): swatch = self._click_non_active_swatch() palette_name = swatch.get_attribute("data-palette") self.wait_for( lambda: self.assertIn( palette_name, self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) # After 10s the preview should clear automatically self.wait_for_slow( lambda: self.assertNotIn( palette_name, self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ), timeout=15, ) class PaletteOkButtonTest(FunctionalTest): """OK btn (unlocked) / × btn (locked) appear centered on clicked swatch.""" def setUp(self): super().setUp() _setup_palette_applet() User.objects.get_or_create(email="okbtn@test.io") self.create_pre_authenticated_session("okbtn@test.io") self.browser.get(self.live_server_url) def test_ok_btn_absent_before_click(self): btns = self.browser.find_elements(By.CSS_SELECTOR, ".swatch .btn-confirm") self.assertEqual(len([b for b in btns if b.is_displayed()]), 0) def test_clicking_unlocked_swatch_shows_ok_btn_inside_swatch(self): swatch = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".palette-item:not(:has(.swatch.active)):not(:has(.swatch.locked)) .swatch", ) ) swatch.click() ok = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".swatch.previewing .btn-confirm" ) ) self.assertTrue(ok.is_displayed()) def test_clicking_locked_swatch_shows_disabled_times_btn(self): locked = self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, ".swatch.locked") ) locked.click() disabled = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".swatch.previewing .btn-disabled" ) ) self.assertIn("×", disabled.text) def test_clicking_ok_commits_palette_and_no_reload(self): self.browser.execute_script("window._no_reload = true") swatch = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".palette-item:not(:has(.swatch.active)):not(:has(.swatch.locked)) .swatch", ) ) palette_name = swatch.get_attribute("data-palette") swatch.click() ok = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".swatch.previewing .btn-confirm" ) ) ok.click() # Body ends up with only the new palette (preview cleared, committed) self.wait_for( lambda: self.assertNotIn( "palette-default", self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) self.wait_for( lambda: self.assertIn( palette_name, self.browser.find_element(By.TAG_NAME, "body").get_attribute("class"), ) ) self.assertTrue(self.browser.execute_script("return window._no_reload === true")) def test_btn_disappears_on_dismiss(self): swatch = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".palette-item:not(:has(.swatch.active)):not(:has(.swatch.locked)) .swatch", ) ) swatch.click() self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, ".swatch.previewing .btn-confirm" ) ) self.browser.find_element(By.CSS_SELECTOR, "h1, h2").click() self.wait_for( lambda: self.assertEqual( len([b for b in self.browser.find_elements( By.CSS_SELECTOR, ".swatch .btn-confirm" ) if b.is_displayed()]), 0, ) ) class PaletteTooltipTest(FunctionalTest): """Clicking a swatch shows a tooltip in #id_tooltip_portal.""" def setUp(self): super().setUp() _setup_palette_applet() self.user, _ = User.objects.get_or_create(email="palettett@test.io") self.create_pre_authenticated_session("palettett@test.io") self.browser.get(self.live_server_url) def _click_swatch(self, selector=".swatch"): swatch = self.wait_for( lambda: self.browser.find_element(By.CSS_SELECTOR, selector) ) swatch.click() return swatch def test_clicking_swatch_shows_tooltip_portal(self): self._click_swatch() portal = self.wait_for( lambda: self.browser.find_element(By.ID, "id_tooltip_portal") ) self.assertTrue(portal.is_displayed()) def test_tooltip_title_is_colored_ter_user(self): self._click_swatch() title = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_tooltip_portal .tt-title" ) ) ter_user = self.browser.execute_script( "return getComputedStyle(document.body).getPropertyValue('--terUser').trim()" ) r, g, b = [int(x.strip()) for x in ter_user.split(",")] color = self.browser.execute_script( "return getComputedStyle(arguments[0]).color", title ) self.assertIn(f"rgb({r}, {g}, {b})", color) def test_tooltip_shows_shoptalk(self): self._click_swatch() self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_tooltip_portal .tt-shoptalk" ) ) def test_unlocked_swatch_shows_lock_open_and_unlocked(self): self._click_swatch( ".palette-item:not(:has(.swatch.locked)) .swatch" ) lock_line = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_tooltip_portal .tt-lock" ) ) self.assertIn("Unlocked", lock_line.text) self.assertTrue(lock_line.find_elements(By.CSS_SELECTOR, ".fa-lock-open")) def test_locked_swatch_shows_lock_and_locked(self): self._click_swatch(".swatch.locked") lock_line = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_tooltip_portal .tt-lock" ) ) self.assertIn("Locked", lock_line.text) self.assertTrue(lock_line.find_elements(By.CSS_SELECTOR, ".fa-lock")) def test_unlocked_tooltip_shows_default_label(self): self._click_swatch(".palette-item:not(:has(.swatch.locked)) .swatch") lock_line = self.wait_for( lambda: self.browser.find_element( By.CSS_SELECTOR, "#id_tooltip_portal .tt-lock" ) ) self.assertIn("Default", lock_line.text) def test_tooltip_dismisses_on_click_outside(self): self._click_swatch() self.wait_for( lambda: self.assertTrue( self.browser.find_element(By.ID, "id_tooltip_portal").is_displayed() ) ) self.browser.find_element(By.CSS_SELECTOR, "h1, h2").click() self.wait_for( lambda: self.assertFalse( self.browser.find_element(By.ID, "id_tooltip_portal").is_displayed() ) ) class SiteThemeTest(FunctionalTest): def test_page_renders_with_earthman_palette(self): self.browser.get(self.live_server_url) body = self.browser.find_element(By.TAG_NAME, "body") self.assertIn("palette-default", body.get_attribute("class")) class LightPaletteTest(FunctionalTest): def test_light_palette_tooltip_uses_white_background(self): user, _ = User.objects.get_or_create(email="light@example.com") user.palette = "palette-oblivion-light" user.save() self.create_pre_authenticated_session("light@example.com") self.browser.get(self.live_server_url + "/dashboard/wallet/") body = self.browser.find_element(By.TAG_NAME, "body") tooltip_bg = self.browser.execute_script( "return getComputedStyle(arguments[0]).getPropertyValue('--tooltip-bg').trim()", body, ) self.assertEqual(tooltip_bg, "255, 255, 255")