import { fireEvent, screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import MaterialNewPage from '@/pages/materials/MaterialNewPage'
import { renderWithProviders } from '@/test/render'
const api = vi.hoisted (() => ({
apiGet: vi.fn (),
apiPost: vi.fn (),
isApiError: vi.fn (),
}))
const toastApi = vi.hoisted (() => ({
toast: vi.fn (),
}))
vi.mock ('@/lib/api', () => api)
vi.mock ('@/components/ui/use-toast', () => toastApi)
describe ('MaterialNewPage', () => {
beforeEach (() => {
vi.clearAllMocks ()
api.apiGet.mockResolvedValue ([])
api.isApiError.mockReturnValue (false)
})
it ('initializes tag from query and submits form data', async () => {
api.apiPost.mockResolvedValueOnce ({})
renderWithProviders (, { route: '/materials/new?tag=%E8%99%B9%E5%A4%8F' })
expect (screen.getAllByRole ('textbox')[0]).toHaveValue ('虹夏')
fireEvent.change (screen.getAllByRole ('textbox')[1], {
target: { value: 'https://example.com/ref' },
})
fireEvent.click (screen.getByRole ('button', { name: '追加' }))
await waitFor (() => {
expect (api.apiPost).toHaveBeenCalledWith ('/materials', expect.any (FormData))
})
const formData = api.apiPost.mock.calls[0]?.[1] as FormData
expect (formData.get ('tag')).toBe ('虹夏')
expect (formData.get ('url')).toBe ('https://example.com/ref')
expect (toastApi.toast).toHaveBeenCalledWith ({ title: '送信成功!' })
})
it ('shows validation errors for file and url fields', async () => {
api.isApiError.mockReturnValue (true)
api.apiPost.mockRejectedValueOnce ({
response: {
status: 422,
data: {
type: 'validation_error',
message: '入力内容を確認してください.',
errors: {
file: ['ファイルまたは URL は必須です.'],
url: ['ファイルまたは URL は必須です.'],
},
base_errors: [],
},
},
})
renderWithProviders ()
fireEvent.change (screen.getAllByRole ('textbox')[0], { target: { value: '虹夏' } })
fireEvent.click (screen.getByRole ('button', { name: '追加' }))
expect (await screen.findAllByText ('ファイルまたは URL は必須です.')).toHaveLength (2)
expect (screen.getAllByRole ('textbox')[1]).toHaveAttribute ('aria-invalid', 'true')
})
})