How can test the react component based on conditions passed as props

34 Views Asked by At

So i am trying to test my code, but my tests are failing because it is not able to find some elements based on condions

this is my Options.tsx file which i want to be tested

this is the error i am getting

✓ show morehorizontal icon when showoprion is true (36 ms) ✕ show move to and Note Delete and Folder Select button when noteId is present and when we are not inside the note (64 ms) ✕ show Folder Delete , edit button when folderId and deleteOptions is present (31 ms)

● Options component › show move to and Note Delete and Folder Select button when noteId is present and when we are not inside the note

TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "Move to"

● Options component › show Folder Delete , edit button when folderId and deleteOptions is present

TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "Delete Folder"

Options.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






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()
    });
  });

So, i tried wait for and or directly passing the props but nothing works

0

There are 0 best solutions below