trainlog/tests/test_web_exercises_browser.py

96 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""Disposable real-browser smoke test for Web Exercises V1."""
import os
import signal
import socket
import subprocess
import tempfile
import time
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
BUILD = ROOT / "build" / "tui"
GECKO = Path(os.environ.get(
"TRAINLOG_GECKODRIVER", "/home/fy59/.cache/trainlog/web-e2e-tools/geckodriver"))
class BrowserExercisesTest(unittest.TestCase):
def test_create_edit_retire_at_desktop_and_mobile_widths(self):
if not GECKO.is_file():
self.skipTest("pinned geckodriver unavailable")
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.service import Service
from selenium.common.exceptions import StaleElementReferenceException
from selenium.webdriver.support.ui import Select, WebDriverWait
with tempfile.TemporaryDirectory(prefix="trainlog-web-exercises-") as directory:
temporary = Path(directory)
data = temporary / "data"
config = temporary / "config"
data.mkdir()
config.mkdir()
with socket.socket() as reserved:
reserved.bind(("127.0.0.1", 0))
port = reserved.getsockname()[1]
environment = os.environ.copy()
environment.update({"XDG_DATA_HOME": str(data), "XDG_CONFIG_HOME": str(config),
"XDG_CACHE_HOME": str(temporary / "cache")})
server = subprocess.Popen(
[str(BUILD / "trainlog"), "--web", "--port", str(port)],
env=environment, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
start_new_session=True,
)
driver = None
try:
for _ in range(200):
with socket.socket() as probe:
if probe.connect_ex(("127.0.0.1", port)) == 0:
break
time.sleep(0.025)
options = webdriver.FirefoxOptions()
options.add_argument("-headless")
driver = webdriver.Firefox(options=options, service=Service(str(GECKO)))
wait = WebDriverWait(driver, 15, ignored_exceptions=(StaleElementReferenceException,))
driver.set_window_size(1440, 1000)
driver.get(f"http://127.0.0.1:{port}/exercices")
wait.until(lambda page: page.find_element(By.TAG_NAME, "h1").text == "Exercices")
self.assertEqual(0, driver.execute_script(
"return document.documentElement.scrollWidth-document.documentElement.clientWidth"))
driver.find_element(By.XPATH, "//button[contains(., 'Nouvel exercice')]").click()
wait.until(lambda page: page.current_url.endswith("/exercices/nouveau"))
name = wait.until(lambda page: page.find_element(By.CSS_SELECTOR, ".exercise-form input"))
name.send_keys("Exercice visuel jetable")
Select(driver.find_element(By.CSS_SELECTOR, ".exercise-form select")).select_by_index(1)
name.send_keys(Keys.ENTER)
wait.until(lambda page: page.find_element(By.TAG_NAME, "h1").text == "Exercice visuel jetable")
driver.find_element(By.XPATH, "//button[normalize-space(.)='Modifier']").click()
name = wait.until(lambda page: page.find_element(By.CSS_SELECTOR, ".exercise-form input"))
name.clear()
name.send_keys("Exercice visuel renommé")
name.send_keys(Keys.ENTER)
wait.until(lambda page: page.find_element(By.TAG_NAME, "h1").text == "Exercice visuel renommé")
driver.set_window_size(390, 844)
self.assertEqual(0, driver.execute_script(
"return document.documentElement.scrollWidth-document.documentElement.clientWidth"))
driver.find_element(By.XPATH, "//button[contains(., 'Retirer du catalogue')]").click()
wait.until(lambda page: page.find_element(By.CSS_SELECTOR, "[role='alertdialog']"))
driver.find_element(By.XPATH, "//*[@role='alertdialog']//button[normalize-space(.)='Retirer']").click()
wait.until(lambda page: page.find_element(By.TAG_NAME, "h1").text == "Exercices")
self.assertNotIn("Exercice visuel renommé", driver.page_source)
finally:
if driver is not None:
driver.quit()
os.killpg(server.pid, signal.SIGTERM)
server.wait(timeout=10)
if __name__ == "__main__":
unittest.main()