Почему .env.development не работает в моем приложении Next.js?

Я пишу Jest/тестирую библиотечные тесты.

Допустим, у нас есть компонент с именем BenchmarksPage.

Пожалуйста, посмотрите на первую строку его оператора return.

import {
  Box,
  capitalize,
  Container,
  FormControl,
  InputLabel,
  MenuItem,
  Select,
} from '@material-ui/core';
import { NextPage } from 'next';
import React, { useCallback, useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import RequireScope from 'src/components/authentication/RequireScope';
import BenchmarkTable from 'src/components/benchmark/BenchmarkTable';
import DashboardLayout from 'src/components/dashboard/DashboardLayout';
import Heading from 'src/components/Heading';
import useSettings from 'src/hooks/useSettings';
import gtm from 'src/lib/gtm';
import { useDispatch, useSelector } from 'src/store';
import { getAllRollingTwelveCalcs } from 'src/store/rolling-twelve/rolling-twelve.thunk';
import { Timeframe, timeframeMap } from 'src/types/benchmark';

const BenchmarksPage: NextPage = () => {
  const { settings } = useSettings();
  const dispatch = useDispatch();

  const [selectedTimeframe, setSelectedTimeframe] = useState<Timeframe>(
    Timeframe.Monthly,
  );

  const company = useSelector((state) => state.company.current);

  useEffect(() => {
    gtm.push({ event: 'page_view' });
  }, []);

  useEffect(() => {
    dispatch(getAllRollingTwelveCalcs());
  }, [company]);

  const handleTimeframeChange = useCallback(
    (
      event: React.ChangeEvent<{
        name?: string;
        value: Timeframe;
        event: Event | React.SyntheticEvent<Element, Event>;
      }>,
    ) => {
      setSelectedTimeframe(event.target.value);
    },
    [],
  );

  return (
    <RequireScope scopes={['query:benchmark-calcs']}>
      <DashboardLayout>
        <Helmet>
          <title>Benchmarks</title>
        </Helmet>
        <Container maxWidth={settings.compact ? 'xl' : false}>
          <Box
            sx={{
              display: 'flex',
              alignItems: 'flex-end',
              justifyContent: 'space-between',
              mb: 4,
            }}
          >
            <Heading>Benchmarks</Heading>
            <FormControl sx={{ width: 300 }}>
              <InputLabel>Timeframe</InputLabel>
              <Select
                sx={{ background: '#ffffff', maxWidth: 400 }}
                value={selectedTimeframe}
                label="Timeframe"
                onChange={handleTimeframeChange}
              >
                {[...timeframeMap.keys()].map((timeframe) => (
                  <MenuItem key={timeframe} value={timeframe}>
                    {capitalize(timeframe)}
                  </MenuItem>
                ))}
              </Select>
            </FormControl>
          </Box>
          <BenchmarkTable timeframe={selectedTimeframe} />
        </Container>
      </DashboardLayout>
    </RequireScope>
  );
};

export default BenchmarksPage;

Обратите внимание, что возвращаемое значение заключено в RequireScope

RequireScope будет отображать свои дочерние элементы только после аутентификации пользователя.

RequireScope:

import React, { useEffect, useState } from 'react';
import useAuth from 'src/hooks/useAuth';

export interface RequireScopeProps {
  scopes: string[];
}

const RequireScope: React.FC<RequireScopeProps> = React.memo((props) => {
  const { children, scopes } = props;
  const { isInitialized, isAuthenticated, permissions } = useAuth();
  const [isPermitted, setIsPermitted] = useState(false);

  useEffect(() => {
    if (process.env.NEXT_PUBLIC_IS_LOCAL) {
      setIsPermitted(true);
    }
  }, []);

  useEffect(() => {
    if (isAuthenticated && isInitialized) {
      (async () => {
        const hasPermissions = scopes
          .map((s) => {
            return permissions.includes(s);
          })
          .filter(Boolean);

        if (hasPermissions.length === scopes.length) {
          setIsPermitted(true);
        }
      })();
    }
  }, [isAuthenticated, isInitialized, scopes, permissions]);

  if (isPermitted) {
    return <>{children}</>;
  }

  return null;
});

export default RequireScope;

Нам просто нужно, чтобы isPermitted было установлено на true

(Кстати, useAuth использует JWT для входа пользователя)

Теперь, когда я визуализирую BenchmarksPage с помощью метода render библиотеки тестирования,

он не отображается на jsdom, потому что

'isPermitted' по-прежнему ложно в RequireScope.

Итак, для того, чтобы сделать isPermitted = true

я установил

NEXT_PUBLIC_IS_LOCAL=true

в .env.development

Согласно первому useEffect в RequireScope, isPermitted должно быть true сейчас.

Тем не менее, компонент все еще не отображается, возвращая

<body></div></body> 

Это по-прежнему означает, что isPermitted является ложным.

Что я пробовал:

Я также пробовал использовать .env.local

Я могу гарантировать вам, что все мои настройки верны (jest.config, использование MockProvider для переноса BenchmarksPage и т. д.)

Почему .env.development не работает и не делает isPermitted = true?

Все логически правильно в моем понимании.

Обновлено: я пытался писать

NEXT_PUBLIC_IS_LOCAL=истина

в файле .env.test тоже

РЕДАКТИРОВАТЬ - ОТВЕТ:

должен был установить

import { loadEnvConfig } from '@next/env';

export default async (): Promise<void> => {
  loadEnvConfig(process.env.PWD);
};

в файле setupEnv.ts.

А затем в package.json добавьте globalSetup (поскольку я не использую jest.config.js -> eslint возился с ним вместе с tsconfig)

"jest": {
    "moduleNameMapper": {
      "^src/(.*)$": "<rootDir>/src/$1"
      },
    "testEnvironment": "jsdom",
    "globalSetup": "<rootDir>/test/setupEnv.ts"
  },

Вы пробовали console.log(process.env), чтобы увидеть, появляется ли вообще какой-либо env?

Overclocked Skid 10.04.2022 02:09
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
1
34
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если ваши переменные среды работают во время работы сервера разработки, но не работают во время тестирования, это связано с тем, что Next не устанавливает переменные для Jest во время модульного тестирования.

Во-первых, создайте .env.test, настроив переменные среды, которые будут использоваться только для тестов.

Затем, чтобы настроить envs в тестовой среде, вы должны добавить это в точку входа в ваши тесты:

// jest.config.js
module.exports = {
  globalSetup: '<rootDir>/__test__/setupEnv.js'
}
// __test__/setupEnv.js
import { loadEnvConfig } from '@next/env'

export default async () => {
  const projectDir = process.cwd()
  loadEnvConfig(projectDir)
}

Обратите внимание, что .env.local не загружается во время тестов

Другие вопросы по теме