Spying on useReportWebVitals from next web vitals in vitest

30 views Asked by At
// useWebVitals.ts
'use client';

import opentelemetry, { TimeInput } from '@opentelemetry/api';
import { CARE_APP } from '@/components/shared/constants/careAppConstants';
import { useReportWebVitals } from 'next/web-vitals';

const DEFAULT_ROUTE = 'Home';

const EVENTS = [
    { metric: 'FCP', name: 'first-contentful-paint', max: 4800 },
    { metric: 'LCP', name: 'largest-contentful-paint', max: 6500 },
    { metric: 'CLS', name: 'cumulative-layout-shift', max: 0.35 },
    { metric: 'FID', name: 'first-input-delay', max: 400 },
    { metric: 'TTFB', name: 'time-to-first-byte' },
    { metric: 'Next.js-hydration', name: 'next-js-hydration' },
    { metric: 'Next.js-route-change-to-render', name: 'next-js-route-change' },
    { metric: 'Next.js-render', name: 'next-js-render' },
];

const getStartTime = (value: number): TimeInput | undefined => {
    return new Date().getTime() - Math.round(value) || undefined;
};

const shouldReportValue = (value: number, max: number | undefined): boolean => {
    return max ? value < max : true;
};

const useWebVitals = (route: string) => {
    // https://nextjs.org/docs/app/api-reference/functions/use-report-web-vitals
    // NextJS has OOTB performance monitoring: https://nextjs.org/docs/advanced-features/measuring-performance
    useReportWebVitals(({ name, value }) => {
        console.log("test name", name);
        console.log("test value", value);
        const event = EVENTS.find(({ metric }) => metric === name);
        // Check values - max is set to ignore crazy outliers that could be due to inactive tabs
        if (event && shouldReportValue(value, event?.max)) {
            opentelemetry.trace
                .getTracer(CARE_APP)
                .startSpan(`metric-${event.metric}`, {
                    startTime: getStartTime(value),
                    attributes: {
                        'http.route': route || DEFAULT_ROUTE,
                    },
                 })
                 .end();
        }
    });
};

export { useWebVitals };
// test
import opentelemetry from '@opentelemetry/api';
import { useWebVitals } from '@/components/shared/hooks/useWebVitals';
import { ROUTES } from '@/lib/routes';
import { renderHook } from '@testing-library/react';
import * as useReportWebVitals from 'next/web-vitals';

vi.mocked(opentelemetry);
vi.spyOn(useReportWebVitals,'useReportWebVitals');

describe('useWebVitals', () => {
    it('evaluates correct start time', () => {
        renderHook(() => useWebVitals(ROUTES.HOME));
        expect(opentelemetry).toHaveBeenCalled();
    });
});

How do I spy on "useReportWebVitals" in order to test the logic that I am performing on the callback? I want to test that the start time is calculated correctly along with the route attribute value.

When I do spy on the hook I get the following error Cannot redefine property: useReportWebVitals

I have tried to use mock + mocked instead. I added some console logs and see that it is not going entering "useReportWebVitals" at all.

1

There are 1 answers

0
Carolyn Lynch On

Solved:

vi.mock('next/web-vitals', () => {
    return {
        useReportWebVitals: vi.fn().mockImplementation((callback) => callback({ name: 'FCP', value: '2000'})),
    }
});