Skip to content

Commit a058403

Browse files
committed
Fix a few coverage hits
1 parent 5182c83 commit a058403

File tree

8 files changed

+64
-13
lines changed

8 files changed

+64
-13
lines changed

Diff for: pyproject.toml

+6-3
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ xfail_strict = true
117117
asyncio_mode = "auto"
118118
log_cli_level = "INFO"
119119

120-
[tool.hatch.envs.default.env-vars]
120+
[tool.hatch.envs.hatch-test.env-vars]
121121
REACTPY_DEBUG_MODE = "1"
122122

123123
#######################################
@@ -234,7 +234,11 @@ warn_unused_ignores = true
234234
source_pkgs = ["reactpy"]
235235
branch = false
236236
parallel = false
237-
omit = ["reactpy/__init__.py"]
237+
omit = [
238+
"src/reactpy/__init__.py",
239+
"src/reactpy/_console/*",
240+
"src/reactpy/__main__.py",
241+
]
238242

239243
[tool.coverage.report]
240244
fail_under = 98
@@ -247,7 +251,6 @@ exclude_also = [
247251
"if __name__ == .__main__.:",
248252
"if TYPE_CHECKING:",
249253
]
250-
omit = ["**/reactpy/__main__.py"]
251254

252255
[tool.ruff]
253256
target-version = "py39"

Diff for: src/reactpy/asgi/middleware.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def __init__(
5656
self.web_modules_path = f"{self.path_prefix}modules/"
5757
self.static_path = f"{self.path_prefix}static/"
5858
self.dispatcher_pattern = re.compile(
59-
f"^{self.dispatcher_path}(?P<dotted_path>[^/]+)/?"
59+
f"^{self.dispatcher_path}(?P<dotted_path>[a-zA-Z0-9_.]+)/$"
6060
)
6161
self.js_modules_pattern = re.compile(f"^{self.web_modules_path}.*")
6262
self.static_pattern = re.compile(f"^{self.static_path}.*")

Diff for: src/reactpy/asgi/standalone.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ def __init__(
4747
self.html_head = html_head or html.head()
4848
self.html_lang = html_lang
4949

50+
def match_dispatch_path(self, scope: asgi_types.WebSocketScope) -> bool:
51+
"""Method override to remove `dotted_path` from the dispatcher URL."""
52+
return str(scope["path"]) == self.dispatcher_path
53+
5054

5155
@dataclass
5256
class ReactPyApp:
@@ -64,7 +68,7 @@ async def __call__(
6468
receive: asgi_types.ASGIReceiveCallable,
6569
send: asgi_types.ASGISendCallable,
6670
) -> None:
67-
if scope["type"] != "http":
71+
if scope["type"] != "http": # pragma: no cover
6872
if scope["type"] != "lifespan":
6973
msg = (
7074
"ReactPy app received unsupported request of type '%s' at path '%s'",
@@ -120,18 +124,13 @@ async def __call__(
120124
headers=dict_to_byte_list(response_headers),
121125
)
122126

123-
def match_dispatch_path(self, scope: asgi_types.WebSocketScope) -> bool:
124-
"""Method override to remove `dotted_path` from the dispatcher URL."""
125-
return str(scope["path"]) == self.parent.dispatcher_path
126-
127127
def process_index_html(self) -> None:
128128
"""Process the index.html and store the results in memory."""
129129
self._cached_index_html = (
130130
"<!doctype html>"
131131
f'<html lang="{self.parent.html_lang}">'
132132
f"{vdom_head_to_html(self.parent.html_head)}"
133133
"<body>"
134-
f'<div id="app"></div>'
135134
f"{render_mount_template('app', '', '')}"
136135
"</body>"
137136
"</html>"

Diff for: src/reactpy/asgi/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def import_components(dotted_paths: Iterable[str]) -> dict[str, Any]:
3434
}
3535

3636

37-
def check_path(url_path: str) -> str:
37+
def check_path(url_path: str) -> str: # pragma: no cover
3838
"""Check that a path is valid URL path."""
3939
if not url_path:
4040
return "URL path must not be empty."

Diff for: src/reactpy/core/hooks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -544,4 +544,4 @@ def strictly_equal(x: Any, y: Any) -> bool:
544544
return x == y # type: ignore
545545

546546
# Fallback to identity check
547-
return x is y
547+
return x is y # pragma: no cover

Diff for: src/reactpy/testing/utils.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
from contextlib import closing
66

77

8-
def find_available_port(host: str, port_min: int = 8000, port_max: int = 9000) -> int:
8+
def find_available_port(
9+
host: str, port_min: int = 8000, port_max: int = 9000
10+
) -> int: # pragma: no cover
911
"""Get a port that's available for the given host and port range"""
1012
for port in range(port_min, port_max):
1113
with closing(socket.socket()) as sock:

Diff for: tests/test_asgi/test_standalone.py

+23
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from collections.abc import MutableMapping
22

33
import pytest
4+
from requests import request
45

56
import reactpy
67
from reactpy import html
78
from reactpy.asgi.standalone import ReactPy
89
from reactpy.testing import BackendFixture, DisplayFixture, poll
10+
from reactpy.testing.common import REACTPY_TESTS_DEFAULT_TIMEOUT
911
from reactpy.types import Connection, Location
1012

1113

@@ -138,3 +140,24 @@ def sample():
138140
async with DisplayFixture(backend=server, driver=page) as new_display:
139141
await new_display.show(sample)
140142
assert (await new_display.page.title()) == custom_title
143+
144+
145+
async def test_head_request(page):
146+
@reactpy.component
147+
def sample():
148+
return html.h1("Hello World")
149+
150+
app = ReactPy(sample)
151+
152+
async with BackendFixture(app) as server:
153+
async with DisplayFixture(backend=server, driver=page) as new_display:
154+
await new_display.show(sample)
155+
url = f"http://{server.host}:{server.port}"
156+
response = request(
157+
"HEAD", url, timeout=REACTPY_TESTS_DEFAULT_TIMEOUT.current
158+
)
159+
assert response.status_code == 200
160+
assert response.headers["content-type"] == "text/html; charset=utf-8"
161+
assert response.headers["cache-control"] == "max-age=60, public"
162+
assert response.headers["access-control-allow-origin"] == "*"
163+
assert response.content == b""

Diff for: tests/test_html.py

+24
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,27 @@ def test_simple_fragment():
115115
def test_fragment_can_have_no_attributes():
116116
with pytest.raises(TypeError, match="Fragments cannot have attributes"):
117117
html.fragment({"some_attribute": 1})
118+
119+
120+
async def test_svg(display: DisplayFixture):
121+
@component
122+
def SvgComponent():
123+
return html.svg(
124+
{"width": 100, "height": 100},
125+
html.svg.circle(
126+
{"cx": 50, "cy": 50, "r": 40, "fill": "red"},
127+
),
128+
html.svg.circle(
129+
{"cx": 50, "cy": 50, "r": 40, "fill": "red"},
130+
),
131+
)
132+
133+
await display.show(SvgComponent)
134+
svg = await display.page.wait_for_selector("svg", state="attached")
135+
assert await svg.get_attribute("width") == "100"
136+
assert await svg.get_attribute("height") == "100"
137+
circle = await display.page.wait_for_selector("circle", state="attached")
138+
assert await circle.get_attribute("cx") == "50"
139+
assert await circle.get_attribute("cy") == "50"
140+
assert await circle.get_attribute("r") == "40"
141+
assert await circle.get_attribute("fill") == "red"

0 commit comments

Comments
 (0)