コミットを比較
2 コミット
| 作成者 | SHA1 | 日付 | |
|---|---|---|---|
| c7e60c9e43 | |||
| 881e940e24 |
@@ -898,6 +898,22 @@ RSpec.describe 'Posts API', type: :request do
|
|||||||
expect(json.fetch('video_ms')).to eq(180_500)
|
expect(json.fetch('video_ms')).to eq(180_500)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'creates a video post with number input duration seconds' do
|
||||||
|
sign_in_as(member)
|
||||||
|
|
||||||
|
post '/posts', params: post_write_params(
|
||||||
|
title: 'video post seconds',
|
||||||
|
url: 'https://example.com/video-post-seconds',
|
||||||
|
tags: '動画 spec_tag',
|
||||||
|
duration: '180.5',
|
||||||
|
thumbnail: dummy_upload
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
expect(Post.find(json.fetch('id')).video_ms).to eq(180_500)
|
||||||
|
expect(json.fetch('video_ms')).to eq(180_500)
|
||||||
|
end
|
||||||
|
|
||||||
it 'clears video_ms when the saved tags do not include 動画' do
|
it 'clears video_ms when the saved tags do not include 動画' do
|
||||||
sign_in_as(member)
|
sign_in_as(member)
|
||||||
|
|
||||||
|
|||||||
@@ -66,4 +66,27 @@ describe ('PostEditForm', () => {
|
|||||||
expect (onSave).toHaveBeenCalledWith (expect.objectContaining ({ versionNo: 5 }))
|
expect (onSave).toHaveBeenCalledWith (expect.objectContaining ({ versionNo: 5 }))
|
||||||
expect (toastApi.toast).toHaveBeenCalledWith ({ description: '更新しました.' })
|
expect (toastApi.toast).toHaveBeenCalledWith ({ description: '更新しました.' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it ('preserves duration while the video tag is temporarily removed', () => {
|
||||||
|
const post = buildPost ({
|
||||||
|
videoMs: 180_500,
|
||||||
|
tags: [
|
||||||
|
buildTag ({ id: 1, name: '動画', category: 'general' }),
|
||||||
|
buildTag ({ id: 2, name: 'general-tag', category: 'general' }),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
render (<PostEditForm post={post} onSave={vi.fn ()}/>)
|
||||||
|
|
||||||
|
expect (screen.getByRole ('spinbutton')).toHaveValue (180.5)
|
||||||
|
|
||||||
|
const tags = screen.getAllByRole ('textbox')[2]
|
||||||
|
fireEvent.change (tags, { target: { value: 'general-tag' } })
|
||||||
|
expect (screen.queryByRole ('spinbutton')).not.toBeInTheDocument ()
|
||||||
|
|
||||||
|
fireEvent.change (tags, {
|
||||||
|
target: { value: '動画 general-tag' },
|
||||||
|
})
|
||||||
|
expect (screen.getByRole ('spinbutton')).toHaveValue (180.5)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -153,11 +153,6 @@ const PostEditForm: FC<Props> = ({ post, onSave }) => {
|
|||||||
setDuration (videoMsToDurationValue (post.videoMs))
|
setDuration (videoMsToDurationValue (post.videoMs))
|
||||||
}, [post])
|
}, [post])
|
||||||
|
|
||||||
useEffect (() => {
|
|
||||||
if (!(videoFlg))
|
|
||||||
setDuration ('')
|
|
||||||
}, [videoFlg])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className="max-w-xl pt-2 space-y-4">
|
<form onSubmit={handleSubmit} className="max-w-xl pt-2 space-y-4">
|
||||||
<FieldError messages={baseErrors}/>
|
<FieldError messages={baseErrors}/>
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ describe ('posts API functions', () => {
|
|||||||
id: 5,
|
id: 5,
|
||||||
title: 'new title',
|
title: 'new title',
|
||||||
tags: 'tag',
|
tags: 'tag',
|
||||||
|
duration: null,
|
||||||
parentPostIds: '1 2',
|
parentPostIds: '1 2',
|
||||||
originalCreatedFrom: null,
|
originalCreatedFrom: null,
|
||||||
originalCreatedBefore: '2026-01-02T00:00:00Z',
|
originalCreatedBefore: '2026-01-02T00:00:00Z',
|
||||||
@@ -82,6 +83,7 @@ describe ('posts API functions', () => {
|
|||||||
{
|
{
|
||||||
title: 'new title',
|
title: 'new title',
|
||||||
tags: 'tag',
|
tags: 'tag',
|
||||||
|
duration: null,
|
||||||
parent_post_ids: '1 2',
|
parent_post_ids: '1 2',
|
||||||
original_created_from: null,
|
original_created_from: null,
|
||||||
original_created_before: '2026-01-02T00:00:00Z',
|
original_created_before: '2026-01-02T00:00:00Z',
|
||||||
|
|||||||
@@ -62,6 +62,24 @@ describe ('PostNewPage', () => {
|
|||||||
expect (toastApi.toast).toHaveBeenCalledWith ({ title: '投稿成功!' })
|
expect (toastApi.toast).toHaveBeenCalledWith ({ title: '投稿成功!' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it ('preserves duration while the video tag is temporarily removed', () => {
|
||||||
|
api.apiGet.mockResolvedValue ([])
|
||||||
|
|
||||||
|
renderWithProviders (<PostNewPage user={buildUser ({ role: 'member' })}/>)
|
||||||
|
|
||||||
|
const tags = screen.getAllByRole ('textbox')[3]
|
||||||
|
fireEvent.change (tags, { target: { value: '動画' } })
|
||||||
|
fireEvent.change (screen.getByRole ('spinbutton'), { target: { value: '180.5' } })
|
||||||
|
|
||||||
|
fireEvent.change (tags, { target: { value: 'general-tag' } })
|
||||||
|
expect (screen.queryByRole ('spinbutton')).not.toBeInTheDocument ()
|
||||||
|
|
||||||
|
fireEvent.change (tags, {
|
||||||
|
target: { value: '動画 general-tag' },
|
||||||
|
})
|
||||||
|
expect (screen.getByRole ('spinbutton')).toHaveValue (180.5)
|
||||||
|
})
|
||||||
|
|
||||||
it ('shows 422 validation errors for post fields', async () => {
|
it ('shows 422 validation errors for post fields', async () => {
|
||||||
api.apiGet.mockResolvedValue ([])
|
api.apiGet.mockResolvedValue ([])
|
||||||
api.isApiError.mockReturnValue (true)
|
api.isApiError.mockReturnValue (true)
|
||||||
|
|||||||
@@ -135,11 +135,6 @@ const PostNewPage: FC<Props> = ({ user }) => {
|
|||||||
fetchThumbnail ()
|
fetchThumbnail ()
|
||||||
}, [fetchThumbnail, thumbnailAutoFlg, url])
|
}, [fetchThumbnail, thumbnailAutoFlg, url])
|
||||||
|
|
||||||
useEffect (() => {
|
|
||||||
if (!(videoFlg))
|
|
||||||
setDuration ('')
|
|
||||||
}, [videoFlg])
|
|
||||||
|
|
||||||
if (!(editable))
|
if (!(editable))
|
||||||
return <Forbidden/>
|
return <Forbidden/>
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ const weights = buildTheatrePostSelectionWeights ({
|
|||||||
tags: [],
|
tags: [],
|
||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
|
const watchingUsers = [
|
||||||
|
{ id: 1, name: 'tester' },
|
||||||
|
{ id: 2, name: 'another' },
|
||||||
|
]
|
||||||
|
|
||||||
const renderPage = (user = buildUser ({ id: 1, role: 'member' })) =>
|
const renderPage = (user = buildUser ({ id: 1, role: 'member' })) =>
|
||||||
renderWithProviders (
|
renderWithProviders (
|
||||||
@@ -136,11 +140,11 @@ const mockDefaultApi = () => {
|
|||||||
postId: currentPost.id,
|
postId: currentPost.id,
|
||||||
postStartedAt: '2026-01-02T03:04:05.000Z',
|
postStartedAt: '2026-01-02T03:04:05.000Z',
|
||||||
postElapsedMs: 1_000,
|
postElapsedMs: 1_000,
|
||||||
watchingUsers: [{ id: 1, name: 'tester' }],
|
watchingUsers,
|
||||||
skipVote: {
|
skipVote: {
|
||||||
votesCount: 0,
|
votesCount: 0,
|
||||||
requiredCount: 2,
|
requiredCount: 2,
|
||||||
watchingUsersCount: 1,
|
watchingUsersCount: watchingUsers.length,
|
||||||
voted: false,
|
voted: false,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
@@ -150,11 +154,11 @@ const mockDefaultApi = () => {
|
|||||||
postId: currentPost.id,
|
postId: currentPost.id,
|
||||||
postStartedAt: '2026-01-02T03:04:05.000Z',
|
postStartedAt: '2026-01-02T03:04:05.000Z',
|
||||||
postElapsedMs: 2_000,
|
postElapsedMs: 2_000,
|
||||||
watchingUsers: [{ id: 1, name: 'tester' }],
|
watchingUsers,
|
||||||
skipVote: {
|
skipVote: {
|
||||||
votesCount: 1,
|
votesCount: 1,
|
||||||
requiredCount: 2,
|
requiredCount: 2,
|
||||||
watchingUsersCount: 1,
|
watchingUsersCount: watchingUsers.length,
|
||||||
voted: true,
|
voted: true,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|||||||
+2
-1
@@ -356,6 +356,7 @@ export type Tag = {
|
|||||||
hasWiki: boolean
|
hasWiki: boolean
|
||||||
materialId: number | null
|
materialId: number | null
|
||||||
hasDeerjikists: boolean
|
hasDeerjikists: boolean
|
||||||
|
children?: Tag[]
|
||||||
matchedAlias?: string | null }
|
matchedAlias?: string | null }
|
||||||
|
|
||||||
export type TagVersion = {
|
export type TagVersion = {
|
||||||
@@ -370,7 +371,7 @@ export type TagVersion = {
|
|||||||
createdAt: string
|
createdAt: string
|
||||||
createdByUser: { id: number; name: string | null } | null }
|
createdByUser: { id: number; name: string | null } | null }
|
||||||
|
|
||||||
export type TagWithSections = Tag & { sections: { beginMs: number
|
export type TagWithSections = Omit<Tag, 'children'> & { sections: { beginMs: number
|
||||||
endMs: number | null }[]
|
endMs: number | null }[]
|
||||||
children: TagWithSections[] }
|
children: TagWithSections[] }
|
||||||
|
|
||||||
|
|||||||
新しい課題から参照
ユーザをブロックする