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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,4 @@ test-logs.txt
smoke-logs.txt
extract_links.py.py
extract_links.py
qa/screenshots/
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ services:
- ../website2022/:/website
stop_signal: SIGKILL

playwright:
build:
context: .
dockerfile: docker/Dockerfile.playwright
working_dir: /code/qa
volumes:
- .:/code
network_mode: host
profiles:
- qa

# mailman-core:
# image: maxking/mailman-core
# stop_grace_period: 5s
Expand Down
3 changes: 3 additions & 0 deletions docker/Dockerfile.playwright
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM mcr.microsoft.com/playwright/python:v1.58.0-noble

RUN pip install --quiet --root-user-action=ignore pytest-playwright
3 changes: 3 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ alias shell := console
@test_pytest_lf: ## runs last failed pytest tests
-docker compose run --rm -e DEBUG_TOOLBAR="False" web pytest -s --create-db --lf

@qa *args: ## runs Playwright QA tests against staging (pass --env=production for prod)
docker compose run --rm playwright pytest --env=staging -v {{ args }}

@test_pytest_asciidoctor: ## runs asciidoctor tests
-docker compose run --rm -e DEBUG_TOOLBAR="False" web pytest -m asciidoctor -s --create-db

Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
DJANGO_SETTINGS_MODULE=config.test_settings
addopts = --reuse-db --no-migrations
norecursedirs = .git config node_modules scss static templates static_deploy
uploads frontend media kube docker config content .github .pytest_cache venv
uploads frontend media kube docker config content .github .pytest_cache venv qa
python_files = test_*.py
markers=
asciidoctor: indicating test involving local asciidoctor rendering
77 changes: 77 additions & 0 deletions qa/config_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import re
import time
from urllib.parse import urljoin, urlencode


def get_base_url(base_url):
return base_url or "https://www.boost.org"


def build_url(base_url, path="/", cachebust=False, params=None):
url = urljoin(base_url.rstrip("/") + "/", path.lstrip("/"))
query_params = {}
if cachebust:
query_params["cachebust"] = str(int(time.time() * 1000))
if params:
query_params.update(params)
if query_params:
url += ("&" if "?" in url else "?") + urlencode(query_params)
return url


class UrlPatterns:
homepage = "/"
libraries = "/libraries/"
releases = "/releases/"
documentation = "/doc/libs/"
community = "/community/"
search = "/search/"

@staticmethod
def doc_libs_version(version="1_85_0"):
return f"/doc/libs/{version}/"

@staticmethod
def release_notes(version="1_85_0"):
return f"/doc/libs/{version}/libs/release_notes/"


class ExpectedUrlPatterns:
after_cta_click = re.compile(r"libraries|releases|docs|learn|download", re.I)
after_search = re.compile(r"search|results|q=", re.I)
after_logo_click = re.compile(r"/?$")
github_boost = re.compile(r"github\.com/boostorg", re.I)
download_site = re.compile(
r"archives\.boost\.io|github\.com/boostorg/boost/releases|download|release",
re.I,
)
community_links = re.compile(r"github.com.*issues|discourse|lists.boost.org", re.I)


url_patterns = UrlPatterns()
expected_url_patterns = ExpectedUrlPatterns()


class TestData:
search_terms = {
"working": "asio",
"alternative": "algorithm",
}
download_files = {
"tar_gz": re.compile(r"boost_1_74_0\.tar\.gz$"),
"zip": re.compile(r"boost_1_85_0\.zip$"),
"supported": re.compile(r"\.(zip|tar\.gz|tar\.bz2|7z|exe)$"),
}
timeouts = {
"short": 5000,
"medium": 15000,
"long": 30000,
"download": 60000,
}
viewport = {
"desktop": {"width": 1280, "height": 720},
"mobile": {"width": 800, "height": 600},
}


test_data = TestData()
44 changes: 44 additions & 0 deletions qa/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import pytest


def pytest_addoption(parser):
parser.addoption(
"--env",
default="staging",
choices=["local", "staging", "production"],
help="Test environment",
)


@pytest.fixture(scope="session")
def base_url(request):
env = request.config.getoption("--env")
urls = {
"local": "http://localhost:8000",
"staging": "https://www.stage.boost.org",
"production": "https://www.boost.org",
}
return urls[env]


@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
return {**browser_context_args, "viewport": {"width": 1280, "height": 720}}


@pytest.fixture(autouse=True)
def screenshot_on_failure(page, request):
yield
if request.node.rep_call.failed if hasattr(request.node, "rep_call") else False:
import pathlib

pathlib.Path("screenshots").mkdir(exist_ok=True)
name = request.node.name.replace(" ", "_")
page.screenshot(path=f"screenshots/{name}_failure.png", full_page=True)


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
setattr(item, f"rep_{rep.when}", rep)
Loading
Loading