Download conftest.py from build-small-hackathon/color-ux-access: direct link, hf CLI and curl.
- Browser
- Download file 6.13 kB
-
https://huggingface.co/spaces/build-small-hackathon/color-ux-access/resolve/main/conftest.py
- Command line
-
hf download hf://spaces/build-small-hackathon/color-ux-access/conftest.py
-
curl -L -o conftest.py https://huggingface.co/spaces/build-small-hackathon/color-ux-access/resolve/main/conftest.py
6.13 kB
| """ | |
| Shared pytest fixtures for color-ux-access. | |
| ============================================= | |
| All tests should import from here rather than doing sys.path gymnastics. | |
| Fixture hierarchy | |
| ----------------- | |
| img_factory β PIL Image, no CVD simulation | |
| cvd_img_factory β Image + callable(cv_type) -> simulated PIL Image | |
| mock_vlm_factory β Returns deterministic WCAG JSON (no API call) | |
| browser_page β Chromium page for screenshot capture tests | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import sys | |
| from pathlib import Path | |
| import pytest | |
| import numpy as np | |
| from dotenv import load_dotenv | |
| from PIL import Image | |
| # Ensure project root is on path | |
| _project_root = Path(__file__).resolve().parent | |
| if str(_project_root) not in sys.path: | |
| sys.path.insert(0, str(_project_root)) | |
| # Load .env so env-gated integration tests (modal endpoints, etc.) work locally | |
| load_dotenv(_project_root / ".env") | |
| # ββ Image Fixtures ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def img_factory(): | |
| """Factory: makes random RGB PIL Images of a given size.""" | |
| def _make(width: int = 640, height: int = 480, seed: int | None = None) -> Image.Image: | |
| if seed is not None: | |
| rng = np.random.default_rng(seed) | |
| arr = rng.integers(0, 255, (height, width, 3), dtype=np.uint8) | |
| else: | |
| arr = np.random.randint(0, 255, (height, width, 3), dtype=np.uint8) | |
| return Image.fromarray(arr) | |
| return _make | |
| def cvd_img_factory(img_factory): | |
| """ | |
| Factory: makes PIL Image AND a simulate() callable. | |
| Usage: | |
| img, simulate = cvd_img_factory(100, 100) | |
| deut_img = simulate(img, 'deuteranopia') | |
| """ | |
| from color_ux_access.cvd_sim import simulate_cvd | |
| def _make(width: int = 640, height: int = 480, seed: int = 42) -> tuple[Image.Image, callable]: | |
| img = img_factory(width, height, seed=seed) | |
| return img, lambda cv_type: simulate_cvd(img, cv_type) | |
| return _make | |
| def sample_button_panel(img_factory) -> Image.Image: | |
| """ | |
| Synthetic button panel β green Confirm button (left), red Cancel button (right). | |
| Tests that CVD simulation makes the two buttons indistinguishable. | |
| """ | |
| arr = np.zeros((120, 300, 3), dtype=np.uint8) | |
| arr[:, :] = [240, 240, 240] # gray background | |
| arr[20:100, 20:145] = [34, 139, 34] # green confirm (left half) | |
| arr[20:100, 155:280] = [205, 92, 92] # red cancel (right half) | |
| return Image.fromarray(arr) | |
| # ββ VLM Fixtures ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def mock_vlm_factory(): | |
| """ | |
| Returns a deterministic WCAG JSON response for testing without API calls. | |
| Use as a patch target for analyze_with_vlm() in app_space.py. | |
| """ | |
| def make_findings(count: int = 2) -> list[dict]: | |
| return [ | |
| { | |
| "type": "Low Contrast", | |
| "wcag_criterion": "1.4.3", | |
| "description": "Button text contrast ratio is 2.8:1 β below the 4.5:1 AA minimum", | |
| "severity": "serious", | |
| "location": "Submit button, top-right", | |
| }, | |
| { | |
| "type": "Color Only Information", | |
| "wcag_criterion": "1.4.1", | |
| "description": "Form validation relies on red/green borders with no secondary indicator", | |
| "severity": "critical", | |
| "location": "Form section, center-left", | |
| }, | |
| ][:count] | |
| def mock_vlm_result(passes: bool = False, findings_count: int = 1) -> dict: | |
| findings = make_findings(findings_count) if not passes else [] | |
| return { | |
| "perception_summary": "The UI is mostly readable but some color-dependent elements may be hard to distinguish." if not passes else "The interface is clear and readable from this perspective.", | |
| "findings": findings, | |
| "summary": f"{findings_count} critical issue(s) found" if findings else "No issues found", | |
| "passes": passes, | |
| } | |
| return mock_vlm_result | |
| # ββ CVD Gallery Fixture βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def ten_type_gallery() -> list[str]: | |
| """ | |
| The 10 canonical CVD type names the UI gallery must produce. | |
| """ | |
| return [ | |
| 'deuteranopia', | |
| 'protanopia', | |
| 'tritanopia', | |
| 'achromatopsia', | |
| 'deuteranomaly', | |
| 'protanomaly', | |
| 'tritanomaly', | |
| ] | |
| # ββ Token Fixture βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def hf_token(): | |
| """ | |
| Read HF_TOKEN from environment or ~/.cache/huggingface/token. | |
| Order: HF_TOKEN env var β HF_API_TOKEN env var β token file. | |
| Skips all E2E tests if no token is available. | |
| Matches how color_ux_access.modal_app and vlm.vlm_inference resolve tokens. | |
| """ | |
| token = os.environ.get("HF_TOKEN") or os.environ.get("HF_API_TOKEN") | |
| if token is None: | |
| token_file = os.path.expanduser("~/.cache/huggingface/token") | |
| if not os.path.exists(token_file): | |
| pytest.skip("HF_TOKEN not found (no env var and no ~/.cache/huggingface/token)") | |
| with open(token_file) as f: | |
| token = f.read().strip() | |
| if not token or len(token) < 10: | |
| pytest.skip("HF_TOKEN is empty or too short to be valid") | |
| return token | |
| # Playwright fixtures removed β HF Space containers cannot run a browser. | |
| # The capture module (color_ux_access.capture.take_screenshot) uses playwright | |
| # locally for screenshots, but tests use source inspection only." |