このコミットが含まれているのは:
2026-07-16 00:44:11 +09:00
コミット 2e1b4449ba
18個のファイルの変更1522行の追加0行の削除
+114
ファイルの表示
@@ -0,0 +1,114 @@
import { useCallback, useEffect } from 'react'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import DialogueProvider from '@/components/dialogues/DialogueProvider'
import useDialogue from '@/lib/dialogues/useDialogue'
import type { DialogueFormControls } from '@/lib/dialogues/useDialogue'
const FormBody = (
{ controls,
onSelect }: { controls: DialogueFormControls
onSelect: () => Promise<boolean> | boolean },
) => {
useEffect (() => {
controls.setActions ([{
label: '左操作',
placement: 'start',
onSelect }, {
label: '保存',
onSelect: () => true }])
}, [controls, onSelect])
return <div></div>
}
const NestedConfirmFormBody = ({ controls }: { controls: DialogueFormControls }) => {
const reset = useCallback (async () => {
await controls.confirm ({
title: '変更をリセットしますか?',
confirmText: 'リセット' })
return false
}, [controls])
return <FormBody controls={controls} onSelect={reset}/>
}
describe ('DialogueProvider', () => {
it ('keeps ordinary dialogues in FIFO order', async () => {
const Launcher = () => {
const dialogue = useDialogue ()
return (
<button
onClick={() => {
void dialogue.confirm ({ title: '一件目' })
void dialogue.confirm ({ title: '二件目' })
}}>
</button>)
}
render (<DialogueProvider><Launcher/></DialogueProvider>)
fireEvent.click (screen.getByRole ('button', { name: '開く' }))
expect (screen.getByText ('一件目')).toBeInTheDocument ()
expect (screen.queryByText ('二件目')).not.toBeInTheDocument ()
fireEvent.click (screen.getByRole ('button', { name: '確定' }))
expect (await screen.findByText ('二件目')).toBeInTheDocument ()
})
it ('keeps a large form open when an action returns false', async () => {
const action = vi.fn ().mockResolvedValue (false)
const Launcher = () => {
const dialogue = useDialogue ()
return (
<button
onClick={() => void dialogue.form ({
title: '投稿を編輯',
description: '説明',
size: 'large',
body: controls => <FormBody controls={controls} onSelect={action}/> })}>
</button>)
}
render (<DialogueProvider><Launcher/></DialogueProvider>)
fireEvent.click (screen.getByRole ('button', { name: '開く' }))
const dialogue = screen.getByRole ('dialog')
expect (dialogue).toHaveClass ('max-h-[calc(100dvh-1rem)]', 'flex-col', 'max-w-3xl')
await waitFor (() => expect (screen.getByRole ('button', { name: '左操作' }))
.toBeInTheDocument ())
expect (screen.getByRole ('button', { name: '左操作' })).toHaveClass ('w-full', 'sm:w-auto')
fireEvent.click (screen.getByRole ('button', { name: '左操作' }))
await waitFor (() => expect (action).toHaveBeenCalledTimes (1))
expect (screen.getByText ('投稿を編輯')).toBeInTheDocument ()
})
it ('opens a nested confirmation over a form and returns to the same form', async () => {
const Launcher = () => {
const dialogue = useDialogue ()
return (
<button
onClick={() => void dialogue.form ({
title: '投稿を編輯',
body: controls => <NestedConfirmFormBody controls={controls}/> })}>
</button>)
}
render (<DialogueProvider><Launcher/></DialogueProvider>)
fireEvent.click (screen.getByRole ('button', { name: '開く' }))
const action = await screen.findByRole ('button', { name: '左操作' })
fireEvent.click (action)
expect (await screen.findByText ('変更をリセットしますか?')).toBeInTheDocument ()
fireEvent.click (screen.getByRole ('button', { name: 'リセット' }))
await waitFor (() => {
expect (screen.queryByText ('変更をリセットしますか?')).not.toBeInTheDocument ()
})
expect (screen.getByText ('投稿を編輯')).toBeInTheDocument ()
})
})