このコミットが含まれているのは:
@@ -7,9 +7,9 @@ import { buildMaterial, buildTag } from '@/test/factories'
|
||||
import { renderWithProviders } from '@/test/render'
|
||||
|
||||
const api = vi.hoisted (() => ({
|
||||
apiGet: vi.fn (),
|
||||
apiPatch: vi.fn (),
|
||||
apiPut: vi.fn (),
|
||||
apiGet: vi.fn (),
|
||||
apiPut: vi.fn (),
|
||||
isApiError: vi.fn (),
|
||||
}))
|
||||
|
||||
const wikiApi = vi.hoisted (() => ({
|
||||
@@ -35,7 +35,11 @@ const renderPage = () =>
|
||||
describe ('MaterialDetailPage', () => {
|
||||
beforeEach (() => {
|
||||
vi.clearAllMocks ()
|
||||
api.apiGet.mockResolvedValue ([])
|
||||
api.apiGet.mockImplementation (async (path: string) =>
|
||||
path === '/tags/autocomplete'
|
||||
? []
|
||||
: buildMaterial ({ id: 8 }))
|
||||
api.isApiError.mockReturnValue (false)
|
||||
wikiApi.fetchWikiPages.mockResolvedValue ([])
|
||||
vi.stubGlobal ('fetch', vi.fn (async () => ({
|
||||
blob: async () => new Blob (['image'], { type: 'image/png' }),
|
||||
@@ -86,4 +90,22 @@ describe ('MaterialDetailPage', () => {
|
||||
expect (formData.get ('export_paths[legacy_drive]')).toBe ('素材/new.png')
|
||||
expect (toastApi.toast).toHaveBeenCalledWith ({ title: '更新成功!' })
|
||||
})
|
||||
|
||||
it ('shows not found when material API returns 404', async () => {
|
||||
api.isApiError.mockReturnValue (true)
|
||||
api.apiGet.mockRejectedValueOnce ({ response: { status: 404 } })
|
||||
|
||||
renderPage ()
|
||||
|
||||
expect (await screen.findByText ('素材が見つかりませんでした.')).toBeInTheDocument ()
|
||||
})
|
||||
|
||||
it ('shows an error for non-404 material API failures', async () => {
|
||||
api.isApiError.mockReturnValue (false)
|
||||
api.apiGet.mockRejectedValueOnce (new Error ('network error'))
|
||||
|
||||
renderPage ()
|
||||
|
||||
expect (await screen.findByText ('素材の取得に失敗しました.')).toBeInTheDocument ()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { screen, waitFor } from '@testing-library/react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import MaterialListPage from '@/pages/materials/MaterialListPage'
|
||||
import { buildMaterial, buildTag } from '@/test/factories'
|
||||
@@ -12,51 +12,118 @@ const api = vi.hoisted (() => ({
|
||||
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',
|
||||
)
|
||||
beforeEach (() => {
|
||||
vi.clearAllMocks ()
|
||||
api.apiGet.mockResolvedValue ({ materials: [], count: 0 })
|
||||
})
|
||||
|
||||
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' })
|
||||
it ('loads the material index on the initial page', async () => {
|
||||
renderWithProviders (<MaterialListPage/>, { route: '/materials' })
|
||||
|
||||
await waitFor (() => {
|
||||
expect (api.apiGet).toHaveBeenCalledWith (
|
||||
'/tags/name/%E7%B4%A0%E6%9D%90/materials',
|
||||
'/materials',
|
||||
{ params: {
|
||||
tag_state: 'all',
|
||||
media_kind: 'all',
|
||||
sort: 'created_at',
|
||||
direction: 'desc',
|
||||
page: 1,
|
||||
limit: 20,
|
||||
} },
|
||||
)
|
||||
})
|
||||
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 (
|
||||
expect (await screen.findByText ('素材はありません.')).toBeInTheDocument ()
|
||||
expect (screen.getByRole ('link', { name: '新規素材を追加' })).toHaveAttribute (
|
||||
'href',
|
||||
'/materials/new?tag=%E6%9C%AA%E7%99%BB%E9%8C%B2',
|
||||
'/materials/new',
|
||||
)
|
||||
expect (screen.getByRole ('link', { name: '履歴' })).toHaveAttribute (
|
||||
'href',
|
||||
'/materials/changes',
|
||||
)
|
||||
})
|
||||
|
||||
it ('shows materials in the default card view', async () => {
|
||||
api.apiGet.mockResolvedValueOnce ({
|
||||
materials: [
|
||||
buildMaterial ({
|
||||
id: 8,
|
||||
tag: buildTag ({ name: '素材タグ', category: 'material' }),
|
||||
thumbnail: 'thumb.png',
|
||||
mediaKind: 'image',
|
||||
contentType: 'image/png',
|
||||
}),
|
||||
],
|
||||
count: 1,
|
||||
})
|
||||
|
||||
renderWithProviders (<MaterialListPage/>, { route: '/materials' })
|
||||
|
||||
expect ((await screen.findByText ('素材タグ')).closest ('a'))
|
||||
.toHaveAttribute ('href', '/materials/8')
|
||||
expect (screen.getByText (/画像 \/ 令和8年1月2日/)).toBeInTheDocument ()
|
||||
})
|
||||
|
||||
it ('submits list filters as material index params', async () => {
|
||||
renderWithProviders (<MaterialListPage/>, { route: '/materials' })
|
||||
|
||||
fireEvent.change (screen.getByPlaceholderText ('タグ名 / URL / ファイル名'), {
|
||||
target: { value: '虹夏' },
|
||||
})
|
||||
const selects = screen.getAllByRole ('combobox')
|
||||
fireEvent.change (selects[0], {
|
||||
target: { value: 'untagged' },
|
||||
})
|
||||
fireEvent.change (selects[1], {
|
||||
target: { value: 'image' },
|
||||
})
|
||||
fireEvent.click (screen.getByRole ('button', { name: '検索' }))
|
||||
|
||||
await waitFor (() => {
|
||||
expect (api.apiGet).toHaveBeenCalledWith (
|
||||
'/materials',
|
||||
expect.objectContaining ({ params: expect.objectContaining ({
|
||||
q: '虹夏',
|
||||
tag_state: 'untagged',
|
||||
media_kind: 'image',
|
||||
}) }),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it ('keeps a route back to the material search top for untagged materials', async () => {
|
||||
renderWithProviders (
|
||||
<MaterialListPage/>,
|
||||
{ route: '/materials?tag_state=untagged&material_filter=any' },
|
||||
)
|
||||
|
||||
expect (await screen.findByRole (
|
||||
'link',
|
||||
{ name: '素材検索トップへ戻る' },
|
||||
)).toHaveAttribute ('href', '/materials?material_filter=any')
|
||||
})
|
||||
|
||||
it ('uses list view for detailed material rows', async () => {
|
||||
api.apiGet.mockResolvedValueOnce ({
|
||||
materials: [
|
||||
buildMaterial ({
|
||||
id: 9,
|
||||
tag: buildTag ({ name: '詳細素材', category: 'material' }),
|
||||
mediaKind: 'file_other',
|
||||
fileByteSize: 2048,
|
||||
}),
|
||||
],
|
||||
count: 1,
|
||||
})
|
||||
|
||||
renderWithProviders (<MaterialListPage/>, { route: '/materials?view=list' })
|
||||
|
||||
expect (await screen.findByRole ('link', { name: '詳細素材' })).toHaveAttribute (
|
||||
'href',
|
||||
'/materials/9',
|
||||
)
|
||||
expect (screen.getByText ('サイズ:')).toBeInTheDocument ()
|
||||
expect (screen.getByText ('2.0 KB')).toBeInTheDocument ()
|
||||
})
|
||||
})
|
||||
|
||||
新しい課題から参照
ユーザをブロックする