I have looked at the basic Next.js testing with Vitest documentation here:
https://nextjs.org/docs/app/building-your-application/testing/vitest
And have successfully tested different situations. However, my actual app has components that are confusing me on how to test them.
I have a Next.js application with this basic layout:
MyNextApp|- __tests__/|- ...|- src| |- ...| |- components/| | |- component01.tsx| | |- component02.tsx| | |- component03.tsx| | |- ...| | `- component-N.tsx| |- pages/| | |- ...| | |- index.js| | `- ...| `- ...`- ...
In index.js
, I have something similar to this:
import Head from 'next/head';import * as React from 'react';import Component01 from '../components/component01';import Component02 from '../components/component02';import Component03 from '../components/component03';export default function (){ return(<> // ... JSX/HTML<Component01 /> // ... JSX/HTML<Component02 /> // ... JSX/HTML<Component03 /> // ... JSX/HTML</> )}
My components have the general form of:
export default function Component01() { return {<> // ...</> );}
And this all works well and fine.
In __tests__
, I have a test "ComponentTest.test.jsx" that looks like this:
import { expect, test } from 'vitest'import { render, screen } from '@testing-library/react'import Component01 from '../src/components/Component01.tsx'import Component02 from '../src/components/Component02.tsx'import Component03 from '../src/components/Component03.tsx'test('RenderComponent01', () => { render(<Component01 />) const theDialog = screen.getByRole('dialog'); // -or- const theTestId = screen.getByTestId('myawesometest');})
Now, when I run the tests
> npm test
They will all pass if I JUST use "render". However, if I try to target any specific section of the component (e.g., input, h1, img, dialog, etc.), the tests will fail.
TestingLibraryElementError: Unable to find an accessible element with the role "input, h1, img, dialog, etc."
There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the 'hidden' option to 'true'. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
After that message, the console displays this:
Ignored nodes: comments, script, style<body><div><div /></div></body>
It's like it is rendering the "index.js" without the imported components.
I have tried several variations of my "vitest.config.js" file:
import { defineConfig } from 'vitest/config'import react from '@vitejs/plugin-react'export default defineConfig({ plugins: [react()], test: { environment: 'jsdom', },})↓↓↓↓↓export default defineConfig({ plugins: [react()], test: { include: ['**/*.test.*sx'], globals: true },})↓↓↓↓↓export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom' },});↓↓↓↓↓export default defineConfig({ plugins: [react(),vue()], test: { include: ['**/*.test.*sx'], globals: true, environment: 'happy-dom' },})↓↓↓↓↓export default defineConfig({ plugins: [react()], test: { include: ['**/*.test.*sx'], globals: true, environment: 'jsdom' },})
But nothing seems to be working.
So how do I go about properly testing my app with these imported components?
EDIT: An actual example of one of my component files:
import * as React from 'react';import Button from '@mui/material/Button';import Dialog from '@mui/material/Dialog';import DialogActions from '@mui/material/DialogActions';import DialogContent from '@mui/material/DialogContent';import DialogContentText from '@mui/material/DialogContentText';import DialogTitle from '@mui/material/DialogTitle';import Paper from '@mui/material/Paper';import Draggable from 'react-draggable';import Table from '@mui/material/Table';import TableBody from '@mui/material/TableBody';import TableCell from '@mui/material/TableCell';import TableContainer from '@mui/material/TableContainer';import TableRow from '@mui/material/TableRow';function PaperComponent(props) { return (<Draggable handle="#draggable-dialog-title" cancel={'[class*="MuiDialogContent-root"]'}><Paper {...props} /></Draggable> );}export default function AboutThis({ open, onClose }) { return (<div><Dialog open={open} onClose={onClose} PaperComponent={PaperComponent} aria-labelledby="draggable-dialog-title"><DialogTitle style={{ cursor: 'move' }} id="draggable-dialog-title"> About This</DialogTitle><DialogContent><DialogContentText><TableContainer component={Paper}><Table><TableBody><TableRow><TableCell>stuff here ...</TableCell></TableRow><TableRow><TableCell>stuff here too ...</TableCell></TableRow></TableBody></Table></TableContainer></DialogContentText></DialogContent><DialogActions><Button disableRipple disableFocusRipple style={{ backgroundColor: "transparent" }} autoFocus onClick={onClose}> OK </Button></DialogActions></Dialog></div> );}