Просмотр исходного кода

test(auth): add tests for user auth form

satnaing 2 месяцев назад
Родитель
Сommit
038bb4fe27
1 измененных файлов с 129 добавлено и 0 удалено
  1. 129 0
      src/features/auth/sign-in/components/user-auth-form.test.tsx

+ 129 - 0
src/features/auth/sign-in/components/user-auth-form.test.tsx

@@ -0,0 +1,129 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { render, type RenderResult } from 'vitest-browser-react'
+import { type Locator, userEvent } from 'vitest/browser'
+import { UserAuthForm } from './user-auth-form'
+
+const FORM_MESSAGES = {
+  emailEmpty: 'Please enter your email.',
+  passwordEmpty: 'Please enter your password.',
+  passwordShort: 'Password must be at least 7 characters long.',
+} as const
+
+const navigate = vi.fn()
+const setUserMock = vi.fn()
+const setAccessTokenMock = vi.fn()
+
+vi.mock('@/stores/auth-store', () => ({
+  useAuthStore: () => ({
+    auth: {
+      setUser: setUserMock,
+      setAccessToken: setAccessTokenMock,
+    },
+  }),
+}))
+
+vi.mock('@tanstack/react-router', async (importOriginal) => {
+  const actual = await importOriginal<typeof import('@tanstack/react-router')>()
+  return {
+    ...actual,
+    useNavigate: () => navigate,
+    Link: ({
+      children,
+      to,
+      className,
+      ...rest
+    }: {
+      children?: React.ReactNode
+      to: string
+      className?: string
+    }) => (
+      <a href={to} className={className} {...rest}>
+        {children}
+      </a>
+    ),
+  }
+})
+
+vi.mock('@/lib/utils', async (orig) => ({
+  ...(await orig()),
+  sleep: vi.fn(() => Promise.resolve()),
+}))
+
+describe('UserAuthForm', () => {
+  describe('Rendering without redirectTo', () => {
+    let screen: RenderResult
+    let emailInput: Locator
+    let passwordInput: Locator
+    let signInButton: Locator
+    let forgotPasswordLink: Locator
+
+    beforeEach(async () => {
+      vi.clearAllMocks()
+      screen = await render(<UserAuthForm />)
+      emailInput = screen.getByRole('textbox', { name: /^Email$/i })
+      passwordInput = screen.getByLabelText(/^Password$/i)
+      signInButton = screen.getByRole('button', { name: /^Sign in$/i })
+      forgotPasswordLink = screen.getByText(/^Forgot password\?$/i)
+    })
+
+    it('renders fields, submit button, and forgot password link', async () => {
+      expect(emailInput).toBeInTheDocument()
+      expect(passwordInput).toBeInTheDocument()
+      expect(signInButton).toBeInTheDocument()
+      expect(forgotPasswordLink).toBeInTheDocument()
+    })
+
+    it('shows validation messages when submitting empty form', async () => {
+      await userEvent.click(signInButton)
+
+      expect(screen.getByText(FORM_MESSAGES.emailEmpty)).toBeInTheDocument()
+      expect(screen.getByText(FORM_MESSAGES.passwordEmpty)).toBeInTheDocument()
+    })
+
+    it('authenticates and navigates to default route on success', async () => {
+      await userEvent.fill(emailInput, 'a@b.com')
+      await userEvent.fill(passwordInput, '1234567')
+
+      await userEvent.click(signInButton)
+
+      await vi.waitFor(() => expect(setUserMock).toHaveBeenCalledOnce())
+      expect(setUserMock).toHaveBeenCalledWith(
+        expect.objectContaining({
+          email: 'a@b.com',
+          accountNo: expect.any(String),
+          role: expect.any(Array),
+          exp: expect.any(Number),
+        })
+      )
+      expect(setAccessTokenMock).toHaveBeenCalledOnce()
+      expect(setAccessTokenMock).toHaveBeenCalledWith('mock-access-token')
+
+      await vi.waitFor(() =>
+        expect(navigate).toHaveBeenCalledWith({ to: '/', replace: true })
+      )
+    })
+  })
+
+  it('navigates to redirectTo when provided', async () => {
+    vi.clearAllMocks()
+
+    const { getByRole, getByLabelText } = await render(
+      <UserAuthForm redirectTo='/settings' />
+    )
+
+    await userEvent.fill(getByRole('textbox', { name: /Email/i }), 'a@b.com')
+    await userEvent.fill(getByLabelText('Password'), '1234567')
+
+    await userEvent.click(getByRole('button', { name: /Sign in/i }))
+
+    await vi.waitFor(() => expect(setUserMock).toHaveBeenCalledOnce())
+    expect(setAccessTokenMock).toHaveBeenCalledOnce()
+
+    await vi.waitFor(() =>
+      expect(navigate).toHaveBeenCalledWith({
+        to: '/settings',
+        replace: true,
+      })
+    )
+  })
+})