Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Dockerfile.selenium
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM python:3.14.3-slim

WORKDIR /tests

COPY tests/requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY tests/ .

ENTRYPOINT [ "pytest", "-v" ]
36 changes: 36 additions & 0 deletions docker-compose.selenium.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
services:
web:
build:
context: .
dockerfile: Dockerfile
command: >
sh -c "sed -i 's|let recaptcha_site_key = .*|let recaptcha_site_key = \"${RECAPTCHA_SITE_KEY}\"|' /app/templater/static/js/main.js &&
sed -i 's|recaptcha_key = .*|recaptcha_key = \"${RECAPTCHA_SECRET_KEY}\"|' /app/config.ini &&
sed -i 's|RECAPTCHA_SITE_KEY|${RECAPTCHA_SITE_KEY}|' /app/templater/templates/layout.jinja2 &&
sed -i 's|mongo_uri = .*|mongo_uri = mongodb://db:27017/templater|' /app/config.ini &&
sed -i '/def recaptcha/,/return/c\def recaptcha(request):\\n return True' /app/templater/views/default.py &&
python3 -u runapp.py"
ports:
- "127.0.0.1:8080:5000"
depends_on:
- db

db:
image: mongo:8-noble

tests:
build:
context: .
dockerfile: Dockerfile.selenium
depends_on:
- web

selenium-hub:
image: selenium/hub:4.41.0-20260222
ports:
- "127.0.0.1:4445:4444"

chrome-node:
image: selenium/node-chrome:145.0-20260222
environment:
- SE_EVENT_BUS_HOST=selenium-hub
27 changes: 27 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest
from selenium import webdriver
from selenium.webdriver.remote.file_detector import LocalFileDetector

GRID_URL = "http://selenium-hub:4444/wd/hub"
BASE_URL = "http://web:5000"

@pytest.fixture
def driver():
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.enable_downloads = True

driver = webdriver.Remote(
command_executor=GRID_URL,
options=options
)
driver.file_detector = LocalFileDetector()

yield driver

driver.quit()

@pytest.fixture
def base_url():
return BASE_URL
Binary file added tests/data/templates/template.docx
Binary file not shown.
51 changes: 51 additions & 0 deletions tests/pages/base_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from selenium import webdriver
from selenium.common import (
ElementNotInteractableException,
NoSuchElementException,
StaleElementReferenceException,
)

from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver import ActionChains

class BasePage:
def __init__(self, driver) -> None:
self.driver = driver
self.wait = WebDriverWait(
driver,
timeout=10,
poll_frequency=2,
ignored_exceptions=[
NoSuchElementException,
StaleElementReferenceException,
ElementNotInteractableException,
],
)

def element(self, locator: tuple) -> WebElement:
self.wait.until(lambda driver: driver.find_element(*locator))
return self.driver.find_element(*locator)

def elements(self, locator: tuple) -> list[WebElement]:
return self.driver.find_elements(*locator)

def hover(self, locator: tuple) -> None:
element = self.element(locator)
ActionChains(self.driver).move_to_element(element).perform()

def click(self, locator: tuple) -> None:
element = self.element(locator)
element.click()

def type(self, locator: tuple, value: str) -> None:
element = self.element(locator)
element.clear()
element.send_keys(value)

def text(self, locator: tuple) -> str:
element = self.element(locator)
return element.text

def open(self, url: str) -> None:
self.driver.get(url)
36 changes: 36 additions & 0 deletions tests/pages/upload_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

from .base_page import BasePage

class UploadPage(BasePage):
template_input_by = (By.CSS_SELECTOR, "#template-file")
template_upload_btn_by = (By.CSS_SELECTOR, "#btn-upload-template")

tempate_preview_by = (By.CSS_SELECTOR, "#preview-container")

template_submit_btn_by = (By.CSS_SELECTOR, "#btn-use-template")
template_reupload_btn_by = (By.CSS_SELECTOR, "#btn-upload-template")

datatable_tab_pill_by = (By.ID, "pills-datatable-tab")

def upload_template(self, filepath):
self.element(self.template_input_by).send_keys(filepath)

def click_upload(self):
self.click(self.template_upload_btn_by)

def wait_preview(self):
return self.wait.until(EC.visibility_of_element_located(self.tempate_preview_by))

def click_use_template(self):
self.click(self.template_submit_btn_by)

def wait_until_datatable_pill_active(self):
self.wait.until(
EC.text_to_be_present_in_element_attribute(
self.datatable_tab_pill_by,
"aria-selected",
"true"
)
)
Binary file added tests/requirements.txt
Binary file not shown.
23 changes: 23 additions & 0 deletions tests/test_upload_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import os
from pages.upload_page import UploadPage
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

def test_upload_template(driver, base_url):
page = UploadPage(driver)

template_path = os.path.abspath("data/templates/template.docx")
print("PATH:", template_path)

page.open(base_url)

page.upload_template(template_path)

page.click_upload()

preview = page.wait_preview()
assert preview is not None

page.click_use_template()

page.wait_until_datatable_pill_active()