import { fireEvent, screen, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import PostSearchPage from '@/pages/posts/PostSearchPage' import { buildPost, buildTag } from '@/test/factories' import { renderWithProviders } from '@/test/render' const postsApi = vi.hoisted (() => ({ fetchPosts: vi.fn (), })) const api = vi.hoisted (() => ({ apiGet: vi.fn (), })) vi.mock ('@/lib/posts', () => postsApi) vi.mock ('@/lib/api', () => api) describe ('PostSearchPage', () => { beforeEach (() => { vi.clearAllMocks () api.apiGet.mockResolvedValue ([]) }) it ('loads posts from URL search filters', async () => { postsApi.fetchPosts.mockResolvedValueOnce ({ posts: [buildPost ({ id: 4, title: '検索対象', tags: [buildTag ({ name: '虹夏' })] })], count: 1, }) renderWithProviders ( , { route: '/posts/search?title=%E6%A4%9C%E7%B4%A2&tags=x&match=any&page=2' }, ) await waitFor (() => { expect (postsApi.fetchPosts).toHaveBeenCalledWith ( expect.objectContaining ({ title: '検索', tags: 'x', match: 'any', page: 2, }), ) }) expect ((await screen.findAllByRole ('link', { name: '検索対象' }))[0]).toHaveAttribute ( 'href', '/posts/4', ) }) it ('submits form state into a new search', async () => { postsApi.fetchPosts.mockResolvedValue ({ posts: [], count: 0 }) renderWithProviders (, { route: '/posts/search' }) const textboxes = screen.getAllByRole ('textbox') fireEvent.change (textboxes[0], { target: { value: 'title' } }) fireEvent.change (textboxes[1], { target: { value: 'https://example.com' } }) fireEvent.change (textboxes[2], { target: { value: 'tag' } }) fireEvent.click (screen.getByRole ('radio', { name: 'OR' })) fireEvent.click (screen.getByRole ('button', { name: '検索' })) await waitFor (() => { expect (postsApi.fetchPosts).toHaveBeenLastCalledWith ( expect.objectContaining ({ title: 'title', url: 'https://example.com', tags: 'tag', match: 'any', page: 1, }), ) }) }) it ('shows the no-result message', async () => { postsApi.fetchPosts.mockResolvedValueOnce ({ posts: [], count: 0 }) renderWithProviders (, { route: '/posts/search' }) expect (await screen.findByText ('結果ないよ(笑)')).toBeInTheDocument () }) })