f1181e8510
Reviewed-on: #413 Co-authored-by: miteruzo <miteruzo@naver.com> Co-committed-by: miteruzo <miteruzo@naver.com>
117 行
3.9 KiB
TypeScript
117 行
3.9 KiB
TypeScript
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',
|
|
'md: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 ()
|
|
})
|
|
})
|