f5b632ed89
Reviewed-on: #397 Co-authored-by: miteruzo <miteruzo@naver.com> Co-committed-by: miteruzo <miteruzo@naver.com>
125 行
4.0 KiB
TypeScript
125 行
4.0 KiB
TypeScript
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'
|
|
import { CLIENT_SETTINGS_STORAGE_KEY } from '@/lib/settings'
|
|
|
|
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 (() => {
|
|
localStorage.clear ()
|
|
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 (
|
|
<PostSearchPage/>,
|
|
{ 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,
|
|
limit: 20,
|
|
}),
|
|
)
|
|
})
|
|
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 (<PostSearchPage/>, { 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 (<PostSearchPage/>, { route: '/posts/search' })
|
|
|
|
expect (await screen.findByText ('結果ないよ(笑)')).toBeInTheDocument ()
|
|
})
|
|
|
|
it ('uses URL limit before localStorage and stores the active list settings', async () => {
|
|
localStorage.setItem (
|
|
CLIENT_SETTINGS_STORAGE_KEY,
|
|
JSON.stringify ({ lists: { postSearch: { limit: 100, order: 'title:asc' } } }))
|
|
postsApi.fetchPosts.mockResolvedValueOnce ({ posts: [], count: 0 })
|
|
|
|
renderWithProviders (
|
|
<PostSearchPage/>,
|
|
{ route: '/posts/search?limit=50&order=created_at%3Adesc' },
|
|
)
|
|
|
|
await waitFor (() => {
|
|
expect (postsApi.fetchPosts).toHaveBeenCalledWith (
|
|
expect.objectContaining ({ limit: 50, order: 'created_at:desc' }),
|
|
)
|
|
})
|
|
expect (JSON.parse (localStorage.getItem (CLIENT_SETTINGS_STORAGE_KEY) ?? '{}'))
|
|
.toMatchObject ({ lists: { postSearch: { limit: 50, order: 'created_at:desc' } } })
|
|
})
|
|
|
|
it ('moves the compact limit control outside the search form and resets page on change', async () => {
|
|
postsApi.fetchPosts.mockResolvedValue ({ posts: [], count: 0 })
|
|
|
|
renderWithProviders (<PostSearchPage/>, { route: '/posts/search?page=4' })
|
|
|
|
const limitSelect = await screen.findByLabelText ('件数')
|
|
expect (limitSelect.closest ('form')).toBeNull ()
|
|
|
|
fireEvent.change (limitSelect, { target: { value: '100' } })
|
|
|
|
await waitFor (() => {
|
|
expect (postsApi.fetchPosts).toHaveBeenLastCalledWith (
|
|
expect.objectContaining ({ page: 1, limit: 100 }),
|
|
)
|
|
})
|
|
})
|
|
})
|