test process.env z Jest

123

Mam aplikację, która zależy od zmiennych środowiskowych, takich jak:

const APP_PORT = process.env.APP_PORT || 8080;

i chciałbym to przetestować np .:

  • APP_PORT można ustawić za pomocą zmiennej env węzła.
  • lub że expressaplikacja działa na porcie ustawionym zprocess.env.APP_PORT

Jak mogę to osiągnąć dzięki Jest? Czy mogę ustawić te process.envzmienne przed każdym testem, czy może powinienem jakoś z tego kpić?

Tomasz Mularczyk
źródło
tak, możesz ustawić zmienną środowiskową
Deep Kakkar
@Deep AFAIK Mogę je ustawić tylko raz w konfiguracji.
Tomasz Mularczyk

Odpowiedzi:

164

Sposób, w jaki to zrobiłem, można znaleźć w tym pytaniu SO .

Ważne jest, aby zresetować moduły przed każdym testem, a następnie dynamicznie zaimportować moduł wewnątrz testu:

describe('environmental variables', () => {
  const OLD_ENV = process.env;

  beforeEach(() => {
    jest.resetModules() // most important - it clears the cache
    process.env = { ...OLD_ENV }; // make a copy
  });

  afterAll(() => {
    process.env = OLD_ENV; // restore old env
  });

  test('will receive process.env variables', () => {
    // set the variables
    process.env.NODE_ENV = 'dev';
    process.env.PROXY_PREFIX = '/new-prefix/';
    process.env.API_URL = 'https://new-api.com/';
    process.env.APP_PORT = '7080';
    process.env.USE_PROXY = 'false';

    const testedModule = require('../../config/env').default

    // ... actual testing
  });
});

Jeśli szukasz sposobu na załadowanie wartości env przed uruchomieniem Jest, poszukaj odpowiedzi poniżej . Powinieneś do tego użyć setupFiles .

Tomasz Mularczyk
źródło
2
Prosimy o przesłanie pełnej odpowiedzi
Yves M.
U mnie zadziałało świetnie. Jeśli potrzebujesz użyć domyślnego eksportu, możesz to zrobić: const testedModule = require ('../../ config / env'). Default;
Aziz
8
jeśli to nie zadziała, upewnij się, że czytając zmienną env w swoim rzeczywistym kodzie, czytasz ją w funkcji / ograniczonym zakresie, a nie zmienne globalne wskazywane na process.env.YOUR_VARIABLE.
penguinsource
1
@learner, jeśli dobrze pamiętam, delete process.env.NODE_ENV; jest tylko pozostałością z mojego kodu i nie powinno mieć znaczenia w Twoim przypadku. Liczy się to, że dzwonisz jest.resetModules()przed testem, a po nim przywracasz początkowy obiekt process.env (OLD_ENV)
Tomasz Mularczyk
1
@MEMark musisz utworzyć kopię, aby nie mutować oryginalnego obiektu (który później trzeba przywrócić)
Tomasz Mularczyk
70

Jest setupFilesto właściwy sposób radzenia sobie z tym problemem i nie musisz instalować dotenvani .envw ogóle używać pliku, aby działał.

jest.config.js:

module.exports = {
  setupFiles: ["<rootDir>/.jest/setEnvVars.js"]
};

.jest/setEnvVars.js:

process.env.MY_CUSTOM_TEST_ENV_VAR = 'foo'

Otóż ​​to.

zgreen
źródło
1
To najprostszy sposób radzenia sobie ze zmiennymi env, dzięki!
klaevv
29

W ./package.json:

"jest": {
  "setupFiles": [
    "<rootDir>/jest/setEnvVars.js"
  ]
}

W ./jest/setEnvVars.js:

process.env.SOME_VAR = 'value';

Emi
źródło
2
Prawdopodobnie najłatwiejszy sposób, jaki widziałem. Nie ma potrzeby instalowania pakietu dotenv.
MattC
to nie zadziała z Create-React-App github.com/facebook/create-react-app/issues/5325 w tym celu zmienne env, które mają być użyte w teście, należy dodać w pliku .env.test.local
Pere
23

Możesz skorzystać z setupFilesfunkcji jest config. Jako dokumentacja mówi , że

Lista ścieżek do modułów, które uruchamiają kod w celu skonfigurowania lub skonfigurowania środowiska testowego. Każdy plik setupFile zostanie uruchomiony raz na plik testowy. Ponieważ każdy test działa we własnym środowisku, skrypty te będą wykonywane w środowisku testowym bezpośrednio przed wykonaniem samego kodu testowego.

  1. npm install dotenv dotenv, który używa do uzyskania dostępu do zmiennej env.
  2. Utwórz .envplik w katalogu głównym aplikacji i dodaj do niego ten wiersz.
#.env
APP_PORT=8080
  1. Utwórz plik modułu niestandardowego pod nazwą someModuleForTest.js i dodaj do niego ten wiersz.
//someModuleForTest.js
require("dotenv").config()
  1. Zaktualizuj swój jest.config.jsplik w ten sposób
module.exports = {
  setupFiles: ["./someModuleForTest"]
}
  1. Możesz uzyskać dostęp do zmiennej env we wszystkich blokach testowych.
test("Some test name", () => {
  expect(process.env.APP_PORT).toBe("8080")
})
Serhan C.
źródło
12

Inną opcją jest dodanie go do jest.config.jspliku po module.exportsdefinicji:

process.env = Object.assign(process.env, {
  VAR_NAME: 'varValue',
  VAR_NAME_2: 'varValue2'
});

Dzięki temu nie ma potrzeby definiowania ENVzmiennych w każdym .specpliku i można je dostosowywać globalnie.

jahller
źródło
To fantastyczna odpowiedź. Dziękuję Ci.
spierce7
3

W zależności od tego, jak możesz zorganizować swój kod, inną opcją może być umieszczenie zmiennej env w funkcji wykonywanej w czasie wykonywania.

W tym pliku zmienna env jest ustawiana w czasie importu i wymaga dynamicznych wartości requirew celu przetestowania różnych zmiennych środowiska (zgodnie z opisem w tej odpowiedzi ):

const env = process.env.MY_ENV_VAR;

const envMessage = () => `MY_ENV_VAR is set to ${env}!`;

export default myModule;

W tym pliku zmienna env jest ustawiana w envMessageczasie wykonywania i powinieneś być w stanie zmutować process.env bezpośrednio w swoich testach:

const envMessage = () => {
  const env = process.env.MY_VAR;
  return `MY_ENV_VAR is set to ${env}!`;
}

export default myModule;

Test jest:

const vals = [
  'ONE',
  'TWO',
  'THREE',
];

vals.forEach((val) => {
  it(`Returns the correct string for each ${val} value`, () => {
    process.env.MY_VAR = val;

    expect(envMessage()).toEqual(...
RobW
źródło
0

Myślę, że ty też możesz spróbować:

const currentEnv = process.env;
process.env = { ENV_NODE: 'whatever' };

// test code...

process.env = currentEnv;

To działa dla mnie i nie potrzebujesz rzeczy modułowych

andy
źródło
problem polega na tym, że jeśli zaimportujesz inny plik, który używa process.env, bezpośrednia zmiana nie przyniesie żadnego efektu. Więc przed każdym testem musisz powiedzieć Jest coś w stylu - „hej, zaimportuj i ponownie uruchom ten plik”.
Tomasz Mularczyk
0

Moim zdaniem jest znacznie czystszy i łatwiejszy do zrozumienia, jeśli wyodrębnisz pobieranie zmiennych środowiskowych do narzędzia (prawdopodobnie chcesz dołączyć sprawdzenie, czy szybko się nie powiedzie, jeśli zmienna środowiskowa i tak nie jest ustawiona), wtedy możesz po prostu mockować narzędzie .

// util.js
exports.getEnv = (key) => {
    const value = process.env[key];
    if (value === undefined) {
      throw new Error(`Missing required environment variable ${key}`);
    }
    return value;
};

// app.test.js
const util = require('./util');
jest.mock('./util');

util.getEnv.mockImplementation(key => `fake-${key}`);

test('test', () => {...});
David Good
źródło