1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""JavaScript module tests. Skipped unless pytest is run with --js-tests."""
from __future__ import annotations
import importlib.util
import sys
from collections.abc import Iterator
from pathlib import Path
from types import ModuleType
from typing import Any, cast
import pytest
from pygitweb.static_tests.js_runtime import JsPage, StaticServer, _NavGuard
class _FileModule(pytest.Module):
def _getobj(self) -> ModuleType:
name = "js_tests_" + self.path.stem.replace("-", "_")
spec = importlib.util.spec_from_file_location(name, self.path)
if spec is None or spec.loader is None:
raise ImportError(f"cannot load {self.path}")
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
return module
@pytest.hookimpl(hookwrapper=True)
def pytest_collect_file(file_path: Path, parent: pytest.Collector) -> object:
outcome = yield
if file_path.suffix != ".py" or not file_path.name.startswith("test_") or "-" not in file_path.name:
return
# pytest 9 gathers every pytest_collect_file result, so the default collector
# would import this hyphenated module a second time.
cast(Any, outcome).force_result([_FileModule.from_parent(parent, path=file_path)])
@pytest.fixture(scope="session")
def _js_browser() -> Iterator[tuple[Any, str]]:
pytest.importorskip("playwright.sync_api")
from playwright.sync_api import sync_playwright
server = StaticServer()
server.start()
try:
with sync_playwright() as playwright:
browser = playwright.chromium.launch(headless=True)
try:
yield browser, server.base_url
finally:
browser.close()
finally:
server.close()
@pytest.fixture
def js(_js_browser: tuple[Any, str]) -> Iterator[JsPage]:
browser, base_url = _js_browser
page = browser.new_page()
page.set_default_timeout(8000)
guard = _NavGuard()
page.route("**/*", guard.handle)
page.goto(base_url + "/", wait_until="domcontentloaded")
guard.current = page.url
guard.locked = True
js_page = JsPage(page, guard)
yield js_page
js_page.close()