ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

85 lines
2.5 KiB

  1. import { fireEvent, screen, waitFor } from '@testing-library/react'
  2. import { beforeEach, describe, expect, it, vi } from 'vitest'
  3. import PostSearchPage from '@/pages/posts/PostSearchPage'
  4. import { buildPost, buildTag } from '@/test/factories'
  5. import { renderWithProviders } from '@/test/render'
  6. const postsApi = vi.hoisted (() => ({
  7. fetchPosts: vi.fn (),
  8. }))
  9. const api = vi.hoisted (() => ({
  10. apiGet: vi.fn (),
  11. }))
  12. vi.mock ('@/lib/posts', () => postsApi)
  13. vi.mock ('@/lib/api', () => api)
  14. describe ('PostSearchPage', () => {
  15. beforeEach (() => {
  16. vi.clearAllMocks ()
  17. api.apiGet.mockResolvedValue ([])
  18. })
  19. it ('loads posts from URL search filters', async () => {
  20. postsApi.fetchPosts.mockResolvedValueOnce ({
  21. posts: [buildPost ({ id: 4, title: '検索対象', tags: [buildTag ({ name: '虹夏' })] })],
  22. count: 1,
  23. })
  24. renderWithProviders (
  25. <PostSearchPage/>,
  26. { route: '/posts/search?title=%E6%A4%9C%E7%B4%A2&tags=x&match=any&page=2' },
  27. )
  28. await waitFor (() => {
  29. expect (postsApi.fetchPosts).toHaveBeenCalledWith (
  30. expect.objectContaining ({
  31. title: '検索',
  32. tags: 'x',
  33. match: 'any',
  34. page: 2,
  35. }),
  36. )
  37. })
  38. expect ((await screen.findAllByRole ('link', { name: '検索対象' }))[0]).toHaveAttribute (
  39. 'href',
  40. '/posts/4',
  41. )
  42. })
  43. it ('submits form state into a new search', async () => {
  44. postsApi.fetchPosts.mockResolvedValue ({ posts: [], count: 0 })
  45. renderWithProviders (<PostSearchPage/>, { route: '/posts/search' })
  46. const textboxes = screen.getAllByRole ('textbox')
  47. fireEvent.change (textboxes[0], { target: { value: 'title' } })
  48. fireEvent.change (textboxes[1], { target: { value: 'https://example.com' } })
  49. fireEvent.change (textboxes[2], { target: { value: 'tag' } })
  50. fireEvent.click (screen.getByRole ('radio', { name: 'OR' }))
  51. fireEvent.click (screen.getByRole ('button', { name: '検索' }))
  52. await waitFor (() => {
  53. expect (postsApi.fetchPosts).toHaveBeenLastCalledWith (
  54. expect.objectContaining ({
  55. title: 'title',
  56. url: 'https://example.com',
  57. tags: 'tag',
  58. match: 'any',
  59. page: 1,
  60. }),
  61. )
  62. })
  63. })
  64. it ('shows the no-result message', async () => {
  65. postsApi.fetchPosts.mockResolvedValueOnce ({ posts: [], count: 0 })
  66. renderWithProviders (<PostSearchPage/>, { route: '/posts/search' })
  67. expect (await screen.findByText ('結果ないよ(笑)')).toBeInTheDocument ()
  68. })
  69. })