220 lines
7.9 KiB
Python
220 lines
7.9 KiB
Python
"""Tests for media element rendering (images vs videos)."""
|
|
|
|
from httpx import AsyncClient
|
|
|
|
import main
|
|
|
|
|
|
class TestMediaElementRendering:
|
|
"""Tests for GET /{file_hash} media element selection."""
|
|
|
|
async def test_image_file_renders_img_tag(self, client_dir: AsyncClient) -> None:
|
|
"""Image files should render an <img> element."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".jpg"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert response.status_code == 200
|
|
assert "<img" in response.text
|
|
assert '<img class="media"' in response.text
|
|
assert f'src="/api/{file_hash}/data"' in response.text
|
|
|
|
async def test_video_file_renders_video_tag(self, client_dir: AsyncClient) -> None:
|
|
"""Video files should render a <video> element."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert response.status_code == 200
|
|
assert "<video" in response.text
|
|
assert '<video class="media"' in response.text
|
|
assert f'src="/api/{file_hash}/data"' in response.text
|
|
|
|
async def test_video_tag_has_controls(self, client_dir: AsyncClient) -> None:
|
|
"""Video element should have controls attribute."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert "controls" in response.text
|
|
|
|
async def test_video_tag_has_autoplay(self, client_dir: AsyncClient) -> None:
|
|
"""Video element should have autoplay attribute."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert "autoplay" in response.text
|
|
|
|
async def test_video_tag_has_loop(self, client_dir: AsyncClient) -> None:
|
|
"""Video element should have loop attribute."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert "loop" in response.text
|
|
|
|
async def test_video_tag_has_muted(self, client_dir: AsyncClient) -> None:
|
|
"""Video element should have muted attribute (required for autoplay)."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert "muted" in response.text
|
|
|
|
async def test_video_tag_has_playsinline(self, client_dir: AsyncClient) -> None:
|
|
"""Video element should have playsinline attribute."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert "playsinline" in response.text
|
|
|
|
async def test_image_tag_has_no_video_attributes(
|
|
self, client_dir: AsyncClient
|
|
) -> None:
|
|
"""Image element should not have video-specific attributes."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".jpg"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert "<video" not in response.text
|
|
|
|
async def test_media_has_data_hash_attribute(self, client_dir: AsyncClient) -> None:
|
|
"""Media element should have data-hash attribute."""
|
|
file_hash = list(main.file_mapping.keys())[0]
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert f'data-hash="{file_hash}"' in response.text
|
|
|
|
async def test_text_file_renders_img_tag(self, client_dir: AsyncClient) -> None:
|
|
"""Non-image, non-video files should render as <img> (default)."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".txt"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/{file_hash}")
|
|
assert "<img" in response.text
|
|
assert "<video" not in response.text
|
|
|
|
|
|
class TestVideoDataEndpoint:
|
|
"""Tests for GET /api/{file_hash}/data with video files."""
|
|
|
|
async def test_video_data_returns_correct_content_type(
|
|
self, client_dir: AsyncClient
|
|
) -> None:
|
|
"""Video data endpoint returns video/mp4 content type."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/api/{file_hash}/data")
|
|
assert response.status_code == 200
|
|
assert "video/mp4" in response.headers["content-type"]
|
|
|
|
async def test_video_data_returns_file_content(
|
|
self, client_dir: AsyncClient
|
|
) -> None:
|
|
"""Video data endpoint returns the actual file bytes."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/api/{file_hash}/data")
|
|
assert response.status_code == 200
|
|
assert len(response.content) > 0
|
|
|
|
async def test_video_data_has_inline_disposition(
|
|
self, client_dir: AsyncClient
|
|
) -> None:
|
|
"""Video data endpoint includes inline Content-Disposition."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(f"/api/{file_hash}/data")
|
|
assert "inline" in response.headers["content-disposition"]
|
|
|
|
|
|
class TestMediaElementWithRefresh:
|
|
"""Tests for media element rendering in auto-refresh mode."""
|
|
|
|
async def test_video_in_refresh_mode(
|
|
self, client_dir: AsyncClient
|
|
) -> None:
|
|
"""Video element renders correctly in auto-refresh mode."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".mp4"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(
|
|
f"/{file_hash}", params={"order": "next", "delay": 5}
|
|
)
|
|
assert response.status_code == 200
|
|
assert "<video" in response.text
|
|
assert '<video class="media"' in response.text
|
|
assert 'http-equiv="refresh"' in response.text
|
|
|
|
async def test_image_in_refresh_mode(self, client_dir: AsyncClient) -> None:
|
|
"""Image element renders correctly in auto-refresh mode."""
|
|
file_hash = None
|
|
for h, path in main.file_mapping.items():
|
|
if path.endswith(".jpg"):
|
|
file_hash = h
|
|
break
|
|
|
|
assert file_hash is not None
|
|
response = await client_dir.get(
|
|
f"/{file_hash}", params={"order": "next", "delay": 5}
|
|
)
|
|
assert response.status_code == 200
|
|
assert "<img" in response.text
|
|
assert '<img class="media"' in response.text
|