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') }) })