login.test.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import { waitFor } from '@testing-library/dom'
  2. import { expect, test, vi } from 'vitest'
  3. import * as cliLogin from '@/data/cli/login'
  4. import { ProfileContextType } from '@/lib/profile'
  5. import { CliLoginScreen } from '@/pages/cli/login'
  6. import { customRender } from '@/tests/lib/custom-render'
  7. const DEFAULT_PROFILE_CONTEXT: ProfileContextType = {
  8. profile: {
  9. id: 1,
  10. auth0_id: 'auth0|test',
  11. gotrue_id: 'gotrue-test',
  12. username: 'testuser',
  13. primary_email: 'test@example.com',
  14. first_name: null,
  15. last_name: null,
  16. mobile: null,
  17. is_alpha_user: false,
  18. is_sso_user: false,
  19. disabled_features: [],
  20. free_project_limit: null,
  21. },
  22. error: null,
  23. isLoading: false,
  24. isError: false,
  25. isSuccess: true,
  26. }
  27. test('still navigates after parent re-renders during an in-flight POST', async () => {
  28. // Resolve manually so we can inject a re-render while the POST is in flight.
  29. let resolveSession: (value: { nonce: string }) => void = () => {}
  30. const createCliLoginSessionMock = vi.spyOn(cliLogin, 'createCliLoginSession').mockImplementation(
  31. () =>
  32. new Promise<{ nonce: string }>((resolve) => {
  33. resolveSession = resolve
  34. })
  35. )
  36. const initialNavigate = vi.fn()
  37. const { rerender } = customRender(
  38. <CliLoginScreen
  39. isLoggedIn
  40. routerReady
  41. sessionId="session-test"
  42. publicKey="public-key-test"
  43. tokenName="local-dev"
  44. navigate={initialNavigate}
  45. />,
  46. { profileContext: DEFAULT_PROFILE_CONTEXT }
  47. )
  48. await waitFor(() => {
  49. expect(createCliLoginSessionMock).toHaveBeenCalledTimes(1)
  50. })
  51. // Parent re-renders mid-POST with a brand-new navigate ref. This was the
  52. // production hang: the cleanup would invalidate the success handler and
  53. // the ref guard would skip the retry, leaving the screen on the loader.
  54. const laterNavigate = vi.fn()
  55. rerender(
  56. <CliLoginScreen
  57. isLoggedIn
  58. routerReady
  59. sessionId="session-test"
  60. publicKey="public-key-test"
  61. tokenName="local-dev"
  62. navigate={laterNavigate}
  63. />
  64. )
  65. resolveSession({ nonce: 'ABCDEFGH12345678' })
  66. await waitFor(() => {
  67. expect(laterNavigate).toHaveBeenCalledWith('/cli/login?device_code=ABCDEFGH')
  68. })
  69. expect(initialNavigate).not.toHaveBeenCalled()
  70. expect(createCliLoginSessionMock).toHaveBeenCalledTimes(1)
  71. })