vitest-dev / vitest

Next generation testing framework powered by Vite.
https://vitest.dev
MIT License
12.83k stars 1.15k forks source link

Error: Uncaught [TypeError: __vite_ssr_import_2__.formattedAvailabilityTime is not a function] #5471

Closed m-nathani closed 6 months ago

m-nathani commented 6 months ago

Describe the bug

My test for a component is failing due to the error as mentioned in title.

A/c to the error it appears that the vitest is not able to find the function formattedAvailabilityTime, where as this function certainly exist on the import

import { useContext } from 'react';
import classnames from 'classnames';
import { useTranslation } from 'react-i18next';
import moment from 'moment-timezone';
import { sortWorkingHours } from 'js/services/reservation-service';
import { formattedAvailabilityTime } from 'js/utils/time-and-date';
import { DEFAULT_LANGUAGE } from 'js/constants/languages';
import { VenueContext } from 'js/contexts/venue';
import type { WorkingHour } from 'js/types/venue';

function ReservationSchedule() {
  const { t } = useTranslation();
  const { venue } = useContext(VenueContext);
  const { availabilities } = venue || {};

  const renderTimeRange = (hour: WorkingHour) => {
    if (hour.opens_at && hour.closes_at) {
      return (
        <span key={hour.id}>
          {formattedAvailabilityTime(hour.opens_at).format(t('common:formats.time_slot'))} &ndash;{' '}
          {formattedAvailabilityTime(hour.closes_at).format(t('common:formats.time_slot'))}
        </span>
      );
    }

    return <span>N/A</span>;
  };

    const renderWorkingHour = (workingHours: WorkingHour[]) => {
    if (workingHours.length) {
      return sortWorkingHours({ workingHours, type: 'opens_at', sort: 'asc' }).map(renderTimeRange);
    }

    return <span>{t('open')}</span>;
  };

  ...

Here is the function that exists in js/utils/time-and-date

 export const formattedAvailabilityTime = (time: string) => moment(time, [TIME_FORMAT, 'HH:mm:ss']);

Here are the functions which is using the above in js/services/reservation-service


const formatSortTime = (time: string) => {
  // Days are from 6:00AM to 5:59AM
  const momentTime = formattedAvailabilityTime(time);
  const sortTime = moment().set({ hours: momentTime.hours(), minutes: momentTime.minutes() });
  return sortTime.hour() < 6 ? sortTime.add(1, 'day') : sortTime;
};

export const sortWorkingHours = ({ workingHours, type, sort }: SortWorkingHours) =>
  // spreading into a new array to always return a new reference of the array after sorting in multiple times
  [
    ...workingHours.sort((a, b) => {
      const aTime = a[type];
      const bTime = b[type];
      if (aTime && bTime) {
        if (sort === 'asc') {
          return formatSortTime(aTime).diff(formatSortTime(bTime));
        }

        return formatSortTime(bTime).diff(formatSortTime(aTime));
      }

      return 0;
    }),
  ];

Scratching my head of to find why it can't find inside sortWorkingHours function used, where as the this function is passing tests on other locations in code where test independently.

Moreover, it passes test when i remove sortWorkingHours({ workingHours, type: 'opens_at', sort: 'asc' }) from the component or add formattedAvailabilityTime inside service file :S

Complete stack trace of the error:

Error: Uncaught [TypeError: __vite_ssr_import_2__.formattedAvailabilityTime is not a function]
    at reportException (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
    at innerInvokeEventListeners (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:353:9)
    at invokeEventListeners (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
    at HTMLUnknownElementImpl._dispatch (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
    at HTMLUnknownElementImpl.dispatchEvent (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
    at HTMLUnknownElement.dispatchEvent (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
    at Object.invokeGuardedCallbackDev (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:4213:16)
    at invokeGuardedCallback (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:4277:31)
    at beginWork$1 (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:27451:7)
    at performUnitOfWork (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:26560:12) TypeError: __vite_ssr_import_2__.formattedAvailabilityTime is not a function
    at formatSortTime (/home/murtaza/umai/widget/src/js/services/reservation-service.ts:210:22)
    at sort (/home/murtaza/umai/widget/src/js/services/reservation-service.ts:262:18)
    at Array.sort (<anonymous>)
    at Module.sortWorkingHours (/home/murtaza/umai/widget/src/js/services/reservation-service.ts:257:21)
    at renderWorkingHour (/home/murtaza/umai/widget/src/js/components/VenueModal/ReservationSchedule.tsx:31:14)
    at map (/home/murtaza/umai/widget/src/js/components/VenueModal/ReservationSchedule.tsx:50:26)
    at Array.map (<anonymous>)
    at ReservationSchedule (/home/murtaza/umai/widget/src/js/components/VenueModal/ReservationSchedule.tsx:41:10)
    at renderWithHooks (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
Error: Uncaught [TypeError: __vite_ssr_import_2__.formattedAvailabilityTime is not a function]
    at reportException (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
    at innerInvokeEventListeners (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:353:9)
    at invokeEventListeners (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
    at HTMLUnknownElementImpl._dispatch (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
    at HTMLUnknownElementImpl.dispatchEvent (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
    at HTMLUnknownElement.dispatchEvent (/home/murtaza/umai/widget/node_modules/.pnpm/jsdom@23.2.0/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
    at Object.invokeGuardedCallbackDev (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:4213:16)
    at invokeGuardedCallback (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:4277:31)
    at beginWork$1 (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:27451:7)
    at performUnitOfWork (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:26560:12) TypeError: __vite_ssr_import_2__.formattedAvailabilityTime is not a function
    at formatSortTime (/home/murtaza/umai/widget/src/js/services/reservation-service.ts:210:22)
    at sort (/home/murtaza/umai/widget/src/js/services/reservation-service.ts:262:18)
    at Array.sort (<anonymous>)
    at Module.sortWorkingHours (/home/murtaza/umai/widget/src/js/services/reservation-service.ts:257:21)
    at renderWorkingHour (/home/murtaza/umai/widget/src/js/components/VenueModal/ReservationSchedule.tsx:31:14)
    at map (/home/murtaza/umai/widget/src/js/components/VenueModal/ReservationSchedule.tsx:50:26)
    at Array.map (<anonymous>)
    at ReservationSchedule (/home/murtaza/umai/widget/src/js/components/VenueModal/ReservationSchedule.tsx:41:10)
    at renderWithHooks (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/home/murtaza/umai/widget/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
The above error occurred in the <ReservationSchedule> component:

    at ReservationSchedule (/home/murtaza/umai/widget/src/js/components/VenueModal/ReservationSchedule.tsx:21:45)

Reproduction

I tried moving these function into the component and it works.. unknowingly cant figure this out yet...

System Info

System:
    OS: Linux 5.15 Ubuntu 22.04.4 LTS 22.04.4 LTS (Jammy Jellyfish)
    CPU: (8) x64 Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
    Memory: 3.35 GB / 15.34 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 20.11.1 - ~/.nvm/versions/node/v20.11.1/bin/node
    Yarn: 1.21.1 - /usr/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.1/bin/npm
    pnpm: 8.15.4 - ~/.local/share/pnpm/pnpm
  Browsers:
    Chrome: 123.0.6312.86
  npmPackages:
    @vitejs/plugin-legacy: ^5.2.0 => 5.3.0 
    @vitejs/plugin-react-swc: ^3.4.1 => 3.6.0 
    @vitest/coverage-v8: ^1.1.3 => 1.2.2 
    vite: ^5.0.11 => 5.1.2 
    vitest: ^1.1.3 => 1.2.2

Used Package Manager

pnpm

Validations

m-nathani commented 6 months ago

I was exporting all the utils from a index.ts file like :

utils/index.ts

...
export * from './sentry';
export * from './time-and-date';
export * from './error';

separating out the imports in file js/service/resevation-service.ts for formattedAvailabilityTime as follows passes the tests now:

import { getTrackingId, getFormattedDate, ... } from 'js/utils';
import { formattedAvailabilityTime } from 'js/utils/time-and-date';

Not sure if this is vite build issue or vitest thing... but certainly could not find the logical way out of it.

hi-ogawa commented 6 months ago

Too complicated to suggest anything useful, but can you at least share your vite config? Some plugins might be interfering with something. Also do you use vi.mock somewhere?

github-actions[bot] commented 6 months ago

Hello @m-nathani. Please provide a minimal reproduction using a GitHub repository or StackBlitz (you can also use examples). Issues marked with needs reproduction will be closed if they have no activity within 3 days.

m-nathani commented 6 months ago

@hi-ogawa using vi.mock in setupTests, which is used as test.setupFiles in the vite.config added below:

setupTests.ts

...

// Use mock implementation from `./__mocks__/react-i18next.js`
vi.mock('react-i18next');

vi.mock('moment-timezone', async () => {
  const moment: Moment = await vi.importActual('moment-timezone');
  // Use same timezone and moment locale for all tests
  (moment.tz as any).setDefault('Asia/Singapore');
  moment.locale('en');
  // Use the actual module in our tests
  return moment;
});

...

vite.config.js

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import checker from 'vite-plugin-checker';
import { visualizer } from 'rollup-plugin-visualizer';
import { resolve } from 'path';

export default defineConfig(({ command, mode }) => ({
  resolve: {
    alias: {
      js: resolve(__dirname, 'src/js/'),
      '@components': resolve(__dirname, 'src/js/components'),
      '@utils': resolve(__dirname, 'src/js/utils'),
      '@store': resolve(__dirname, 'src/js/store'),
      '@constants': resolve(__dirname, 'src/js/constants'),
      '@api': resolve(__dirname, 'src/js/api'),
      '@images': resolve(__dirname, 'images'),
      '@contexts': resolve(__dirname, 'src/js/contexts'),
      '@services': resolve(__dirname, 'src/js/services'),
      '@styles': resolve(__dirname, 'src/js/styles'),
      '@locales': resolve(__dirname, 'locales'),
    },
  },

  plugins: [
    react(),

    // Only lint while using dev server,
    // for deployments run eslint separately in Github action
    command === 'serve' &&
      !process.env.VITEST &&
      checker({
        overlay: {
          initialIsOpen: false,
          // Show panel on top of widget modal
          badgeStyle: 'z-index: 1000000001;',
          panelStyle: 'z-index: 1000000000;',
        },
        eslint: {
          lintCommand: 'eslint "./src/js/**/*.{js,jsx,ts,tsx}"',
        },
        typescript: true,
      }),

    // Bundle analizer
    mode === 'analyze' && visualizer(),
  ].filter(Boolean),

  build: {
    rollupOptions: {
      input: {
        embed: resolve(__dirname, 'src/js/embed.ts'),
        widget: resolve(__dirname, 'src/js/widget.tsx'),
      },
      output: {
        entryFileNames: '[name].min.js',
        assetFileNames: (assetInfo) => {
          const ext = assetInfo.name.split('.').pop();
          if (ext === 'css') {
            return '[name].min.css';
          }
          return assetInfo.name;
        },
      },
    },
    sourcemap: true,
    target: 'es2015',
  },

  server: {
    port: 8080,
  },

  define: {
    // Use `__APP_VERSION__` to get the version instead of directly importing `package.json`
    __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
  },

  // Use Vitest instead of Jest as test runner
  test: {
    // describe, it, test, will be available without having to import (Similar to Jest)
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/setupTests.ts',
    coverage: {
      provider: 'v8',
    },
  },
}));
hi-ogawa commented 6 months ago

As one more tip to debug potential code transform bugs, you can try running it with VITE_NODE_DEBUG_DUMP=true, which will output transformed code in .vite-node/dump.

You might be able to find how __vite_ssr_import_2__.formattedAvailabilityTime is used from there.

m-nathani commented 6 months ago

@hi-ogawa alright thanks... Will check on this tip and revert back to you. 🙏