e2e_tests/pytest_abra/custom_fixtures.py

163 lines
4.8 KiB
Python

# This file is registered as a pytest plugin, meaning it will automatically loaded.
# All fixtures in this file will be available without manual loading.
import os
import re
from datetime import datetime, timedelta
from pathlib import Path
from typing import Generator, Protocol, TypedDict
import pytest
from dotenv import dotenv_values
from icecream import ic # type: ignore
from imbox import Imbox # type: ignore
from playwright.sync_api import APIRequestContext, BrowserContext, Playwright, expect
from pytest import Parser
from pytest_abra import BaseUrl, DirManager, EnvFile
def pytest_addoption(parser: Parser):
parser.addoption("--runner_index", action="store", type=int)
parser.addoption("--output_dir", action="store", type=Path)
parser.addoption("--session_id", action="store", type=str)
parser.addoption("--timeout", action="store", type=int, default=20_000)
@pytest.fixture(autouse=True)
def set_expect_timeout(request):
TIMEOUT = request.config.getoption("--timeout")
expect.set_options(timeout=TIMEOUT)
@pytest.fixture
def context(context: BrowserContext, request) -> BrowserContext:
# note: because this has the existing context fixture as an argument, it is ensured
# that the original fixture is called first and then overwritten by this custom one.
TIMEOUT = request.config.getoption("--timeout")
LOCALE = {"Accept-Language": "de_DE"}
context.set_default_timeout(TIMEOUT)
context.set_extra_http_headers(LOCALE)
return context
@pytest.fixture(scope="session")
def DIR(request) -> DirManager:
"""Fixture holding test directories
DIR.OUTPUT
DIR.SESSION
DIR.RECORDS
DIR.STATES
DIR.RESULTS"""
output_dir = request.config.getoption("--output_dir")
assert output_dir, "pytest argument --output_dir not set"
session_id = request.config.getoption("--session_id")
assert session_id, "pytest argument --session_id not set"
dirmanager = DirManager(output_dir=output_dir, session_id=session_id)
dirmanager.create_all_dirs()
return dirmanager
@pytest.fixture(scope="session")
def env_files(DIR: DirManager) -> list[EnvFile]:
"""list of EnvFile objects created from the given env files"""
env_files_dict: dict[int, EnvFile] = dict()
for env_path in DIR.ENV_FILES.glob("*.env"):
config: dict[str, str] = dotenv_values(env_path) # type: ignore
env_type = config["TYPE"]
result = re.search(r"(\d+)-*", env_path.name)
assert result
runner_index = int(result[1])
env_files_dict[runner_index] = EnvFile(env_path=env_path, env_config=config, env_type=env_type)
keys = list(env_files_dict.keys())
keys.sort()
return [env_files_dict[key] for key in keys]
@pytest.fixture(scope="session")
def env_config(request, env_files: list[EnvFile]) -> dict[str, str]:
"""Current env_config"""
runner_index = request.config.getoption("--runner_index")
return env_files[runner_index].env_config
@pytest.fixture(scope="session")
def URL(env_config: dict[str, str]) -> BaseUrl:
"""BaseUrl object based on current DOMAIN"""
return BaseUrl(netloc=env_config["DOMAIN"])
@pytest.fixture(scope="session")
def imap_client() -> None:
"""imap email client using credentials from environment variables"""
assert os.environ["IMAP_HOST"]
assert os.environ["IMAP_PORT"]
assert os.environ["IMAP_USER"]
assert os.environ["IMAP_PASS"]
imbox = Imbox(
hostname=os.environ["IMAP_HOST"],
port=os.environ["IMAP_PORT"],
username=os.environ["IMAP_USER"],
password=os.environ["IMAP_PASS"],
ssl=True,
ssl_context=None,
starttls=False,
)
yield imbox
imbox.logout()
class Body(TypedDict):
plain: list
html: list
class Message(Protocol):
sent_from: list
sent_to: list
subject: str
headers: list
date: str
body: Body
@pytest.fixture
def imap_recent_messages(imap_client: Imbox) -> list[Message]:
"""Get all messages from [n_minutes] ago till now.
# iterate with
for uid, message in messages:
print(uid, message.subject, message.date)"""
N_MINUTES = 30
n_minutes_ago = datetime.now() - timedelta(minutes=N_MINUTES)
uids: list[bytes] = []
messages: list[Message] = []
# for uid, message in imap_client.messages(date__gt=n_minutes_ago):
for uid, message in imap_client.messages():
ic("one time")
uids.append(uid)
messages.append(message)
return messages
@pytest.fixture(scope="session")
def api_request_context(
playwright: Playwright,
DIR: DirManager,
) -> Generator[APIRequestContext, None, None]:
state_file = DIR.STATES / "authentik_admin_state.json"
request_context = playwright.request.new_context(storage_state=state_file)
yield request_context
request_context.dispose()