"""RED tests for scripts.twitter_threads.fetch_thread (normalize URL + HTML to ThreadData).""" from __future__ import annotations from pathlib import Path import pytest from scripts.twitter_threads.error_types import PostData, ThreadData from scripts.twitter_threads.fetch_thread import fetch_thread_from_html, _normalize_url def test_normalize_url_strips_query() -> None: assert _normalize_url("https://x.com/VPCOMPRESSB/status/1991383117571957052?s=20") == "https://x.com/VPCOMPRESSB/status/1991383117571957052" assert _normalize_url("https://x.com/NOTimothyLottes/status/123") == "https://x.com/NOTimothyLottes/status/123" def test_parse_html_single_post(tmp_path: Path) -> None: html = """
Hello thread
""" p = tmp_path / "x.html" p.write_text(html, encoding="utf-8") result = fetch_thread_from_html(p) assert result.is_ok td = result.data assert td is not None assert td.root_post_id == "1757198624818168210" assert len(td.posts) == 1 post = td.posts[0] assert post.post_id == "1757198624818168210" assert post.author == "Timothy Lottes" assert post.handle == "NOTimothyLottes" assert post.timestamp == "2024-02-13T12:00:00Z" assert "Hello thread" in post.text assert post.media_urls == ("https://pbs.twimg.com/media/AAA.jpg",) assert post.metrics.reply_count == 5 assert post.metrics.repost_count == 10 assert post.metrics.like_count == 100 assert post.metrics.view_count == 5000 assert td.source_url == "https://x.com/NOTimothyLottes/status/1757198624818168210" def test_parse_html_thread(tmp_path: Path) -> None: html = """
p1
p2
p3
""" p = tmp_path / "x.html" p.write_text(html, encoding="utf-8") result = fetch_thread_from_html(p) assert result.is_ok td = result.data assert td is not None assert len(td.posts) == 3 ids = [pt.post_id for pt in td.posts] assert ids == ["1", "2", "3"] assert td.posts[1].reply_to_id == "1" assert td.posts[2].reply_to_id == "2" assert td.posts[0].reply_to_id is None def test_parse_html_no_media(tmp_path: Path) -> None: html = """
no media here
""" p = tmp_path / "x.html" p.write_text(html, encoding="utf-8") result = fetch_thread_from_html(p) assert result.is_ok td = result.data assert td is not None assert td.posts[0].media_urls == () def test_parse_html_quote(tmp_path: Path) -> None: html = """
quoting
""" p = tmp_path / "x.html" p.write_text(html, encoding="utf-8") result = fetch_thread_from_html(p) assert result.is_ok td = result.data assert td is not None assert td.posts[0].quote_of_id == "999" def test_parse_html_malformed(tmp_path: Path) -> None: html = "

no articles here

" p = tmp_path / "x.html" p.write_text(html, encoding="utf-8") result = fetch_thread_from_html(p) assert result.is_ok is False assert result.error is not None assert result.error.kind == "ParseError" def test_parse_html_view_count_absent(tmp_path: Path) -> None: html = """
x
""" p = tmp_path / "x.html" p.write_text(html, encoding="utf-8") result = fetch_thread_from_html(p) assert result.is_ok td = result.data assert td is not None assert td.posts[0].metrics.view_count is None assert td.posts[0].metrics.reply_count == 0