How to write test for react-splide in react with jest correctly?

Viewed 13

Problem:

I am new to react unit testing world. I have a component like this that is showing a report component that is using @splidejs/react-splide.

const Incident = () => {
    const { t } = useTranslation()
    const navigate = useNavigate()
    const { Id } = useParams()
    const theme = useTheme()
    const { fetch, ...dataFetchResult } =
        useReportDataFetch("incidents/GetById")

    useEffect(() => {
        fetch({ id: Id })

        return ()=>{
            localStorage.removeItem("vehicle")
        }
    }, [Id, fetch])

    const data = dataFetchResult.data
    const photos = useMemo(
        () =>
            data?.photos
                ? data.photos.map(photo => ({
                        ...photo,
                        original: `${process.env.REACT_APP_PHOTO_SOURCE}${photo.fileName}.jpg`,
                        thumbnail: `${process.env.REACT_APP_PHOTO_SOURCE}${photo.thumbnail}.jpg`,
                  }))
                : [],
        [data.photos]
    )
    const location = useLocation()
    const from = location.state?.from?.pathname || "/"

    const renderLink = () => {
        if (from === "/Incidents") {
            return (
                <Grid
                    container
                    justifyContent="space-between"
                    alignContent="center"
                    alignItems="center"
                    sx={{ paddingRight: theme.spacing(3) }}
                >
                    <Grid item lg="auto">
                        <Link
                            style={{ fontWeight: "bold" }}
                            href="#"
                            onClick={() => navigate(-1)}
                            underline="none"
                        >
                            {t("incident.all_incidents")}
                        </Link>
                    </Grid>
                    <Grid item>
                        <TopIconButtonContainer>
                            <TopIconLabelContainer>
                                <TopIconContainer>
                                    <TopIcon icon={faShareFromSquare} />
                                </TopIconContainer>
                                <Box sx={{ fontWeight: "500" }}>
                                    {t("incident.share")}
                                </Box>
                            </TopIconLabelContainer>
                            <TopIconLabelContainer>
                                <TopIconContainer>
                                    <TopIcon icon={faClock} />
                                </TopIconContainer>
                                <Box sx={{ fontWeight: "500" }}>
                                    {t("incident.schedule")}
                                </Box>
                            </TopIconLabelContainer>
                            <TopIconLabelContainer>
                                <TopIconContainer>
                                    <TopIcon icon={faPrint} />
                                </TopIconContainer>
                                <Box sx={{ fontWeight: "500" }}>
                                    {t("incident.print")}
                                </Box>
                            </TopIconLabelContainer>
                            <TopIconLabelContainer>
                                <TopIconContainer>
                                    <TopIcon icon={faDownToLine} />
                                </TopIconContainer>
                                <Box sx={{ fontWeight: "500" }}>
                                    {t("incident.export")}
                                </Box>
                            </TopIconLabelContainer>
                            <TopIconLabelContainer>
                                <TopIconContainer>
                                    <TopIcon icon={faQuestion} />
                                </TopIconContainer>
                                <Box sx={{ fontWeight: "500" }}>
                                    {t("incident.help")}
                                </Box>
                            </TopIconLabelContainer>
                        </TopIconButtonContainer>
                    </Grid>
                </Grid>
            )
        }
    }

    return (
        <>
            <ErrorBoundary>
                <ReportDataLayout dataFetchResult={dataFetchResult} noCancel>
                    <Container>{renderLink()}</Container>
                    <Grid container sx={{ paddingRight: theme.spacing(3) }}>
                        <Grid item xs={12} lg={6} md={6} xl={6} sm={12}>
                            <BoxContainer>
                                <Box>
                                    <h4>{t("incident.incident_details")}</h4>
                                    <DataContainer>
                                        {dataFetchResult.hasData && (
                                            <AssetLabel asset={data.asset} />
                                        )}
                                    </DataContainer>
                                    <DataContainer>
                                        {dataFetchResult.hasData && (
                                            <span>
                                                {shortDateTime(
                                                    data.dateAndTime
                                                )}
                                            </span>
                                        )}
                                    </DataContainer>
                                    <DataContainer>
                                        <span>Driver {data.driver}</span>
                                    </DataContainer>
                                    <DataContainer>
                                        <div>{data.details}</div>
                                    </DataContainer>
                                </Box>
                                <Box>
                                    <h4>
                                        {t("incident.other_driver_details")}
                                    </h4>
                                    <DataContainer>
                                        <span>{data?.otherDriver?.driver}</span>
                                    </DataContainer>
                                    <DataContainer>
                                        {data?.otherDriver?.registration}
                                    </DataContainer>
                                    <DataContainer>
                                        {data?.otherDriver?.insurance}
                                    </DataContainer>
                                </Box>
                            </BoxContainer>
                        </Grid>
                        <Grid item xs={12} lg={6} md={6} xl={6} sm={12}>
                            <MapContainer>
                                <h4>{t("incident.incident_location")}</h4>
                                {dataFetchResult.hasData && (
                                    <Map
                                        center={{
                                            lat: data.locationLat,
                                            lng: data.locationLong,
                                        }}
                                        zoom={8}
                                        defaultZoom={8}
                                        onZoomChange={(lat, lng, scale) => {}}
                                    >
                                        <IncidentMapMarker
                                            data={data}
                                        ></IncidentMapMarker>
                                    </Map>
                                )}
                                <LocationContainer sx={{ display: "flex" }}>
                                    <LocationIconContainer
                                        color={theme.palette.primary.main}
                                        icon={faLocationDot}
                                    />
                                    <div>{data?.location}</div>
                                </LocationContainer>
                            </MapContainer>
                        </Grid>
                    </Grid>
                    <PhotoTitleContainer>
                        <h4 style={{ marginTop: 70 }}>
                            {t("incident.photos")}
                        </h4>
                        <div
                            style={{
                                flexDirection: "row",
                                display: "flex",
                                flexWrap: "wrap",
                            }}
                        >
                            {photos.length >= 1 &&
                                photos?.map((item, index) => (
                                    <img
                                        style={{
                                            width: 100,
                                            margin: 10,
                                            height: 75,
                                        }}
                                        key={index}
                                        src={item?.thumbnail}
                                        alt={`Image ${index}`}
                                    />
                                ))}
                        </div>
                    </PhotoTitleContainer>
                    <PhotoContainer>
                        <Splide
                            options={{
                                rewind: true,
                                gap: "1rem",
                                perPage: 2,
                                fixedWidth: "50%",
                                snap: true,
                                lazyLoad: "nearby",
                            }}
                        >
                            {photos.length >= 1 &&
                                photos?.map((item, index) => (
                                    <SplideSlide key={index}>
                                        <img
                                            style={{
                                                width: "100%",
                                                height: 400,
                                            }}
                                            src={item?.original}
                                            alt={`Image ${index}`}
                                        />
                                    </SplideSlide>
                                ))}
                        </Splide>
                    </PhotoContainer>
                </ReportDataLayout>
            </ErrorBoundary>
        </>
    )
}

Error boundary component is like this.

class ErrorBoundary extends React.Component {
    constructor(props) {
        super(props)
        this.state = { hasError: false }
    }

    static getDerivedStateFromError(error) {
        return { hasError: true }
    }

    //  Not used at the moment but for logging etc...
    //  We might be able to store it for "raise a support case"

    componentDidCatch(error, errorInfo) {}

    render() {
        if (this.state.hasError) {
            return <Error />
        }

        return this.props.children
    }
}

And report data layout is look like this.

const ReportDataLayout = ({
    dataFetchResult,
    noCancel,
    noDataMessage,
    children,
}) => {
    if (dataFetchResult.isError) throw new Error()

    if (dataFetchResult.isFetching) {
        if (noCancel) {
            return (
                <Container>
                    <Progress size="large" />
                </Container>
            )
        } else {
            return (
                <Container>
                    <ProgressWithCancel
                        size="large"
                        onCancel={dataFetchResult.cancel}
                    />
                </Container>
            )
        }
    }
    if (dataFetchResult.isCanceled) {
        return (
            <Container>
                <UserCanceled />
            </Container>
        )
    }
    if (!dataFetchResult.hasData && !dataFetchResult.isIdle) {
        return (
            <Container>
                <NoData message={noDataMessage} />
            </Container>
        )
    }
    return <div>{children}</div>
}

After that I wrote an unit testing for this component like this.

Before I adding splideJs it was working like charm after I added that package when I run unit test it is failing. This is how I have wrote it.

import React from "react"
import {
    render,
    screen,
    fireEvent,
    waitFor,
    within,
} from "@testing-library/react"
import axios from "axios"
import MockAdapter from "axios-mock-adapter"
import { BrowserRouter, Routes, Route } from "react-router-dom"
import * as HTTP_STATUS from "../../../data-fetch/constants/httpStatuses"
import Incident from "./Incident"

jest.mock("react-i18next", () => ({
    useTranslation: () => {
        return {
            t: str => str,
        }
    },
}))

const mock_refresh = jest.fn()
jest.mock("../../../framework/useApplication", () => ({
    useApplication: () => {
        return {
            refresh: () => mock_refresh(),
        }
    },
}))

jest.mock("../../../utilities/date-formats", () => ({
    mediumDateTime: dateTime => dateTime.toString(),
}))

const renderTestDom = () => {
    window.history.pushState({}, "Incident", "/Incident")
    render(
        <BrowserRouter>
            <Routes>
                <Route path="/Incident" element={<Incident />} />
            </Routes>
        </BrowserRouter>
    )
}

const reportData = {
    id: 1,
    driver: "David Smith",
    locationLat: 52.504897,
    locationLong: -2.080205,
    location: "Prospect Row, Dudley",
    dateAndTime: "2022-07-12T09:06:18.47",
    details: "The car was hit by another driver while being parked",
    otherDriver: {
        driver: "Jack Smith",
        registration: "Vehicle registration",
        insurance: "Name of insurance",
    },
    asset: {
        id: 471319,
        description: "170633 Ginsters",
        icon: "largevan_green",
        aspectRatio: 2.5,
        site: 0,
        groups: [],
    },
    photos: [
        {
            fileName: "VehAccident-1",
            thumbnail: "VehAccident-1-thumb",
        },
        {
            fileName: "VehAccident-2",
            thumbnail: "VehAccident-2-thumb",
        },
    ],
}

describe("Incident", () => {
    let mock_axios
    beforeAll(() => {
        mock_axios = new MockAdapter(axios)
        Object.defineProperty(window, "matchMedia", {
            writable: true,
            value: jest.fn().mockImplementation(query => ({
                matches: false,
                media: query,
                onchange: null,
                addListener: jest.fn(), // Deprecated
                removeListener: jest.fn(), // Deprecated
                addEventListener: jest.fn(),
                removeEventListener: jest.fn(),
                dispatchEvent: jest.fn(),
            })),
        })
    })

    beforeEach(() => {
        mock_axios
            .onGet("incidents/GetById", {
                params: {
                    id: 1,
                },
            })
            .reply(HTTP_STATUS.OK, reportData)
    })

    test("should render title", async () => {
        renderTestDom()
        await waitFor(async () => {
            expect(screen.getByText(/incident.incident_details/)).not.toBeNull()
        })
    })
})

But After I wruuning this test it is showing me this issue.

console.error
      Error: Uncaught [TypeError: Cannot read properties of undefined (reading 'matches')]
          at reportException (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\helpers\runtime-script-errors.js:66:24)
          at innerInvokeEventListeners (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:341:9)
          at invokeEventListeners (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:274:3)
          at HTMLUnknownElementImpl._dispatch (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:221:9)
          at HTMLUnknownElementImpl.dispatchEvent (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:94:17)
          at HTMLUnknownElement.dispatchEvent (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\generated\EventTarget.js:231:34)
          at Object.invokeGuardedCallbackDev (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:3994:16)
          at invokeGuardedCallback (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:4056:31)
          at commitRootImpl (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:23151:9)
          at unstable_runWithPriority (E:\Freelance\webclient-fleettacking\node_modules\scheduler\cjs\scheduler.development.js:468:12) TypeError: Cannot read properties of undefined (reading 'matches')
          at E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:537:38
          at Array.reduce (<anonymous>)
          at update (E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:536:26)
          at Object.setup (E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:521:5)
          at E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:2471:36
          at forOwn (E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:154:13)
          at _Splide2.mount (E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:2468:5)
          at Splide2.componentDidMount (E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:2691:19)
          at commitLifeCycles (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:20663:24)
          at commitLayoutEffects (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:23426:7)
          at HTMLUnknownElement.callCallback (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:3945:14)
          at HTMLUnknownElement.callTheUserObjectsOperation (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\generated\EventListener.js:26:30)
          at innerInvokeEventListeners (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:338:25)
          at invokeEventListeners (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:274:3)
          at HTMLUnknownElementImpl._dispatch (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:221:9)
          at HTMLUnknownElementImpl.dispatchEvent (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\events\EventTarget-impl.js:94:17)
          at HTMLUnknownElement.dispatchEvent (E:\Freelance\webclient-fleettacking\node_modules\jsdom\lib\jsdom\living\generated\EventTarget.js:231:34)
          at Object.invokeGuardedCallbackDev (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:3994:16)
          at invokeGuardedCallback (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:4056:31)
          at commitRootImpl (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:23151:9)
          at unstable_runWithPriority (E:\Freelance\webclient-fleettacking\node_modules\scheduler\cjs\scheduler.development.js:468:12)
          at runWithPriority$1 (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:11276:10)
          at commitRoot (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:22990:3)
          at performSyncWorkOnRoot (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:22329:3)
          at scheduleUpdateOnFiber (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:21881:7)
          at updateContainer (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:25482:3)
          at E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:26021:7
          at unbatchedUpdates (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:22431:12)
          at legacyRenderSubtreeIntoContainer (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:26020:5)
          at Object.render (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:26103:10)
          at E:\Freelance\webclient-fleettacking\node_modules\@testing-library\react\dist\pure.js:101:25
          at batchedUpdates$1 (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom.development.js:22380:12)
          at act (E:\Freelance\webclient-fleettacking\node_modules\react-dom\cjs\react-dom-test-utils.development.js:1042:14)
          at render (E:\Freelance\webclient-fleettacking\node_modules\@testing-library\react\dist\pure.js:97:26)
          at renderTestDom (E:\Freelance\webclient-fleettacking\src\reports\incident\incidentDetailPage\Incident.test.js:38:2)
          at Object.<anonymous> (E:\Freelance\webclient-fleettacking\src\reports\incident\incidentDetailPage\Incident.test.js:110:3)
          at Promise.then.completed (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\utils.js:391:28)
          at new Promise (<anonymous>)
          at callAsyncCircusFn (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\utils.js:316:10)
          at _callCircusTest (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\run.js:218:40)
          at processTicksAndRejections (node:internal/process/task_queues:96:5)
          at _runTest (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\run.js:155:3)
          at _runTestsForDescribeBlock (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\run.js:66:9)
          at _runTestsForDescribeBlock (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\run.js:60:9)
          at run (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\run.js:25:3)
          at runAndTransformResultsToJestFormat (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\legacy-code-todo-rewrite\jestAdapterInit.js:170:21)
          at jestAdapter (E:\Freelance\webclient-fleettacking\node_modules\jest-circus\build\legacy-code-todo-rewrite\jestAdapter.js:82:19)
          at runTestInternal (E:\Freelance\webclient-fleettacking\node_modules\jest-runner\build\runTest.js:389:16)
          at runTest (E:\Freelance\webclient-fleettacking\node_modules\jest-runner\build\runTest.js:475:34)
          at Object.worker (E:\Freelance\webclient-fleettacking\node_modules\jest-runner\build\testWorker.js:133:12)

      at VirtualConsole.<anonymous> (node_modules/jsdom/lib/jsdom/virtual-console.js:29:45)
      at reportException (node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:70:28)
      at innerInvokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:341:9)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17)
      at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34)

    console.error
      The above error occurred in the <Splide2> component:

          at Splide2 (E:\Freelance\webclient-fleettacking\node_modules\@splidejs\react-splide\dist\js\react-splide.cjs.js:2681:5)
          at div
          at I (E:\Freelance\webclient-fleettacking\node_modules\styled-components\src\models\StyledComponent.js:252:3)
          at div
          at ReportDataLayout (E:\Freelance\webclient-fleettacking\src\data-fetch\ReportDataLayout.js:14:2)
          at ErrorBoundary (E:\Freelance\webclient-fleettacking\src\framework\elements\ErrorBoundary.js:10:3)
          at Incident (E:\Freelance\webclient-fleettacking\src\reports\incident\incidentDetailPage\Incident.js:114:19)
          at Routes (E:\Freelance\packages\react-router\index.tsx:336:3)
          at Router (E:\Freelance\packages\react-router\index.tsx:256:13)
          at BrowserRouter (E:\Freelance\packages\react-router-dom\index.tsx:136:3)

      React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.

I tried a lot to find out a solution for this one but I was unable to do so. Can someone help me to solve this. This issue was stopping me for two days now. It would be great if anyone could help me regarding this issue.Thank you

0 Answers
Related