このコミットが含まれているのは:
2026-07-16 22:05:40 +09:00
コミット 7f8cce39bc
4個のファイルの変更36行の追加40行の削除
+25 -1
ファイルの表示
@@ -1,4 +1,4 @@
import { render, screen } from '@testing-library/react' import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import PostThumbnailPreview from '@/components/posts/PostThumbnailPreview' import PostThumbnailPreview from '@/components/posts/PostThumbnailPreview'
@@ -9,4 +9,28 @@ describe ('PostThumbnailPreview', () => {
expect (screen.getByRole ('img')).toHaveAttribute ('src', 'blob:preview') expect (screen.getByRole ('img')).toHaveAttribute ('src', 'blob:preview')
}) })
it ('renders an empty thumbnail frame without text when the URL is empty', () => {
const { container } = render (
<PostThumbnailPreview url="" className="h-10 w-10"/>)
expect (screen.queryByRole ('img')).toBeNull ()
expect (screen.queryByText ('サムネールを表示できません')).toBeNull ()
expect (screen.queryByText ('なし')).toBeNull ()
expect (container.querySelector ('div.rounded.border.bg-muted')).not.toBeNull ()
expect (container.textContent).toBe ('')
})
it ('renders an empty thumbnail frame without text when image loading fails', () => {
const { container } = render (
<PostThumbnailPreview url="blob:preview" className="h-10 w-10"/>)
fireEvent.error (screen.getByRole ('img'))
expect (screen.queryByRole ('img')).toBeNull ()
expect (screen.queryByText ('サムネールを表示できません')).toBeNull ()
expect (screen.queryByText ('なし')).toBeNull ()
expect (container.querySelector ('div.rounded.border.bg-muted')).not.toBeNull ()
expect (container.textContent).toBe ('')
})
}) })
+2 -19
ファイルの表示
@@ -19,30 +19,13 @@ const PostThumbnailPreview: FC<Props> = (
setFailed (false) setFailed (false)
}, [url]) }, [url])
if (!(url)) if (!(url) || failed)
{ {
return ( return (
<div <div
className={cn ( className={cn (
className, className,
'flex items-center justify-center rounded border', 'rounded border border-border bg-muted')}/>)
'border-border bg-muted text-xs text-muted-foreground')}>
</div>)
}
if (failed)
{
return (
<div
className={cn (
className,
'flex items-center justify-center rounded border',
'border-amber-300 bg-amber-50 p-2 text-center text-xs',
'text-amber-700 dark:border-amber-900 dark:bg-amber-950',
'dark:text-amber-200')}>
</div>)
} }
return ( return (
+8 -2
ファイルの表示
@@ -38,12 +38,18 @@ describe ('PostImportThumbnailPreview', () => {
it ('does not render the unsafe URL directly when preview fetching fails', async () => { it ('does not render the unsafe URL directly when preview fetching fails', async () => {
api.apiGet.mockRejectedValueOnce (new Error ('unsafe')) api.apiGet.mockRejectedValueOnce (new Error ('unsafe'))
render ( const { container } = render (
<PostImportThumbnailPreview <PostImportThumbnailPreview
url="http://127.0.0.1/private.png" url="http://127.0.0.1/private.png"
className="h-10 w-10"/>) className="h-10 w-10"/>)
expect (await screen.findByText ('サムネールを表示できません')).toBeInTheDocument () await waitFor (() => {
expect (screen.queryByRole ('img')).toBeNull ()
})
expect (screen.queryByText ('サムネールを表示できません')).toBeNull ()
expect (screen.queryByText ('なし')).toBeNull ()
expect (container.querySelector ('div.rounded.border.bg-muted')).not.toBeNull ()
expect (container.textContent).toBe ('')
expect (screen.queryByRole ('img')).toBeNull () expect (screen.queryByRole ('img')).toBeNull ()
}) })
+1 -18
ファイルの表示
@@ -2,7 +2,6 @@ import { useEffect, useRef, useState } from 'react'
import PostThumbnailPreview from '@/components/posts/PostThumbnailPreview' import PostThumbnailPreview from '@/components/posts/PostThumbnailPreview'
import { apiGet } from '@/lib/api' import { apiGet } from '@/lib/api'
import { cn } from '@/lib/utils'
import type { FC } from 'react' import type { FC } from 'react'
@@ -18,7 +17,6 @@ const PostImportThumbnailPreview: FC<Props> = (
className = 'h-16 w-16' }, className = 'h-16 w-16' },
) => { ) => {
const [previewUrl, setPreviewUrl] = useState ('') const [previewUrl, setPreviewUrl] = useState ('')
const [unavailable, setUnavailable] = useState (false)
const previewUrlRef = useRef ('') const previewUrlRef = useRef ('')
useEffect (() => { useEffect (() => {
@@ -28,7 +26,6 @@ const PostImportThumbnailPreview: FC<Props> = (
previewUrlRef.current = '' previewUrlRef.current = ''
} }
setPreviewUrl ('') setPreviewUrl ('')
setUnavailable (false)
if (!(url)) if (!(url))
return return
@@ -51,7 +48,7 @@ const PostImportThumbnailPreview: FC<Props> = (
catch catch
{ {
if (active) if (active)
setUnavailable (true) setPreviewUrl ('')
} }
} }
@@ -67,20 +64,6 @@ const PostImportThumbnailPreview: FC<Props> = (
} }
}, [url]) }, [url])
if (unavailable)
{
return (
<div
className={cn (
className,
'flex items-center justify-center rounded border',
'border-amber-300 bg-amber-50 p-2 text-center text-xs',
'text-amber-700 dark:border-amber-900 dark:bg-amber-950',
'dark:text-amber-200')}>
</div>)
}
return ( return (
<PostThumbnailPreview <PostThumbnailPreview
url={previewUrl} url={previewUrl}