Vi
O Vitest fornece funções utilitárias para auxiliar você, acessíveis através do seu auxiliar vi
. Você pode acessá-lo globalmente (quando a configuração de globais está habilitada), ou importá-lo diretamente de vitest
:
import { vi } from 'vitest';
Mock de módulos
Esta seção descreve a API que você pode usar ao simular um módulo. É importante notar que o Vitest não suporta simular módulos importados usando require()
.
vi.mock
- Tipo:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
Substitui todos os módulos importados do path
fornecido por outro módulo. Você pode usar aliases Vite configurados no caminho. A chamada para vi.mock
é elevada (hoisted), então não importa onde você a chame. Ela sempre será executada antes de todas as importações. Se você precisar referenciar algumas variáveis fora de seu escopo, você pode defini-las dentro de vi.hoisted
e referenciá-las dentro de vi.mock
.
WARNING
vi.mock
funciona apenas para módulos que foram importados com a palavra-chave import
. Não funciona com require
.
Para elevar (hoist) vi.mock
, o Vitest analisa estaticamente seus arquivos. Isso indica que vi
que não foi diretamente importado do pacote vitest
(por exemplo, de algum arquivo utilitário) não poderá ser utilizado. Use vi.mock
com vi
importado de vitest
, ou habilite a opção de configuração globals
.
O Vitest não simulará módulos que foram importados dentro de um arquivo de configuração porque eles são armazenados em cache no momento em que um arquivo de teste está sendo executado. Você pode chamar vi.resetModules()
dentro de vi.hoisted
para limpar todos os caches de módulo antes de executar um arquivo de teste.
WARNING
O modo navegador não suporta atualmente simular módulos. Você pode acompanhar este recurso na issue do GitHub.
Se factory
for definido, todas as importações retornarão seu resultado. O Vitest chama a factory apenas uma vez e armazena os resultados em cache para todas as importações subsequentes até que vi.unmock
ou vi.doUnmock
seja chamado.
Ao contrário do jest
, a factory pode ser assíncrona. Você pode usar vi.importActual
ou um auxiliar com a factory passada como o primeiro argumento, e obter o módulo original dentro.
import { vi } from 'vitest';
// ---cut---
// when using JavaScript
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal();
return {
...mod,
// replace some exports
namedExport: vi.fn(),
};
});
// when using TypeScript
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal<typeof import('./path/to/module.js')>();
return {
...mod,
// replace some exports
namedExport: vi.fn(),
};
});
WARNING
vi.mock
é elevado (hoisted) (em outras palavras, movido) para o topo do arquivo. Isso significa que sempre que você o escrever (seja dentro de beforeEach
ou test
), ele será realmente chamado antes disso.
Isso também significa que você não pode usar dentro da factory nenhuma variável definida fora dela.
Se você precisar usar variáveis dentro da factory, tente vi.doMock
. Funciona da mesma forma, mas não é elevado (hoisted). Esteja ciente de que ele só simula importações subsequentes.
Você também pode referenciar variáveis definidas pelo método vi.hoisted
se ele foi declarado antes de vi.mock
:
import { namedExport } from './path/to/module.js';
const mocks = vi.hoisted(() => {
return {
namedExport: vi.fn(),
};
});
vi.mock('./path/to/module.js', () => {
return {
namedExport: mocks.namedExport,
};
});
vi.mocked(namedExport).mockReturnValue(100);
expect(namedExport()).toBe(100);
expect(namedExport).toBe(mocks.namedExport);
WARNING
Se você estiver simulando um módulo com exportação padrão, você precisará fornecer uma chave default
dentro do objeto da função factory retornada. Esta é uma particularidade específica dos módulos ES; portanto, a documentação do jest
pode ser diferente, pois o jest
usa módulos CommonJS. Por exemplo,
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// etc...
};
});
Se houver uma pasta __mocks__
junto com um arquivo que você está simulando, e a factory não for fornecida, o Vitest tentará encontrar um arquivo com o mesmo nome na subpasta __mocks__
e usá-lo como um módulo real. Se você estiver simulando uma dependência, o Vitest tentará encontrar uma pasta __mocks__
na raiz do projeto (o padrão é process.cwd()
). Você pode indicar ao Vitest onde as dependências estão localizadas através da opção de configuração deps.moduleDirectories.
Por exemplo, você tem esta estrutura de arquivos:
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
Se você chamar vi.mock
em um arquivo de teste sem uma factory fornecida, ele encontrará um arquivo na pasta __mocks__
para usar como um módulo:
// increment.test.js
import { vi } from 'vitest';
// axios is a default export from `__mocks__/axios.js`
import axios from 'axios';
// increment is a named export from `src/__mocks__/increment.js`
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
É importante notar que se você não chamar vi.mock
, os módulos não são simulados automaticamente. Para replicar o comportamento de auto-mocking do Jest, você pode chamar vi.mock
para cada módulo necessário dentro de setupFiles
.
Se não houver uma pasta __mocks__
ou uma factory fornecida, o Vitest importará o módulo original e auto-simulará todas as suas exportações. Para as regras aplicadas, veja algoritmo.
vi.doMock
- Tipo:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
O mesmo que vi.mock
, mas não é elevado (hoisted) para o topo do arquivo, então você pode referenciar variáveis no escopo de arquivo global. A próxima importação dinâmica do módulo será simulada.
WARNING
Isso não simulará módulos que foram importados antes de ser chamado. Lembre-se que todas as importações estáticas em ESM são sempre elevadas (hoisted)(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#hoisting), então colocar isso antes da importação estática não forçará que seja chamado antes da importação:
vi.doMock('./increment.js'); // this will be called _after_ the import statement
import { increment } from './increment.js';
// ./increment.js
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// the module is not mocked, because vi.doMock is not called yet
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// you can access variables inside a factory
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('importing the next module imports mocked one', async () => {
// original import WAS NOT MOCKED, because vi.doMock is evaluated AFTER imports
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// new dynamic import returns mocked module
expect(mockedIncrement(1)).toBe(101);
expect(mockedIncrement(1)).toBe(102);
expect(mockedIncrement(1)).toBe(103);
});
vi.mocked
- Tipo:
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
- Tipo:
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>
Auxiliar de tipo para TypeScript. Apenas retorna o objeto que foi passado.
Quando partial
é true
, ele esperará um Partial<T>
como um valor de retorno. Por padrão, isso só fará com que o TypeScript acredite que os valores do primeiro nível são simulados. Você pode passar { deep: true }
como um segundo argumento para dizer ao TypeScript que o objeto inteiro é simulado, se for o caso.
import example from './example.js';
vi.mock('./example.js');
test('1 + 1 equals 10', async () => {
vi.mocked(example.calc).mockReturnValue(10);
expect(example.calc(1, '+', 1)).toBe(10);
});
vi.importActual
- Tipo:
<T>(path: string) => Promise<T>
Importa o módulo, ignorando todas as verificações se ele deve ser simulado. Pode ser útil se você quiser simular o módulo parcialmente.
vi.mock('./example.js', async () => {
const axios = await vi.importActual('./example.js');
return { ...axios, get: vi.fn() };
});
vi.importMock
- Tipo:
<T>(path: string) => Promise<MaybeMockedDeep<T>>
Importa um módulo com todas as suas propriedades (incluindo propriedades aninhadas) simuladas. Segue as mesmas regras que vi.mock
faz. Para as regras aplicadas, veja algoritmo.
vi.unmock
- Tipo:
(path: string) => void
Remove o módulo do registro simulado. Todas as chamadas para importar retornarão o módulo original, mesmo que tenha sido simulado antes. Esta chamada é elevada (hoisted) para o topo do arquivo, então ela só des-simulará módulos que foram definidos em setupFiles
, por exemplo.
vi.doUnmock
- Tipo:
(path: string) => void
O mesmo que vi.unmock
, mas não é elevado (hoisted) para o topo do arquivo. A próxima importação do módulo importará o módulo original em vez do mock. Isso não des-simulará módulos importados anteriormente.
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment is already mocked, because vi.mock is hoisted
increment(1) === 100;
// this is hoisted, and factory is called before the import on line 1
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// all calls are mocked, and `increment` always returns 100
increment(1) === 100;
increment(30) === 100;
// this is not hoisted, so other import will return unmocked module
vi.doUnmock('./increment.js');
// this STILL returns 100, because `vi.doUnmock` doesn't reevaluate a module
increment(1) === 100;
increment(30) === 100;
// the next import is unmocked, now `increment` is the original function that returns count + 1
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Tipo:
() => Vitest
Redefine o registro de módulos, limpando o cache de todos os módulos. Isso permite que os módulos sejam reavaliados quando reimportados. As importações de nível superior não podem ser reavaliadas. Pode ser útil para isolar módulos onde o estado local entra em conflito entre os testes.
import { vi } from 'vitest';
import { data } from './data.js'; // Will not get reevaluated beforeEach test
beforeEach(() => {
vi.resetModules();
});
test('change state', async () => {
const mod = await import('./some/path.js'); // Will get reevaluated
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('module has old state', async () => {
const mod = await import('./some/path.js'); // Will get reevaluated
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Não redefine o registro de mocks. Para limpar o registro de mocks, use vi.unmock
ou vi.doUnmock
.
vi.dynamicImportSettled
Espera que todas as importações dinâmicas sejam carregadas. Útil, se você tiver uma chamada síncrona que começa a importar um módulo que você não pode esperar de outra forma.
import { expect, test } from 'vitest';
// cannot track import because Promise is not returned
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('operations are resolved', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Se durante uma importação dinâmica outra importação dinâmica for iniciada, este método esperará até que todas elas sejam resolvidas.
Este método também esperará pelo próximo tick de setTimeout
após a importação ser resolvida, para que todas as operações síncronas sejam concluídas no momento em que for resolvida.
Simulando Funções e Objetos
Esta seção descreve como trabalhar com mocks de método e substituir variáveis ambientais e globais.
vi.fn
- Tipo:
(fn?: Function) => Mock
Monitora uma função, podendo ser iniciado sem uma função. A cada invocação, a função armazena seus argumentos, retornos e instâncias. O comportamento pode ser manipulado com métodos. Se nenhuma função for fornecida, o mock retorna undefined
ao ser invocado.
import { expect, vi } from 'vitest';
// ---cut---
const getApples = vi.fn(() => 0);
getApples();
expect(getApples).toHaveBeenCalled();
expect(getApples).toHaveReturnedWith(0);
getApples.mockReturnValueOnce(5);
const res = getApples();
expect(res).toBe(5);
expect(getApples).toHaveNthReturnedWith(2, 5);
vi.isMockFunction
- Tipo:
(fn: Function) => boolean
Verifica se um parâmetro é uma função mock. Se estiver usando TypeScript, o tipo também será restringido.
vi.clearAllMocks
Chama .mockClear()
em todos os espiões. Limpa o histórico de mocks, mas não redefine a implementação para o padrão.
vi.resetAllMocks
Chama .mockReset()
em todos os espiões. Limpa o histórico de mocks e redefine a implementação para uma função vazia (que retorna undefined
).
vi.restoreAllMocks
Chama .mockRestore()
em todos os espiões. Limpa o histórico de mocks e redefine a implementação para a original.
vi.spyOn
- Tipo:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
Cria um espião para um método ou getter/setter de um objeto, similar a vi.fn()
. Retorna uma função mock.
import { expect, vi } from 'vitest';
// ---cut---
let apples = 0;
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples);
apples = 1;
expect(cart.getApples()).toBe(1);
expect(spy).toHaveBeenCalled();
expect(spy).toHaveReturnedWith(1);
TIP
Chame vi.restoreAllMocks
em afterEach
(ou habilite test.restoreMocks
) para restaurar todos os métodos às suas implementações originais. Isso restaura o descritor de objeto original, impedindo a alteração da implementação do método:
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockReturnValue(10);
console.log(cart.getApples()); // 10
vi.restoreAllMocks();
console.log(cart.getApples()); // 42
spy.mockReturnValue(10);
console.log(cart.getApples()); // still 42!
vi.stubEnv 0.26.0+
- Tipo:
(name: string, value: string) => Vitest
Altera o valor de uma variável de ambiente em process.env
e import.meta.env
. Restaure o valor com vi.unstubAllEnvs
.
import { vi } from 'vitest';
// `process.env.NODE_ENV` and `import.meta.env.NODE_ENV`
// are "development" before calling "vi.stubEnv"
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
// doesn't change other envs
import.meta.env.MODE === 'development';
TIP
Você pode alterar o valor atribuindo-o diretamente, mas não poderá usar vi.unstubAllEnvs
para restaurar o valor anterior:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs 0.26.0+
- Tipo:
() => Vitest
Restaura os valores de import.meta.env
e process.env
alterados com vi.stubEnv
. Na primeira chamada, o Vitest armazena o valor original e o restaura até que unstubAllEnvs
seja chamado novamente.
import { vi } from 'vitest';
// `process.env.NODE_ENV` and `import.meta.env.NODE_ENV`
// are "development" before calling stubEnv
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
vi.stubEnv('NODE_ENV', 'staging');
process.env.NODE_ENV === 'staging';
import.meta.env.NODE_ENV === 'staging';
vi.unstubAllEnvs();
// restores to the value that were stored before the first "stubEnv" call
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Tipo:
(name: string | number | symbol, value: unknown) => Vitest
Altera o valor de uma variável global. Restaure o valor original com vi.unstubAllGlobals
.
import { vi } from 'vitest';
// `innerWidth` is "0" before calling stubGlobal
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// if you are using jsdom or happy-dom
window.innerWidth === 100;
TIP
Você pode alterar o valor atribuindo-o diretamente a globalThis
ou window
(em ambientes jsdom
ou happy-dom
), mas não poderá usar vi.unstubAllGlobals
para restaurar o valor original:
globalThis.innerWidth = 100;
// if you are using jsdom or happy-dom
window.innerWidth = 100;
vi.unstubAllGlobals 0.26.0+
- Tipo:
() => Vitest
Restaura os valores globais em globalThis
/global
(e window
/top
/self
/parent
em ambientes jsdom
ou happy-dom
) alterados com vi.stubGlobal
. Na primeira chamada, o Vitest armazena o valor original e o restaura até que unstubAllGlobals
seja chamado novamente.
import { vi } from 'vitest';
const Mock = vi.fn();
// IntersectionObserver is "undefined" before calling "stubGlobal"
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// if you are using jsdom or happy-dom
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// throws ReferenceError, because it's not defined
IntersectionObserver === undefined;
Timers Falsificados (Fake Timers)
Esta seção descreve como trabalhar com timers falsos.
vi.advanceTimersByTime
- Tipo:
(ms: number) => Vitest
Este método executa todos os timers iniciados até que o número especificado de milissegundos tenha passado ou a fila de timers esteja vazia, o que ocorrer primeiro.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- Tipo:
(ms: number) => Promise<Vitest>
Este método executa todos os timers iniciados, incluindo os definidos de forma assíncrona, até que o número especificado de milissegundos tenha passado ou a fila de timers esteja vazia, o que ocorrer primeiro.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersByTimeAsync(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersToNextTimer
- Tipo:
() => Vitest
Executa o próximo timer disponível na fila. Útil para realizar verificações entre cada execução de timer. Você pode encadear chamadas para gerenciar os timers manualmente.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Tipo:
() => Promise<Vitest>
Executa o próximo timer disponível e aguarda até que ele seja resolvido, caso tenha sido definido de forma assíncrona. Útil para realizar verificações entre cada execução de timer.
import { expect, vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersToNextTimerAsync(); // log: 1
expect(console.log).toHaveBeenCalledWith(1);
await vi.advanceTimersToNextTimerAsync(); // log: 2
await vi.advanceTimersToNextTimerAsync(); // log: 3
vi.getTimerCount
- Tipo:
() => number
Retorna o número de timers pendentes.
vi.clearAllTimers
Remove todos os timers agendados, impedindo sua execução futura.
vi.getMockedSystemTime
- Tipo:
() => Date | null
Retorna a data simulada atual que foi definida usando setSystemTime
. Se a data não estiver sendo simulada, o método retornará null
.
vi.getRealSystemTime
- Tipo:
() => number
Ao usar vi.useFakeTimers
, as chamadas a Date.now
são simuladas. Se você precisar obter o tempo real em milissegundos, você pode chamar esta função.
vi.runAllTicks
- Tipo:
() => Vitest
Executa cada microtarefa que foi enfileirada por process.nextTick
. Isso também executará todas as microtarefas agendadas por si mesmas.
vi.runAllTimers
- Tipo:
() => Vitest
Este método executa todos os timers iniciados até que a fila de timers esteja vazia. Isso significa que cada timer agendado durante a execução de runAllTimers
será executado. Se você tiver um intervalo infinito, um erro será lançado após 10.000 tentativas (pode ser configurado com fakeTimers.loopLimit
).
import { vi } from 'vitest';
// ---cut---
let i = 0;
setTimeout(() => console.log(++i));
const interval = setInterval(() => {
console.log(++i);
if (i === 3) clearInterval(interval);
}, 50);
vi.runAllTimers();
// log: 1
// log: 2
// log: 3
vi.runAllTimersAsync
- Tipo:
() => Promise<Vitest>
Este método executa de forma assíncrona todos os timers iniciados até que a fila de timers esteja vazia. Isso significa que cada timer agendado durante a execução de runAllTimersAsync
será executado, incluindo timers assíncronos. Se você tiver um intervalo infinito, um erro será lançado após 10.000 tentativas (pode ser configurado com fakeTimers.loopLimit
).
import { vi } from 'vitest';
// ---cut---
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Tipo:
() => Vitest
Este método executa cada timer que foi iniciado após a chamada de vi.useFakeTimers
. Ele não executará nenhum timer que foi iniciado durante sua execução.
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Tipo:
() => Promise<Vitest>
Este método executa de forma assíncrona cada timer que foi iniciado após a chamada de vi.useFakeTimers
, mesmo os assíncronos. Ele não executará nenhum timer que foi iniciado durante sua execução.
import { vi } from 'vitest';
// ---cut---
setTimeout(() => {
console.log(1);
}, 100);
setTimeout(() => {
Promise.resolve().then(() => {
console.log(2);
setInterval(() => {
console.log(3);
}, 40);
});
}, 10);
await vi.runOnlyPendingTimersAsync();
// log: 2
// log: 3
// log: 3
// log: 1
vi.setSystemTime
- Tipo:
(date: string | number | Date) => void
Se a simulação de timers estiver habilitada, este método simula a alteração do relógio do sistema por um usuário (afetará a API relacionada à data como hrtime
, performance.now
ou new Date()
) - no entanto, ele não disparará nenhum timer. Se os timers falsos não estiverem habilitados, este método apenas simulará as chamadas Date.*
.
Útil se você precisar testar algo que depende da data atual - por exemplo, chamadas à biblioteca Luxon dentro do seu código.
import { expect, vi } from 'vitest';
// ---cut---
const date = new Date(1998, 11, 19);
vi.useFakeTimers();
vi.setSystemTime(date);
expect(Date.now()).toBe(date.valueOf());
vi.useRealTimers();
vi.useFakeTimers
- Tipo:
(config?: FakeTimerInstallOpts) => Vitest
Para habilitar a simulação de timers, você precisa chamar este método. Ele interceptará todas as chamadas subsequentes para timers (como setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
e Date
) até que vi.useRealTimers()
seja chamado.
A simulação de nextTick
não é suportada ao executar o Vitest dentro de node:child_process
usando --pool=forks
. NodeJS usa process.nextTick
internamente em node:child_process
e trava quando é simulado. A simulação de nextTick
é suportada ao executar o Vitest com --pool=threads
.
A implementação é baseada internamente em @sinonjs/fake-timers
.
TIP
Desde a versão 0.35.0
, vi.useFakeTimers()
não simula mais automaticamente process.nextTick
. Ele ainda pode ser simulado especificando a opção no argumento toFake
: vi.useFakeTimers({ toFake: ['nextTick'] })
.
vi.isFakeTimers 0.34.5+
- Tipo:
() => boolean
Retorna true
se os timers falsos estiverem habilitados.
vi.useRealTimers
- Tipo:
() => Vitest
Após o uso de timers simulados, você pode chamar este método para retornar os timers simulados para suas implementações originais. Todos os timers que foram agendados antes serão descartados.
Diversos
Um conjunto de funções auxiliares úteis que o Vitest fornece.
vi.waitFor 0.34.5+
- Tipo:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Espera que o callback seja executado com sucesso. Se o callback lançar um erro ou retornar uma promise rejeitada, a função aguardará até que ele seja bem-sucedido ou o tempo limite seja atingido.
Isso é muito útil quando você precisa aguardar a conclusão de alguma ação assíncrona, por exemplo, quando você inicia um servidor e precisa esperar que ele esteja pronto.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Server started successfully', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) throw new Error('Server not started');
console.log('Server started');
},
{
timeout: 500, // o valor padrão é 1000
interval: 20, // o valor padrão é 50
}
);
expect(server.isReady).toBe(true);
});
Também funciona para callbacks assíncronos
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Element exists in a DOM', async () => {
// start populating DOM
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// try to get the element until it exists
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // o valor padrão é 1000
interval: 20, // o valor padrão é 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
Se vi.useFakeTimers
for utilizado, vi.waitFor
chama automaticamente vi.advanceTimersByTime(interval)
em cada callback de verificação.
vi.waitUntil 0.34.5+
- Tipo:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Isso é semelhante a vi.waitFor
, mas se o callback lançar um erro, a execução é interrompida imediatamente e uma mensagem de erro é retornada. Se o callback retornar um valor falsy, a próxima verificação continuará até que um valor truthy seja retornado. Isso é útil quando você precisa esperar que algo exista antes de dar o próximo passo.
Veja o exemplo abaixo. Podemos usar vi.waitUntil
para esperar que o elemento apareça na página e, em seguida, podemos fazer algo com o elemento.
import { expect, test, vi } from 'vitest';
test('Element render correctly', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // o valor padrão é 1000
interval: 20, // o valor padrão é 50
});
// do something with the element
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted 0.31.0+
- Tipo:
<T>(factory: () => T) => T
Todas as declarações import
estáticas em módulos ES são hoisted (elevadas) para o topo do arquivo, então qualquer código que é definido antes dos imports será realmente executado após os imports serem avaliados.
No entanto, pode ser útil invocar alguns efeitos colaterais, como simulação de datas, antes de importar um módulo.
Para contornar essa limitação, você pode reescrever imports estáticos em dinâmicos como este:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
Ao executar vitest
, você pode fazer isso automaticamente usando o método vi.hoisted
.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
Este método retorna o valor que foi retornado da função fábrica. Você pode usar esse valor em suas fábricas vi.mock
se precisar de acesso fácil a variáveis definidas localmente:
import { expect, vi } from 'vitest';
import { originalMethod } from './path/to/module.js';
const { mockedMethod } = vi.hoisted(() => {
return { mockedMethod: vi.fn() };
});
vi.mock('./path/to/module.js', () => {
return { originalMethod: mockedMethod };
});
mockedMethod.mockReturnValue(100);
expect(originalMethod()).toBe(100);
Observe que este método também pode ser chamado de forma assíncrona, mesmo que seu ambiente não suporte top-level await.
const promised = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- Tipo:
RuntimeConfig
Atualiza a configuração para o arquivo de teste atual. Este método suporta apenas as opções de configuração que afetam o arquivo de teste atual:
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// supports the whole object
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// supports only "sequence.hooks"
},
});
vi.resetConfig
- Tipo:
RuntimeConfig
Se vi.setConfig
foi chamado anteriormente, isso reverterá a configuração para o estado original.