Мокирование
При написании тестов часто возникает необходимость создать имитированную версию внутренней или внешней службы. Этот процесс обычно называется мокированием. Vitest предоставляет вспомогательные функции для этого через объект vi
. Вы можете импортировать его из vitest
или получить к нему доступ глобально, если включена конфигурация global
.
WARNING
Всегда помните очищать или восстанавливать моки до или после каждого запуска теста, чтобы сбросить их состояние между запусками! Дополнительную информацию см. в документации mockReset
.
Если вы не знакомы с методами vi.fn
, vi.mock
или vi.spyOn
, сначала ознакомьтесь с разделом API.
Даты
Иногда необходимо контролировать дату для обеспечения согласованности при тестировании. Vitest использует пакет @sinonjs/fake-timers
для манипулирования таймерами и системной датой. Более подробную информацию о конкретном API можно найти здесь.
Пример
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const businessHours = [9, 17];
function purchase() {
const currentHour = new Date().getHours();
const [open, close] = businessHours;
if (currentHour > open && currentHour < close) {
return { message: 'Success' };
}
return { message: 'Error' };
}
describe('purchasing flow', () => {
beforeEach(() => {
// информируем vitest о том, что мы используем мокированное время
vi.useFakeTimers();
});
afterEach(() => {
// восстанавливаем реальное время после каждого теста
vi.useRealTimers();
});
it('allows purchases within business hours', () => {
// устанавливаем час в пределах рабочего времени
const date = new Date(2000, 1, 1, 13);
vi.setSystemTime(date);
// вызов Date.now() вернет дату, установленную выше
expect(purchase()).toEqual({ message: 'Success' });
});
it('disallows purchases outside of business hours', () => {
// устанавливаем час за пределами рабочего времени
const date = new Date(2000, 1, 1, 19);
vi.setSystemTime(date);
// вызов Date.now() вернет дату, установленную выше
expect(purchase()).toEqual({ message: 'Error' });
});
});
Функции
Мокирование функций можно разделить на две категории: отслеживание и мокирование.
Иногда все, что вам нужно, это проверить, была ли вызвана конкретная функция (и, возможно, какие аргументы были переданы). В таких случаях достаточно отслеживания, которое можно использовать напрямую с vi.spyOn()
(подробнее здесь).
Однако отслеживание может только отслеживать функции, но не изменять их реализацию. В случае, когда нам нужно создать имитированную (или мокированную) версию функции, мы можем использовать vi.fn()
(подробнее здесь).
Мы используем Tinyspy в качестве основы для мокирования функций, но у нас есть собственная обертка, чтобы сделать его совместимым с jest
. Методы vi.fn()
и vi.spyOn()
обладают одинаковыми методами, однако только возвращаемый результат vi.fn()
является вызываемым.
Пример
import { afterEach, describe, expect, it, vi } from 'vitest';
const messages = {
items: [
{ message: 'Simple test message', from: 'Testman' },
// ...
],
getLatest, // также может быть `getter` или `setter`, если поддерживается
};
function getLatest(index = messages.items.length - 1) {
return messages.items[index];
}
describe('reading messages', () => {
afterEach(() => {
vi.restoreAllMocks();
});
it('should get the latest message with a spy', () => {
const spy = vi.spyOn(messages, 'getLatest');
expect(spy.getMockName()).toEqual('getLatest');
expect(messages.getLatest()).toEqual(
messages.items[messages.items.length - 1]
);
expect(spy).toHaveBeenCalledTimes(1);
spy.mockImplementationOnce(() => 'access-restricted');
expect(messages.getLatest()).toEqual('access-restricted');
expect(spy).toHaveBeenCalledTimes(2);
});
it('should get with a mock', () => {
const mock = vi.fn().mockImplementation(getLatest);
expect(mock()).toEqual(messages.items[messages.items.length - 1]);
expect(mock).toHaveBeenCalledTimes(1);
mock.mockImplementationOnce(() => 'access-restricted');
expect(mock()).toEqual('access-restricted');
expect(mock).toHaveBeenCalledTimes(2);
expect(mock()).toEqual(messages.items[messages.items.length - 1]);
expect(mock).toHaveBeenCalledTimes(3);
});
});
Подробнее
Глобальные переменные
Вы можете мокировать глобальные переменные, которые не определены в jsdom
или node
, используя вспомогательную функцию vi.stubGlobal
. Она установит значение глобальной переменной в объекте globalThis
.
import { vi } from 'vitest';
const IntersectionObserverMock = vi.fn(() => ({
disconnect: vi.fn(),
observe: vi.fn(),
takeRecords: vi.fn(),
unobserve: vi.fn(),
}));
vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
// теперь вы можете получить к нему доступ как `IntersectionObserver` или `window.IntersectionObserver`
Модули
Мокирование модулей позволяет имитировать сторонние библиотеки, которые вызываются в другом коде, позволяя тестировать аргументы, вывод или даже переопределять их реализацию.
Подробное описание API см. в разделе vi.mock()
API.
Алгоритм автомокирования
Если ваш код импортирует мокированный модуль без связанного файла __mocks__
или factory
для этого модуля, Vitest будет мокировать сам модуль, вызывая его и мокируя каждый экспорт.
Применяются следующие принципы:
- Все массивы будут опустошены.
- Все примитивы и коллекции останутся без изменений.
- Все объекты будут глубоко клонированы.
- Все экземпляры классов и их прототипы будут клонированы с глубоким копированием.
Виртуальные модули
Vitest поддерживает мокирование виртуальных модулей Vite. Это работает иначе, чем обработка виртуальных модулей в Jest. Вместо передачи virtual: true
в функцию vi.mock
, вам нужно сообщить Vite, что модуль существует, иначе это приведет к ошибке во время парсинга. Вы можете сделать это несколькими способами:
- Предоставить псевдоним
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
test: {
alias: {
'$app/forms': resolve('./mocks/forms.js'),
},
},
});
- Предоставить плагин, который разрешает виртуальный модуль
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [
{
name: 'virtual-modules',
resolveId(id) {
if (id === '$app/forms') {
return 'virtual:$app/forms';
}
},
},
],
});
Преимущество второго подхода заключается в том, что вы можете динамически создавать различные виртуальные точки входа. Если вы перенаправляете несколько виртуальных модулей в один файл, то vi.mock
повлияет на все из них, поэтому убедитесь, что используете уникальные идентификаторы.
Особенности мокирования
Имейте в виду, что невозможно мокировать вызовы методов, которые вызываются внутри других методов того же файла. Например, в этом коде:
export function foo() {
return 'foo';
}
export function foobar() {
return `${foo()}bar`;
}
Невозможно мокировать метод foo
извне, потому что он вызывается напрямую. Таким образом, этот код не повлияет на вызов foo
в функции foobar
(но повлияет на вызов foo
в других модулях):
import { vi } from 'vitest';
import * as mod from './foobar.js';
// это повлияет только на "foo" вне исходного модуля
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
return {
...(await importOriginal<typeof import('./foobar.js')>()),
// это повлияет только на "foo" вне исходного модуля
foo: () => 'mocked',
};
});
Вы можете подтвердить это поведение, предоставив реализацию методу foobar
напрямую:
import * as mod from './foobar.js';
vi.spyOn(mod, 'foo');
// экспортированный foo ссылается на мокированный метод
mod.foobar(mod.foo);
export function foo() {
return 'foo';
}
export function foobar(injectedFoo) {
return injectedFoo === foo; // false
}
Такое поведение является ожидаемым. Обычно это может свидетельствовать о плохом коде, когда мокирование используется таким образом. Рассмотрите необходимость рефакторинга вашего кода в несколько файлов или улучшения архитектуры вашего приложения с использованием таких методов, как внедрение зависимостей.
Пример
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';
// получить задачи
export async function getTodos(event, context) {
const client = new Client({
// ...clientOptions
});
await client.connect();
try {
const result = await client.query('SELECT * FROM todos;');
client.end();
return success({
message: `${result.rowCount} item(s) returned`,
data: result.rows,
status: true,
});
} catch (e) {
console.error(e.stack);
client.end();
return failure({ message: e, status: false });
}
}
vi.mock('pg', () => {
const Client = vi.fn();
Client.prototype.connect = vi.fn();
Client.prototype.query = vi.fn();
Client.prototype.end = vi.fn();
return { Client };
});
vi.mock('./handlers.js', () => {
return {
success: vi.fn(),
failure: vi.fn(),
};
});
describe('get a list of todo items', () => {
let client;
beforeEach(() => {
client = new Client();
});
afterEach(() => {
vi.clearAllMocks();
});
it('should return items successfully', async () => {
client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });
await getTodos();
expect(client.connect).toBeCalledTimes(1);
expect(client.query).toBeCalledWith('SELECT * FROM todos;');
expect(client.end).toBeCalledTimes(1);
expect(success).toBeCalledWith({
message: '0 item(s) returned',
data: [],
status: true,
});
});
it('should throw an error', async () => {
const mError = new Error('Unable to retrieve rows');
client.query.mockRejectedValueOnce(mError);
await getTodos();
expect(client.connect).toBeCalledTimes(1);
expect(client.query).toBeCalledWith('SELECT * FROM todos;');
expect(client.end).toBeCalledTimes(1);
expect(failure).toBeCalledWith({ message: mError, status: false });
});
});
Файловая система
Мокирование файловой системы гарантирует, что тесты не зависят от реальной файловой системы, что делает тесты более надежными и предсказуемыми. Такая изоляция позволяет избежать влияния предыдущих тестов. Она позволяет тестировать условия ошибок и граничные случаи, которые трудно или невозможно воспроизвести с реальной файловой системой, например, проблемы с разрешениями, сценарии заполнения диска или ошибки чтения/записи.
Vitest не предоставляет встроенного API для имитации файловой системы. Вы можете использовать vi.mock
для ручной имитации модуля fs
, но это сложно в поддержке. Вместо этого мы рекомендуем использовать memfs
. memfs
создает файловую систему в памяти, которая имитирует операции файловой системы без обращения к реальному диску. Этот подход быстр и безопасен, предотвращая любые потенциальные побочные эффекты в реальной файловой системе.
Пример
Чтобы автоматически перенаправлять все вызовы fs
в memfs
, вы можете создать файлы __mocks__/fs.cjs
и __mocks__/fs/promises.cjs
в корне вашего проекта:
// мы также можем использовать `import`, но тогда
// каждый экспорт должен быть явно определен
const { fs } = require('memfs');
module.exports = fs;
// мы также можем использовать `import`, но тогда
// каждый экспорт должен быть явно определен
const { fs } = require('memfs');
module.exports = fs.promises;
import { readFileSync } from 'node:fs';
export function readHelloWorld(path) {
return readFileSync(path, 'utf-8');
}
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';
// сообщаем vitest использовать мок fs из папки __mocks__
// это можно сделать в файле настройки, если fs всегда должен быть мокирован
vi.mock('node:fs');
vi.mock('node:fs/promises');
beforeEach(() => {
// сбрасываем состояние файловой системы в памяти
vol.reset();
});
it('should return correct text', () => {
const path = '/hello-world.txt';
fs.writeFileSync(path, 'hello world');
const text = readHelloWorld(path);
expect(text).toBe('hello world');
});
it('can return a value multiple times', () => {
// вы можете использовать vol.fromJSON для определения нескольких файлов
vol.fromJSON(
{
'./dir1/hw.txt': 'hello dir1',
'./dir2/hw.txt': 'hello dir2',
},
// cwd по умолчанию
'/tmp'
);
expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});
Запросы
Поскольку Vitest работает в Node, мокирование сетевых запросов является непростой задачей; веб-API не поддерживаются, поэтому нам нужно что-то, что будет имитировать сетевое поведение. Мы рекомендуем Mock Service Worker для достижения этой цели. Он позволяет мокировать сетевые запросы http
, WebSocket
и GraphQL
и не привязан к фреймворку.
Mock Service Worker (MSW) работает путем перехвата запросов, выполняемых вашими тестами, что позволяет использовать его без изменения кода вашего приложения. В браузере для этого используется Service Worker API. В Node.js и для Vitest он использует библиотеку @mswjs/interceptors
. Чтобы узнать больше о MSW, прочитайте их введение
Конфигурация
Вы можете использовать его, как показано ниже, в вашем файле настройки
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
];
export const restHandlers = [
http.get('https://rest-endpoint.example/path/to/posts', () => {
return HttpResponse.json(posts);
}),
];
const server = setupServer(...restHandlers);
// Запустить сервер перед всеми тестами
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Закрыть сервер после всех тестов
afterAll(() => server.close());
// Сбросить обработчики после каждого теста для изоляции тестов
afterEach(() => server.resetHandlers());
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';
const posts = [
{
userId: 1,
id: 1,
title: 'first post title',
body: 'first post body',
},
// ...
];
const graphqlHandlers = [
graphql.query('ListPosts', () => {
return HttpResponse.json({
data: { posts },
});
}),
];
const server = setupServer(...graphqlHandlers);
// Запустить сервер перед всеми тестами
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Закрыть сервер после всех тестов
afterAll(() => server.close());
// Сбросить обработчики после каждого теста для изоляции тестов
afterEach(() => server.resetHandlers());
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';
const chat = ws.link('wss://chat.example.com');
const wsHandlers = [
chat.addEventListener('connection', ({ client }) => {
client.addEventListener('message', event => {
console.log('Received message from client:', event.data);
// Отправляем полученное сообщение обратно клиенту
client.send(`Server received: ${event.data}`);
});
}),
];
const server = setupServer(...wsHandlers);
// Запустить сервер перед всеми тестами
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
// Закрыть сервер после всех тестов
afterAll(() => server.close());
// Сбросить обработчики после каждого теста для изоляции тестов
afterEach(() => server.resetHandlers());
Настройка сервера с
onUnhandledRequest: 'error'
гарантирует, что будет выброшена ошибка при каждом запросе, для которого не найден соответствующий обработчик.
Подробнее
MSW предоставляет гораздо больше возможностей. Вы можете получать доступ к файлам cookie и параметрам запроса, определять имитированные ответы об ошибках и многое другое! Чтобы узнать все, что вы можете сделать с MSW, прочитайте их документацию.
Таймеры
Когда мы тестируем код, который использует тайм-ауты или интервалы, вместо того чтобы наши тесты ждали или завершались по тайм-ауту, мы можем ускорить наши тесты, используя "фальшивые" таймеры, которые имитируют вызовы setTimeout
и setInterval
.
Подробное описание API см. в разделе vi.useFakeTimers
API.
Пример
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
function executeAfterTwoHours(func) {
setTimeout(func, 1000 * 60 * 60 * 2); // 2 часа
}
function executeEveryMinute(func) {
setInterval(func, 1000 * 60); // 1 минута
}
const mock = vi.fn(() => console.log('executed'));
describe('delayed execution', () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.restoreAllMocks();
});
it('should execute the function', () => {
executeAfterTwoHours(mock);
vi.runAllTimers();
expect(mock).toHaveBeenCalledTimes(1);
});
it('should not execute the function', () => {
executeAfterTwoHours(mock);
// перемещение времени на 2 мс не вызовет функцию
vi.advanceTimersByTime(2);
expect(mock).not.toHaveBeenCalled();
});
it('should execute every minute', () => {
executeEveryMinute(mock);
vi.advanceTimersToNextTimer();
expect(mock).toHaveBeenCalledTimes(1);
vi.advanceTimersToNextTimer();
expect(mock).toHaveBeenCalledTimes(2);
});
});
Классы
Вы можете мокировать весь класс одним вызовом vi.fn
— поскольку все классы также являются функциями, это поддерживается по умолчанию. Имейте в виду, что в настоящее время Vitest не обрабатывает ключевое слово new
, поэтому new.target
всегда будет undefined
в теле функции.
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
static getType(): string {
return 'animal';
}
greet = (): string => {
return `Hi! My name is ${this.name}!`;
};
speak(): string {
return 'bark!';
}
isHungry() {}
feed() {}
}
Мы можем воссоздать этот класс с помощью функций ES5:
const Dog = vi.fn(function (name) {
this.name = name;
// имитируем методы экземпляра в конструкторе, каждый экземпляр будет иметь свой собственный отслеживаемый метод
this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});
// обратите внимание, что статические методы имитируются непосредственно на функции,
// а не на экземпляре класса
Dog.getType = vi.fn(() => 'mocked animal');
// имитируем методы "speak" и "feed" на каждом экземпляре класса
// все экземпляры `new Dog()` будут наследовать и совместно использовать эти отслеживаемые методы
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();
WARNING
Если из функции-конструктора возвращается не примитивное значение, это значение станет результатом нового выражения. В этом случае [[Prototype]]
может быть некорректно установлен:
const CorrectDogClass = vi.fn(function (name) {
this.name = name;
});
const IncorrectDogClass = vi.fn(name => ({
name,
}));
const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');
Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!
КОГДА ИСПОЛЬЗОВАТЬ?
Как правило, класс воссоздается таким образом внутри фабрики модуля, если он реэкспортируется из другого модуля:
import { Dog } from './dog.js';
vi.mock(import('./dog.js'), () => {
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
// ... другие моки
return { Dog };
});
Этот метод также можно использовать для передачи экземпляра класса функции, которая принимает тот же интерфейс:
function feed(dog: Dog) {
// ...
}
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
test('can feed dogs', () => {
const dogMax = new Dog('Max');
feed(dogMax);
expect(dogMax.feed).toHaveBeenCalled();
expect(dogMax.isHungry()).toBe(false);
});
Теперь, когда мы создаем новый экземпляр класса Dog
, его метод speak
(наряду с feed
и greet
) уже мокирован:
const Cooper = new Dog('Cooper');
Cooper.speak(); // loud bark!
Cooper.greet(); // Hi! My name is Cooper!
// вы можете использовать встроенные утверждения для проверки корректности вызова
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();
const Max = new Dog('Max');
// методы, назначенные прототипу, являются общими между экземплярами
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();
Мы можем переназначить возвращаемое значение для конкретного экземпляра:
const dog = new Dog('Cooper');
// "vi.mocked" - это вспомогательный тип, поскольку
// TypeScript не знает, что Dog - это мокированный класс,
// он оборачивает любую функцию в тип MockInstance<T>
// без проверки, является ли функция моком
vi.mocked(dog.speak).mockReturnValue('woof woof');
dog.speak(); // woof woof
Чтобы мокировать свойство, мы можем использовать метод vi.spyOn(dog, 'name', 'get')
. Это позволяет использовать утверждения отслеживания для мокированного свойства:
const dog = new Dog('Cooper');
const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');
expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);
TIP
Вы также можете отслеживать геттеры и сеттеры, используя тот же метод.
Шпаргалка
INFO
vi
в примерах ниже импортируется непосредственно из vitest
. Вы также можете использовать его глобально, если установите globals
в true
в вашей конфигурации.
Возможные сценарии:
Мокировать экспортированные переменные
export const getter = 'variable';
import * as exports from './example.js';
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');
Мокировать экспортированную функцию
- Пример с
vi.mock
:
WARNING
Не забывайте, что вызов vi.mock
перемещается в начало файла. Он всегда будет выполняться перед всеми импортами.
export function method() {}
import { method } from './example.js';
vi.mock('./example.js', () => ({
method: vi.fn(),
}));
- Пример с
vi.spyOn
:
import * as exports from './example.js';
vi.spyOn(exports, 'method').mockImplementation(() => {});
Мокировать реализацию экспортированного класса
- Пример с
vi.mock
и.prototype
:
export class SomeClass {}
import { SomeClass } from './example.js';
vi.mock(import('./example.js'), () => {
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
return { SomeClass };
});
// SomeClass.mock.instances будет иметь SomeClass
- Пример с
vi.spyOn
:
import * as mod from './example.js';
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);
Отслеживать объект, возвращаемый из функции
- Пример использования кеша:
export function useObject() {
return { method: () => true };
}
import { useObject } from './example.js';
const obj = useObject();
obj.method();
import { useObject } from './example.js';
vi.mock(import('./example.js'), () => {
let _cache;
const useObject = () => {
if (!_cache) {
_cache = {
method: vi.fn(),
};
}
// теперь каждый раз, когда вызывается useObject(), он будет
// возвращать ту же ссылку на объект
return _cache;
};
return { useObject };
});
const obj = useObject();
// obj.method был вызван внутри some-path
expect(obj.method).toHaveBeenCalled();
Мокировать часть модуля
import { mocked, original } from './some-path.js';
vi.mock(import('./some-path.js'), async importOriginal => {
const mod = await importOriginal();
return {
...mod,
mocked: vi.fn(),
};
});
original(); // сохраняет оригинальное поведение
mocked(); // является отслеживаемой функцией
WARNING
Не забывайте, что это мокирует только внешний доступ. В этом примере, если original
вызывает mocked
внутренне, он всегда будет вызывать функцию, определенную в модуле, а не в фабрике моков.
Мокировать текущую дату
Чтобы мокировать время Date
, вы можете использовать вспомогательную функцию vi.setSystemTime
. Это значение не будет автоматически сбрасываться между различными тестами.
Имейте в виду, что использование vi.useFakeTimers
также изменяет время Date
.
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// сброс мокированного времени
vi.useRealTimers();
Мокировать глобальную переменную
Вы можете установить глобальную переменную, присвоив значение свойству globalThis
или используя вспомогательную функцию vi.stubGlobal
. При использовании vi.stubGlobal
она не будет автоматически сбрасываться между различными тестами, если вы не включите опцию конфигурации unstubGlobals
или не вызовете vi.unstubAllGlobals
.
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
Мокировать import.meta.env
- Чтобы изменить переменную окружения, вы можете просто присвоить ей новое значение.
WARNING
Значение переменной окружения не будет автоматически сбрасываться между различными тестами.
import { beforeEach, expect, it } from 'vitest';
// перед запуском тестов "VITE_ENV" имеет значение "test"
const originalViteEnv = import.meta.env.VITE_ENV;
beforeEach(() => {
import.meta.env.VITE_ENV = originalViteEnv;
});
it('changes value', () => {
import.meta.env.VITE_ENV = 'staging';
expect(import.meta.env.VITE_ENV).toBe('staging');
});
- Если вы хотите автоматически сбрасывать значение(я), вы можете использовать вспомогательную функцию
vi.stubEnv
с включенной опцией конфигурацииunstubEnvs
(или вручную вызватьvi.unstubAllEnvs
в хукеbeforeEach
):
import { expect, it, vi } from 'vitest';
// перед запуском тестов "VITE_ENV" имеет значение "test"
import.meta.env.VITE_ENV === 'test';
it('changes value', () => {
vi.stubEnv('VITE_ENV', 'staging');
expect(import.meta.env.VITE_ENV).toBe('staging');
});
it('the value is restored before running an other test', () => {
expect(import.meta.env.VITE_ENV).toBe('test');
});
export default defineConfig({
test: {
unstubEnvs: true,
},
});