所以我试图测试我的代码,但我的测试失败了,因为它无法根据条件找到一些元素
这是我想要测试的 Options.tsx 文件
这是我遇到的错误
✓ 当 showoprion 为 true 时显示更多水平图标(36 毫秒) ✕ 当 noteId 存在且不在笔记内时显示移动到、笔记删除和文件夹选择按钮(64 毫秒) ✕ 当存在folderId 和deleteOptions 时显示文件夹删除、编辑按钮(31 毫秒)
● 选项组件 › 当 noteId 存在且不在笔记内时,显示移动到、笔记删除和文件夹选择按钮
TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "Move to"
● 选项组件 › 当存在folderId 和deleteOptions 时显示文件夹删除、编辑按钮
TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "Delete Folder"
选项.tsx
import React, { useState } from 'react'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { useMutation, useQuery } from "convex/react";
import { toast } from "sonner";
import { api } from "../../../../convex/_generated/api";
import { MoreHorizontal, Plus} from 'lucide-react'
import { Id } from '../../../../convex/_generated/dataModel';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { useRouter } from 'next/navigation';
type Props = {}
const Options = ({
folder = true,
folderId,
deleteOptions = false,
showOption = false,
note = true,
noteId,
}:{
folder?:boolean,
folderId?:Id<"folder">
deleteOptions?:boolean
showOption:boolean
note?:boolean
noteId?:Id<"note">
}) => {
const folders = useQuery(api.folder.getAllFolders,{});
const createfolder = useMutation(api.folder.create);
const createnote = useMutation(api.note.create);
const deletefolder = useMutation(api.folder.deleteFolder)
const deletenote = useMutation(api.note.deleteNote)
const movenote = useMutation(api.note.moveNote)
const updatefoldertitle = useMutation(api.folder.updateTitleFolder)
const updatenotetitle = useMutation(api.note.updateTitleNote)
const [selectedFolder, setSelectedFolder] = useState<Id<"folder">>()
const [title, setTitle] = useState<string>("")
console.log(selectedFolder)
const router = useRouter()
const handleCreateFolder = () => {
const promise = createfolder({ title: "Untitled" })
.then((documentId) => router.push(`/folder/${documentId}`))
toast.promise(promise, {
loading: "Creating a new folder...",
success: "New folder created!",
error: "Failed to create a new folder."
});
};
const handleCreateNote = () => {
const promise = createnote({ title: "Untitled", folderId: folderId })
.then((documentId) => router.push(`/notes/${documentId}`))
toast.promise(promise, {
loading: "Creating a new note...",
success: "New note created!",
error: "Failed to create a new note."
});
};
const handleDeleteFolder = () => {
if(!folderId) return
const promise = deletefolder({folderId:folderId})
toast.promise(promise, {
loading: "Deleting the folder ...",
success: "Deleted folder successfully",
error: "Failed to delete folder"
});
}
const handleDeleteNote = () => {
if(!noteId) return
const promise = deletenote({noteId})
.then(() => router.push(`/notes`))
toast.promise(promise, {
loading: "Deleting the note ...",
success: "Deleted note successfully",
error: "Failed to delete note"
});
}
const handleMoveNote = () => {
if(!noteId || !selectedFolder) return
const promise = movenote({noteId, folderId:selectedFolder})
toast.promise(promise, {
loading: "Moving note ...",
success: "Moved note successfully",
error: "Failed to move note"
});
}
const handleEditFolder = () => {
if(!folderId) return
const promise = updatefoldertitle({folderId:folderId, title})
toast.promise(promise, {
loading: "updating the folder title ...",
success: "updated folder title successfully",
error: "Failed to update folder title"
});
}
const handleEditNote = () => {
if(!noteId) return
const promise = updatenotetitle({noteId, title})
toast.promise(promise, {
loading: "updating the note title ...",
success: "updated note title successfully",
error: "Failed to update note title"
});
}
return (
<div className='px-3'>
<DropdownMenu>
<DropdownMenuTrigger role='more-options' className='cursor-pointer hover:bg-primary/10 p-1 rounded-md'>
<span className={`${showOption ? "" :"invisible"}`}>
<MoreHorizontal size={18}/>
</span>
</DropdownMenuTrigger>
<DropdownMenuContent className='max-w-[250px] min-w-[180px]'>
<DropdownMenuItem className={`${folder ? "" : "hidden"}`} onClick={handleCreateFolder}>Add Folder</DropdownMenuItem>
<DropdownMenuItem className={`${note ? "" : "hidden"}`} onClick={handleCreateNote}>Add Note</DropdownMenuItem>
{(note === false && noteId) && (
<div>
<Dialog>
<DialogTrigger className='w-full text-left text-sm p-1 px-2 hover:bg-primary/10 rounded'>Move to</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle className='text-base mb-2'>Select Folder</DialogTitle>
<Select onValueChange={(event) => setSelectedFolder(event as Id<"folder">)}>
<SelectTrigger className="w-full">
<SelectValue placeholder="Folder" />
</SelectTrigger>
<SelectContent>
{folders?.map((foldera) => (
<SelectItem key={foldera._id} value={foldera._id}>{foldera.title}</SelectItem>
))}
</SelectContent>
</Select>
</DialogHeader>
<DialogClose onClick={handleMoveNote}><Button className='w-full'>Move</Button></DialogClose>
</DialogContent>
</Dialog>
</div>
)}
{(deleteOptions && folderId) && (
<div>
<DropdownMenuItem onClick={handleDeleteFolder}>Delete Folder</DropdownMenuItem>
<div>
<Dialog >
<DialogTrigger className='w-full text-left text-sm p-1 px-2 hover:bg-primary/10 rounded'>Edi Folder</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle className='text-base mb-2'>Folder Title</DialogTitle>
<Input onChange={(e) => setTitle(e.target.value)} placeholder='title' />
</DialogHeader>
<DialogClose onClick={handleEditFolder}><Button className='w-full'>Save</Button></DialogClose>
</DialogContent>
</Dialog>
</div>
</div>
)}
{(deleteOptions && noteId) &&(
<div>
<DropdownMenuItem onClick={handleDeleteNote}>Delete Note</DropdownMenuItem>
<div>
<Dialog >
<DialogTrigger className='w-full text-left text-sm p-1 px-2 hover:bg-primary/10 rounded'>Edit Note</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle className='text-base mb-2'>Note Title</DialogTitle>
<Input onChange={(e) => setTitle(e.target.value)} placeholder='title' />
</DialogHeader>
<DialogClose onClick={handleEditNote}><Button className='w-full'>Save</Button></DialogClose>
</DialogContent>
</Dialog>
</div>
</div>
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
)
}
export default Options
选项.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import Options from '@/app/(notes)/_components/options';
import { Id } from '../../convex/_generated/dataModel';
import { MoreHorizontal } from 'lucide-react';
jest.mock('convex/react', () => ({
useMutation: jest.fn(),
useQuery: jest.fn(),
}));
jest.mock('next/navigation', () => ({
useRouter: jest.fn(),
}));
describe('Options component', () => {
it('show morehorizontal icon when showoprion is true', () => {
// Mock useRouter implementation
const enabledProps: { showOption:boolean} = {
showOption:true
};
// Render the component
render(<Options deleteOptions {...enabledProps} />);
const Icon = render(<MoreHorizontal size={18} />)
expect(Icon).toBeTruthy()
expect(screen.queryByRole('button', { name: 'Move to' })).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Delete Note' })).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Edit Note' })).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Delete Folder' })).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Edit Folder' })).not.toBeInTheDocument()
});
it('show move to and Note Delete and Folder Select button when noteId is present and when we are not inside the note', () => {
const enabledProps: { showOption:boolean, noteId:Id<'note'>,note:boolean, deleteOptions:boolean} = {
showOption:true,
noteId:'id' as Id<'note'>,
note:false,
deleteOptions:true
};
// Render the component
render(<Options showOption deleteOptions note noteId={'id' as Id<'note'>} />);
console.log(document.body.innerHTML);
expect(screen.getByRole('button', { name: 'Move to' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Select Folder' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Delete Note' })).toBeInTheDocument();
});
it('show Folder Delete , edit button when folderId and deleteOptions is present ', () => {
const enabledProps1: { showOption:boolean, folderId:Id<'folder'>,deleteOptions:boolean} = {
showOption:true,
folderId:'id' as Id<'folder'>,
deleteOptions:false
};
// Render the component
render(<Options {...enabledProps1} />);
expect(screen.getByRole('button', { name: 'Delete Folder' })).toBeInTheDocument()
expect(screen.getByRole('button', { name: 'Delete Folder' })).toBeInTheDocument()
});
});
所以,我尝试等待或直接传递道具,但没有任何作用
代码太多。尝试更具体一点