login_frame_test.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import {
  2. act,
  3. assertEquals,
  4. cleanup,
  5. fireEvent,
  6. render,
  7. screen,
  8. } from "./setup.ts";
  9. import LoginFrame from "../../islands/LoginFrame.tsx";
  10. // Mock fetch to prevent actual network calls
  11. const originalFetch = globalThis.fetch;
  12. function mockFetch(response = { success: false }) {
  13. globalThis.fetch = () =>
  14. Promise.resolve(
  15. new Response(JSON.stringify(response), {
  16. headers: { "Content-Type": "application/json" },
  17. }),
  18. );
  19. }
  20. function restoreFetch() {
  21. globalThis.fetch = originalFetch;
  22. }
  23. // Mock $loading to prevent errors
  24. function mockLoading() {
  25. globalThis.$loading = { show: () => {}, hide: () => {} };
  26. }
  27. function restoreLoading() {
  28. delete globalThis.$loading;
  29. }
  30. Deno.test({
  31. name: "LoginFrame - login mode renders email and password inputs",
  32. async fn() {
  33. mockFetch();
  34. const { container } = render(<LoginFrame mode="login" />);
  35. // Wait for useEffect to settle
  36. await act(async () => {});
  37. assertEquals(screen.getByPlaceholderText("Your email") !== null, true);
  38. assertEquals(screen.getByPlaceholderText("Your password") !== null, true);
  39. cleanup();
  40. restoreFetch();
  41. },
  42. sanitizeResources: false,
  43. sanitizeOps: false,
  44. });
  45. Deno.test({
  46. name: "LoginFrame - login mode renders Sign in button",
  47. async fn() {
  48. mockFetch();
  49. const { container } = render(<LoginFrame mode="login" />);
  50. await act(async () => {});
  51. assertEquals(screen.getByText("Sign in").tagName, "BUTTON");
  52. cleanup();
  53. restoreFetch();
  54. },
  55. sanitizeResources: false,
  56. sanitizeOps: false,
  57. });
  58. Deno.test({
  59. name: "LoginFrame - login mode renders Go Register button",
  60. async fn() {
  61. mockFetch();
  62. render(<LoginFrame mode="login" />);
  63. await act(async () => {});
  64. assertEquals(screen.getByText("Go Register").tagName, "BUTTON");
  65. cleanup();
  66. restoreFetch();
  67. },
  68. sanitizeResources: false,
  69. sanitizeOps: false,
  70. });
  71. Deno.test({
  72. name: "LoginFrame - login mode does not render confirm password",
  73. async fn() {
  74. mockFetch();
  75. render(<LoginFrame mode="login" />);
  76. await act(async () => {});
  77. const confirmInput = screen.queryByPlaceholderText("Confirm your password");
  78. assertEquals(confirmInput, null);
  79. cleanup();
  80. restoreFetch();
  81. },
  82. sanitizeResources: false,
  83. sanitizeOps: false,
  84. });
  85. Deno.test({
  86. name: "LoginFrame - register mode renders confirm password input",
  87. fn() {
  88. mockFetch();
  89. render(<LoginFrame mode="register" />);
  90. assertEquals(
  91. screen.getByPlaceholderText("Confirm your password") !== null,
  92. true,
  93. );
  94. cleanup();
  95. restoreFetch();
  96. },
  97. sanitizeResources: false,
  98. sanitizeOps: false,
  99. });
  100. Deno.test({
  101. name: "LoginFrame - register mode renders Register button",
  102. fn() {
  103. mockFetch();
  104. render(<LoginFrame mode="register" />);
  105. assertEquals(screen.getByText("Register").tagName, "BUTTON");
  106. cleanup();
  107. restoreFetch();
  108. },
  109. sanitizeResources: false,
  110. sanitizeOps: false,
  111. });
  112. Deno.test({
  113. name: "LoginFrame - register mode renders Go Login button",
  114. fn() {
  115. mockFetch();
  116. render(<LoginFrame mode="register" />);
  117. assertEquals(screen.getByText("Go Login").tagName, "BUTTON");
  118. cleanup();
  119. restoreFetch();
  120. },
  121. sanitizeResources: false,
  122. sanitizeOps: false,
  123. });
  124. Deno.test({
  125. name: "LoginFrame - submit with empty fields sets error state",
  126. async fn() {
  127. mockFetch();
  128. mockLoading();
  129. render(<LoginFrame mode="login" />);
  130. await act(async () => {});
  131. const submitBtn = screen.getByText("Sign in");
  132. await act(async () => {
  133. fireEvent.click(submitBtn);
  134. });
  135. // Check that error borders appear on empty inputs
  136. const emailInput = screen.getByPlaceholderText("Your email");
  137. const passwordInput = screen.getByPlaceholderText("Your password");
  138. assertEquals(emailInput.className.includes("border-red-600"), true);
  139. assertEquals(passwordInput.className.includes("border-red-600"), true);
  140. cleanup();
  141. restoreFetch();
  142. restoreLoading();
  143. },
  144. sanitizeResources: false,
  145. sanitizeOps: false,
  146. });
  147. Deno.test({
  148. name: "LoginFrame - typing clears error state",
  149. async fn() {
  150. mockFetch();
  151. mockLoading();
  152. render(<LoginFrame mode="login" />);
  153. await act(async () => {});
  154. // Trigger error
  155. await act(async () => {
  156. fireEvent.click(screen.getByText("Sign in"));
  157. });
  158. const emailInput = screen.getByPlaceholderText("Your email");
  159. assertEquals(emailInput.className.includes("border-red-600"), true);
  160. // Type into the email input to clear error
  161. await act(async () => {
  162. fireEvent.input(emailInput, { target: { value: "test@email.com" } });
  163. });
  164. assertEquals(emailInput.className.includes("border-red-600"), false);
  165. cleanup();
  166. restoreFetch();
  167. restoreLoading();
  168. },
  169. sanitizeResources: false,
  170. sanitizeOps: false,
  171. });