test_chatgpt_signup.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import unittest
  2. from unittest.mock import patch
  3. import chatgpt_signup
  4. class PasskeyEnrollmentTests(unittest.TestCase):
  5. def test_detects_passkey_enrollment_url(self):
  6. self.assertTrue(
  7. chatgpt_signup._is_passkey_enrollment_url(
  8. "https://auth.openai.com/create-account-enroll-passkey"
  9. )
  10. )
  11. def test_does_not_treat_about_you_as_passkey_enrollment(self):
  12. self.assertFalse(
  13. chatgpt_signup._is_passkey_enrollment_url(
  14. "https://auth.openai.com/about-you"
  15. )
  16. )
  17. def test_passkey_handler_clicks_skip_button(self):
  18. class _FakeLocator:
  19. def __init__(self, page, selector):
  20. self.page = page
  21. self.selector = selector
  22. def count(self):
  23. return 1 if "Skip for now" in self.selector else 0
  24. def nth(self, _idx):
  25. return self
  26. def is_visible(self):
  27. return True
  28. def is_enabled(self):
  29. return True
  30. def click(self, **_kwargs):
  31. self.page.clicked.append(self.selector)
  32. self.page.url = "https://chatgpt.com/"
  33. class _FakePage:
  34. def __init__(self):
  35. self.url = "https://auth.openai.com/create-account-enroll-passkey"
  36. self.clicked = []
  37. def locator(self, selector):
  38. return _FakeLocator(self, selector)
  39. page = _FakePage()
  40. handled = chatgpt_signup._handle_passkey_enrollment_if_present(
  41. page,
  42. log=lambda *_: None,
  43. timeout_sec=1,
  44. )
  45. self.assertTrue(handled)
  46. self.assertTrue(page.clicked)
  47. self.assertEqual(page.url, "https://chatgpt.com/")
  48. class SignupEntrypointTests(unittest.TestCase):
  49. def test_does_not_generate_credentials_when_entry_page_cannot_open(self):
  50. class _FakePage:
  51. def goto(self, *_args, **_kwargs):
  52. raise RuntimeError("net::ERR_EMPTY_RESPONSE")
  53. with patch.object(chatgpt_signup, "build_a4sky_email", return_value="n@example.com") as build_email:
  54. with self.assertRaises(RuntimeError):
  55. chatgpt_signup.signup_chatgpt(
  56. _FakePage(),
  57. helper_url="http://mail.example",
  58. log=lambda *_: None,
  59. )
  60. self.assertEqual(build_email.call_count, 0)
  61. class SsoWorkspaceChoiceTests(unittest.TestCase):
  62. def test_signup_sso_clicks_workspace_choice_before_keycloak_register(self):
  63. class _FakePage:
  64. def __init__(self):
  65. self.url = ""
  66. def goto(self, *_args, **_kwargs):
  67. self.url = "https://chatgpt.com/"
  68. def wait_for_timeout(self, *_args, **_kwargs):
  69. pass
  70. def wait_for_load_state(self, *_args, **_kwargs):
  71. pass
  72. page = _FakePage()
  73. workspace_clicks = []
  74. def fill_sso_email(fake_page, *_args, **_kwargs):
  75. fake_page.url = "https://auth.openai.com/sso"
  76. def click_workspace(fake_page, *_args, **_kwargs):
  77. workspace_clicks.append(fake_page.url)
  78. fake_page.url = "https://sso.claudeai.life/realms/openai/login-actions/authenticate"
  79. return True
  80. def click_register(fake_page, *_args, **_kwargs):
  81. fake_page.url = "https://sso.claudeai.life/realms/openai/login-actions/registration"
  82. return True
  83. with patch.object(chatgpt_signup, "_build_sso_email", return_value="n@example.com"):
  84. with patch.object(chatgpt_signup, "_rand_name", return_value=("First", "Last")):
  85. with patch.object(chatgpt_signup, "_find_visible", return_value=(object(), "input")):
  86. with patch.object(chatgpt_signup, "_fill_signup_email", side_effect=fill_sso_email):
  87. with patch.object(chatgpt_signup, "_wait_for_sso_or_keycloak", return_value=True):
  88. with patch.object(chatgpt_signup, "_click_sso_workspace_option", side_effect=click_workspace, create=True):
  89. with patch.object(chatgpt_signup, "_click_keycloak_register", side_effect=click_register):
  90. with patch.object(chatgpt_signup, "_wait_until", side_effect=lambda predicate, _timeout: bool(predicate())):
  91. with patch.object(chatgpt_signup, "_fill_keycloak_registration"):
  92. with patch.object(chatgpt_signup, "_handle_interstitial_confirm", return_value=False):
  93. with patch.object(chatgpt_signup, "_handle_passkey_enrollment_if_present", return_value=False):
  94. with patch.object(chatgpt_signup, "_fetch_session", return_value={"accessToken": "tok"}):
  95. chatgpt_signup.signup_chatgpt_sso(page, log=lambda *_: None)
  96. self.assertEqual(workspace_clicks, ["https://auth.openai.com/sso"])
  97. def test_click_sso_workspace_option_clicks_workspace_button(self):
  98. class _FakeLocator:
  99. def __init__(self, page, selector):
  100. self.page = page
  101. self.selector = selector
  102. def count(self):
  103. return 1 if "Workspace" in self.selector else 0
  104. def nth(self, _idx):
  105. return self
  106. def is_visible(self):
  107. return True
  108. def is_enabled(self):
  109. return True
  110. def click(self, **_kwargs):
  111. self.page.clicked.append(self.selector)
  112. self.page.url = "https://sso.claudeai.life/realms/openai/login-actions/authenticate"
  113. class _FakePage:
  114. def __init__(self):
  115. self.url = "https://auth.openai.com/sso"
  116. self.clicked = []
  117. def locator(self, selector):
  118. return _FakeLocator(self, selector)
  119. def wait_for_timeout(self, *_args, **_kwargs):
  120. pass
  121. page = _FakePage()
  122. click_workspace = getattr(chatgpt_signup, "_click_sso_workspace_option", lambda *_args, **_kwargs: False)
  123. clicked = click_workspace(page, log=lambda *_: None, timeout_sec=1)
  124. self.assertTrue(clicked)
  125. self.assertTrue(page.clicked)
  126. self.assertIn("Workspace", page.clicked[0])
  127. class SsoConsentTests(unittest.TestCase):
  128. def test_handle_consent_page_clicks_approve_sign_in(self):
  129. class _FakeLocator:
  130. def __init__(self, page, selector):
  131. self.page = page
  132. self.selector = selector
  133. def count(self):
  134. return 1 if "Approve sign-in" in self.selector else 0
  135. def nth(self, _idx):
  136. return self
  137. def is_visible(self):
  138. return True
  139. def is_enabled(self):
  140. return True
  141. def click(self, **_kwargs):
  142. self.page.clicked.append(self.selector)
  143. self.page.url = "https://chatgpt.com/"
  144. class _FakePage:
  145. def __init__(self):
  146. self.url = "https://external.auth.openai.com/sso/signin-consent?token=abc"
  147. self.clicked = []
  148. def locator(self, selector):
  149. return _FakeLocator(self, selector)
  150. def wait_for_timeout(self, *_args, **_kwargs):
  151. pass
  152. page = _FakePage()
  153. with patch.object(chatgpt_signup, "_wait_until", side_effect=lambda predicate, _timeout: bool(predicate())):
  154. approved = chatgpt_signup._handle_interstitial_confirm(page, log=lambda *_: None, timeout_sec=1)
  155. self.assertTrue(approved)
  156. self.assertTrue(page.clicked)
  157. self.assertIn("Approve sign-in", page.clicked[0])
  158. if __name__ == "__main__":
  159. unittest.main()