41 lines
1.3 KiB
Python
41 lines
1.3 KiB
Python
"""Shared data models for the Peregrine E2E test harness."""
|
|
from __future__ import annotations
|
|
import fnmatch
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Callable, Any
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ErrorRecord:
|
|
type: str # "exception" | "alert"
|
|
message: str
|
|
element_html: str
|
|
|
|
def __eq__(self, other: object) -> bool:
|
|
if not isinstance(other, ErrorRecord):
|
|
return NotImplemented
|
|
return (self.type, self.message) == (other.type, other.message)
|
|
|
|
def __hash__(self) -> int:
|
|
return hash((self.type, self.message))
|
|
|
|
|
|
def diff_errors(before: list[ErrorRecord], after: list[ErrorRecord]) -> list[ErrorRecord]:
|
|
"""Return errors in `after` that were not present in `before`."""
|
|
before_set = set(before)
|
|
return [e for e in after if e not in before_set]
|
|
|
|
|
|
@dataclass
|
|
class ModeConfig:
|
|
name: str
|
|
base_url: str
|
|
auth_setup: Callable[[Any], None]
|
|
expected_failures: list[str] # fnmatch glob patterns against element labels
|
|
results_dir: Path | None
|
|
settings_tabs: list[str] # tabs expected per mode
|
|
|
|
def matches_expected_failure(self, label: str) -> bool:
|
|
"""Return True if label matches any expected_failure pattern (fnmatch)."""
|
|
return any(fnmatch.fnmatch(label, pattern) for pattern in self.expected_failures)
|