From 57b91c03d85ef7b76328807af2a40cc9741f039e Mon Sep 17 00:00:00 2001 From: Lucius Date: Fri, 31 Jul 2026 15:34:19 +0800 Subject: [PATCH] fix: bootstrap ClientTransaction from responsive home --- tests/test_client.py | 38 ++++++++++++++++++++++++++++++++++++++ twitter_cli/client.py | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/test_client.py b/tests/test_client.py index c1393d3..0bb996a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -266,6 +266,44 @@ def test_handles_malformed_html(self): # ── TwitterClient._build_headers ───────────────────────────────────────── class TestBuildHeaders: + @patch("twitter_cli.client._update_features_from_html") + @patch("twitter_cli.client.ClientTransaction") + @patch( + "twitter_cli.client.get_ondemand_file_url", + return_value="https://abs.twimg.com/responsive-web/client-web/ondemand.s.js", + ) + @patch("twitter_cli.client._gen_ct_headers", return_value={"User-Agent": "test"}) + @patch("twitter_cli.client._get_cffi_session") + def test_client_transaction_bootstraps_from_responsive_home_page( + self, + mock_session_factory, + _mock_headers, + _mock_ondemand_url, + mock_client_transaction, + mock_update_features, + ): + home_page = MagicMock(content=b"", text="") + ondemand_file = MagicMock(text="ondemand bundle") + mock_session_factory.return_value.get.side_effect = [home_page, ondemand_file] + + client = TwitterClient.__new__(TwitterClient) + client._ct_init_attempted = False + client._client_transaction = None + client._load_ct_cache = MagicMock(return_value=False) + client._save_ct_cache = MagicMock() + + client._ensure_client_transaction() + + first_request = mock_session_factory.return_value.get.call_args_list[0] + assert first_request.args[0] == "https://x.com/home" + assert first_request.kwargs == { + "headers": {"User-Agent": "test"}, + "timeout": 10, + } + mock_client_transaction.assert_called_once() + mock_update_features.assert_called_once_with("") + client._save_ct_cache.assert_called_once_with("", "ondemand bundle") + @patch("twitter_cli.client._get_cffi_session") @patch("twitter_cli.client._gen_ct_headers", return_value={}) def test_required_headers_present(self, mock_ct_headers, mock_session): diff --git a/twitter_cli/client.py b/twitter_cli/client.py index 0436c8e..d24f7d5 100644 --- a/twitter_cli/client.py +++ b/twitter_cli/client.py @@ -1104,7 +1104,7 @@ def _ensure_client_transaction(self): cffi_session = _get_cffi_session() ct_headers = _gen_ct_headers() home_page = cffi_session.get( - "https://x.com", headers=ct_headers, timeout=10, + "https://x.com/home", headers=ct_headers, timeout=10, ) home_page_response = bs4.BeautifulSoup(home_page.content, "html.parser") ondemand_url = get_ondemand_file_url(response=home_page_response)