このコミットが含まれているのは:
@@ -0,0 +1,26 @@
|
||||
import { screen } from '@testing-library/react'
|
||||
import { Route, Routes } from 'react-router-dom'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import MaterialBasePage from '@/pages/materials/MaterialBasePage'
|
||||
import { renderWithProviders } from '@/test/render'
|
||||
|
||||
vi.mock ('@/components/MaterialSidebar', () => ({
|
||||
default: () => <aside>Material sidebar</aside>,
|
||||
}))
|
||||
|
||||
describe ('MaterialBasePage', () => {
|
||||
it ('renders the material sidebar and nested route outlet', () => {
|
||||
renderWithProviders (
|
||||
<Routes>
|
||||
<Route path="/materials" element={<MaterialBasePage/>}>
|
||||
<Route index element={<div>Outlet content</div>}/>
|
||||
</Route>
|
||||
</Routes>,
|
||||
{ route: '/materials' },
|
||||
)
|
||||
|
||||
expect (screen.getByText ('Material sidebar')).toBeInTheDocument ()
|
||||
expect (screen.getByText ('Outlet content')).toBeInTheDocument ()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,86 @@
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import { Route, Routes } from 'react-router-dom'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import MaterialDetailPage from '@/pages/materials/MaterialDetailPage'
|
||||
import { buildMaterial, buildTag } from '@/test/factories'
|
||||
import { renderWithProviders } from '@/test/render'
|
||||
|
||||
const api = vi.hoisted (() => ({
|
||||
apiGet: vi.fn (),
|
||||
apiPut: vi.fn (),
|
||||
}))
|
||||
|
||||
const wikiApi = vi.hoisted (() => ({
|
||||
fetchWikiPages: vi.fn (),
|
||||
}))
|
||||
|
||||
const toastApi = vi.hoisted (() => ({
|
||||
toast: vi.fn (),
|
||||
}))
|
||||
|
||||
vi.mock ('@/lib/api', () => api)
|
||||
vi.mock ('@/lib/wiki', () => wikiApi)
|
||||
vi.mock ('@/components/ui/use-toast', () => toastApi)
|
||||
|
||||
const renderPage = () =>
|
||||
renderWithProviders (
|
||||
<Routes>
|
||||
<Route path="/materials/:id" element={<MaterialDetailPage/>}/>
|
||||
</Routes>,
|
||||
{ route: '/materials/8' },
|
||||
)
|
||||
|
||||
describe ('MaterialDetailPage', () => {
|
||||
beforeEach (() => {
|
||||
vi.clearAllMocks ()
|
||||
api.apiGet.mockResolvedValue ([])
|
||||
wikiApi.fetchWikiPages.mockResolvedValue ([])
|
||||
vi.stubGlobal ('fetch', vi.fn (async () => ({
|
||||
blob: async () => new Blob (['image'], { type: 'image/png' }),
|
||||
})))
|
||||
})
|
||||
|
||||
it ('loads and displays material detail', async () => {
|
||||
api.apiGet.mockResolvedValueOnce (
|
||||
buildMaterial ({
|
||||
id: 8,
|
||||
tag: buildTag ({ name: '素材タグ' }),
|
||||
file: 'image.png',
|
||||
contentType: 'image/png',
|
||||
}),
|
||||
)
|
||||
|
||||
renderPage ()
|
||||
|
||||
await waitFor (() => {
|
||||
expect (api.apiGet).toHaveBeenCalledWith ('/materials/8')
|
||||
})
|
||||
expect (await screen.findByAltText ('素材タグ')).toHaveAttribute ('src', 'image.png')
|
||||
})
|
||||
|
||||
it ('submits edited material fields', async () => {
|
||||
api.apiGet.mockResolvedValueOnce (
|
||||
buildMaterial ({ id: 8, tag: buildTag ({ name: 'old' }), url: '' }),
|
||||
)
|
||||
api.apiPut.mockResolvedValueOnce (
|
||||
buildMaterial ({ id: 8, tag: buildTag ({ name: 'new' }) }),
|
||||
)
|
||||
|
||||
renderPage ()
|
||||
|
||||
fireEvent.click (await screen.findByText ('編輯'))
|
||||
const textboxes = screen.getAllByRole ('textbox')
|
||||
fireEvent.change (textboxes[0], { target: { value: 'new' } })
|
||||
fireEvent.change (textboxes[1], { target: { value: 'https://example.com/ref' } })
|
||||
fireEvent.click (screen.getByRole ('button', { name: '更新' }))
|
||||
|
||||
await waitFor (() => {
|
||||
expect (api.apiPut).toHaveBeenCalledWith ('/materials/8', expect.any (FormData))
|
||||
})
|
||||
const formData = api.apiPut.mock.calls[0]?.[1] as FormData
|
||||
expect (formData.get ('tag')).toBe ('new')
|
||||
expect (formData.get ('url')).toBe ('https://example.com/ref')
|
||||
expect (toastApi.toast).toHaveBeenCalledWith ({ title: '更新成功!' })
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,62 @@
|
||||
import { screen, waitFor } from '@testing-library/react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import MaterialListPage from '@/pages/materials/MaterialListPage'
|
||||
import { buildMaterial, buildTag } from '@/test/factories'
|
||||
import { renderWithProviders } from '@/test/render'
|
||||
|
||||
const api = vi.hoisted (() => ({
|
||||
apiGet: vi.fn (),
|
||||
}))
|
||||
|
||||
vi.mock ('@/lib/api', () => api)
|
||||
|
||||
describe ('MaterialListPage', () => {
|
||||
it ('shows the empty selection guide without a tag query', () => {
|
||||
renderWithProviders (<MaterialListPage/>, { route: '/materials' })
|
||||
|
||||
expect (screen.getByText ('左のリストから照会したいタグを選択してください。')).toBeInTheDocument ()
|
||||
expect (screen.getByRole ('link', { name: '素材を新規追加する' })).toHaveAttribute (
|
||||
'href',
|
||||
'/materials/new',
|
||||
)
|
||||
})
|
||||
|
||||
it ('loads materials for a tag query', async () => {
|
||||
const tag = {
|
||||
...buildTag ({
|
||||
id: 4,
|
||||
name: '素材タグ',
|
||||
category: 'material',
|
||||
}),
|
||||
material: buildMaterial ({ id: 8, contentType: 'image/png', file: 'image.png' }),
|
||||
children: [],
|
||||
}
|
||||
api.apiGet.mockResolvedValueOnce (tag)
|
||||
|
||||
renderWithProviders (<MaterialListPage/>, { route: '/materials?tag=%E7%B4%A0%E6%9D%90' })
|
||||
|
||||
await waitFor (() => {
|
||||
expect (api.apiGet).toHaveBeenCalledWith (
|
||||
'/tags/name/%E7%B4%A0%E6%9D%90/materials',
|
||||
)
|
||||
})
|
||||
expect (await screen.findByRole ('link', { name: '素材タグ' })).toBeInTheDocument ()
|
||||
expect (screen.getByRole ('link', { name: '' })).toHaveAttribute ('href', '/materials/8')
|
||||
})
|
||||
|
||||
it ('offers adding a missing non-meme material', async () => {
|
||||
api.apiGet.mockResolvedValueOnce ({
|
||||
...buildTag ({ name: '未登録', category: 'material' }),
|
||||
material: null,
|
||||
children: [],
|
||||
})
|
||||
|
||||
renderWithProviders (<MaterialListPage/>, { route: '/materials?tag=x' })
|
||||
|
||||
expect (await screen.findByRole ('link', { name: '追加' })).toHaveAttribute (
|
||||
'href',
|
||||
'/materials/new?tag=%E6%9C%AA%E7%99%BB%E9%8C%B2',
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,38 @@
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import MaterialNewPage from '@/pages/materials/MaterialNewPage'
|
||||
import { renderWithProviders } from '@/test/render'
|
||||
|
||||
const api = vi.hoisted (() => ({
|
||||
apiPost: vi.fn (),
|
||||
}))
|
||||
|
||||
const toastApi = vi.hoisted (() => ({
|
||||
toast: vi.fn (),
|
||||
}))
|
||||
|
||||
vi.mock ('@/lib/api', () => api)
|
||||
vi.mock ('@/components/ui/use-toast', () => toastApi)
|
||||
|
||||
describe ('MaterialNewPage', () => {
|
||||
it ('initializes tag from query and submits form data', async () => {
|
||||
api.apiPost.mockResolvedValueOnce ({})
|
||||
|
||||
renderWithProviders (<MaterialNewPage/>, { 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: '送信成功!' })
|
||||
})
|
||||
})
|
||||
新しい課題から参照
ユーザをブロックする