ぼざクリタグ広場 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.
 
 
 
 

110 lines
3.3 KiB

  1. import { fireEvent, screen, waitFor } from '@testing-library/react'
  2. import { Route, Routes } from 'react-router-dom'
  3. import { beforeEach, describe, expect, it, vi } from 'vitest'
  4. import PostDetailPage from '@/pages/posts/PostDetailPage'
  5. import { buildPost, buildUser } from '@/test/factories'
  6. import { renderWithProviders } from '@/test/render'
  7. import type { ReactNode } from 'react'
  8. const postsApi = vi.hoisted (() => ({
  9. fetchPost: vi.fn (),
  10. toggleViewedFlg: vi.fn (),
  11. }))
  12. const api = vi.hoisted (() => ({
  13. isApiError: vi.fn (() => false),
  14. }))
  15. vi.mock ('@/lib/posts', () => postsApi)
  16. vi.mock ('@/lib/api', () => api)
  17. vi.mock ('@/components/PostEmbed', () => ({
  18. default: ({ post }: { post: { url: string } }) => <div>Embed:{post.url}</div>,
  19. }))
  20. vi.mock ('@/components/TagDetailSidebar', () => ({
  21. default: () => <aside>Tag sidebar</aside>,
  22. }))
  23. vi.mock ('@/components/PostEditForm', () => ({
  24. default: () => <div>Post edit form</div>,
  25. }))
  26. vi.mock ('framer-motion', () => ({
  27. motion: {
  28. div: ({ children }: { children?: ReactNode }) => <div>{children}</div>,
  29. main: ({ children }: { children?: ReactNode }) => <main>{children}</main>,
  30. },
  31. }))
  32. const renderPage = (user = buildUser ({ role: 'member' })) =>
  33. renderWithProviders (
  34. <Routes>
  35. <Route path="/posts/:id" element={<PostDetailPage user={user}/>}/>
  36. </Routes>,
  37. { route: '/posts/9' },
  38. )
  39. describe ('PostDetailPage', () => {
  40. beforeEach (() => {
  41. vi.clearAllMocks ()
  42. postsApi.toggleViewedFlg.mockResolvedValue (undefined)
  43. })
  44. it ('loads and displays a post detail', async () => {
  45. postsApi.fetchPost.mockResolvedValue (
  46. buildPost ({
  47. id: 9,
  48. url: 'https://example.com/9',
  49. related: [],
  50. thumbnail: null,
  51. thumbnailBase: null,
  52. }),
  53. )
  54. renderPage ()
  55. await waitFor (() => {
  56. expect (postsApi.fetchPost).toHaveBeenCalledWith ('9')
  57. })
  58. expect (await screen.findByText ('Embed:https://example.com/9')).toBeInTheDocument ()
  59. expect (screen.getByRole ('button', { name: '未閲覧' })).toBeInTheDocument ()
  60. expect (screen.getByText ('まだないよ(笑)')).toBeInTheDocument ()
  61. })
  62. it ('toggles viewed state through the mutation', async () => {
  63. postsApi.fetchPost.mockResolvedValue (
  64. buildPost ({ id: 9, viewed: false, thumbnail: null, thumbnailBase: null }),
  65. )
  66. renderPage ()
  67. fireEvent.click (await screen.findByRole ('button', { name: '未閲覧' }))
  68. await waitFor (() => {
  69. expect (postsApi.toggleViewedFlg).toHaveBeenCalledWith ('9', true)
  70. })
  71. })
  72. it ('shows the edit tab for members', async () => {
  73. postsApi.fetchPost.mockResolvedValue (
  74. buildPost ({ id: 9, thumbnail: null, thumbnailBase: null }),
  75. )
  76. renderPage (buildUser ({ role: 'member' }))
  77. fireEvent.click (await screen.findByText ('編輯'))
  78. expect (screen.getByText ('Post edit form')).toBeInTheDocument ()
  79. })
  80. it ('hides the edit tab for guests', async () => {
  81. postsApi.fetchPost.mockResolvedValue (
  82. buildPost ({ id: 9, thumbnail: null, thumbnailBase: null }),
  83. )
  84. renderPage (buildUser ({ role: 'guest' }))
  85. expect (await screen.findByText ('関聯')).toBeInTheDocument ()
  86. expect (screen.queryByText ('編輯')).not.toBeInTheDocument ()
  87. })
  88. })