Test Runner
WARNING
Esta é uma API avançada. Se você apenas deseja executar testes, provavelmente não precisa dela. Ela é usada principalmente por autores de bibliotecas.
Você pode especificar o caminho para o seu test runner com a opção runner
no seu arquivo de configuração. Este arquivo deve ter uma exportação padrão que contenha um construtor de classe implementando estes métodos:
export interface VitestRunner {
/**
* A primeira coisa a ser chamada antes de realmente coletar e executar os testes.
*/
onBeforeCollect?: (paths: string[]) => unknown;
/**
* Chamado após coletar os testes e antes de "onBeforeRun".
*/
onCollected?: (files: File[]) => unknown;
/**
* Chamado quando o test runner deve cancelar as próximas execuções de testes.
* O runner deve ouvir este método e marcar os testes e suites como ignorados em
* "onBeforeRunSuite" e "onBeforeRunTask" quando for chamado.
*/
onCancel?: (reason: CancelReason) => unknown;
/**
* Chamado antes de executar um único teste. Ainda não tem "result".
*/
onBeforeRunTest?: (test: TaskPopulated) => unknown;
/**
* Chamado antes de realmente executar a função de teste. Já possui "result" com "state" e "startTime".
*/
onBeforeTryTask?: (
test: TaskPopulated,
options: { retry: number; repeats: number }
) => unknown;
/**
* Chamado após o resultado e o estado serem definidos.
*/
onAfterRunTask?: (test: TaskPopulated) => unknown;
/**
* Chamado logo após executar a função de teste. Ainda não possui o novo estado. Não será chamado se a função de teste lançar um erro.
*/
onAfterTryTask?: (
test: TaskPopulated,
options: { retry: number; repeats: number }
) => unknown;
/**
* Chamado antes de executar uma única suite. Ainda não tem "result".
*/
onBeforeRunSuite?: (suite: Suite) => unknown;
/**
* Chamado após executar uma única suite. Tem estado e resultado.
*/
onAfterRunSuite?: (suite: Suite) => unknown;
/**
* Se definido, será chamado em vez da partição e do tratamento usual de suites do Vitest.
* Os hooks "before" e "after" não serão ignorados.
*/
runSuite?: (suite: Suite) => Promise<void>;
/**
* Se definido, será chamado em vez do tratamento usual do Vitest. Útil se você tiver sua função de teste personalizada.
* Os hooks "before" e "after" não serão ignorados.
*/
runTask?: (test: TaskPopulated) => Promise<void>;
/**
* Chamado quando uma tarefa é atualizada. É o mesmo que "onTaskUpdate" em um reporter, mas isso está sendo executado no mesmo thread que os testes.
*/
onTaskUpdate?: (task: [string, TaskResult | undefined][]) => Promise<void>;
/**
* Chamado antes de executar todos os testes nos caminhos coletados.
*/
onBeforeRunFiles?: (files: File[]) => unknown;
/**
* Chamado logo após executar todos os testes nos caminhos coletados.
*/
onAfterRunFiles?: (files: File[]) => unknown;
/**
* Chamado quando um novo contexto para um teste é definido. É útil se você quiser adicionar propriedades personalizadas ao contexto.
* Se você só quiser definir um contexto personalizado com um runner, considere usar "beforeAll" em "setupFiles" em vez disso.
*
* Este método é chamado para os manipuladores "test" e "custom".
*
* @see https://www.getbook.com/en/book/vitest-2/advanced/runner#your-task-function
*/
extendTaskContext?: <T extends Test | Custom>(
context: TaskContext<T>
) => TaskContext<T>;
/**
* Chamado quando certos arquivos são importados. Pode ser chamado em duas situações: ao coletar testes e ao importar arquivos de setup.
*/
importFile: (filepath: string, source: VitestRunnerImportSource) => unknown;
/**
* Configuração publicamente disponível.
*/
config: VitestRunnerConfig;
}
Ao instanciar esta classe, o Vitest passa a configuração do Vitest, e você deve expô-la como a propriedade config
.
WARNING
O Vitest também injeta uma instância de ViteNodeRunner
como a propriedade __vitest_executor
. Você pode usá-la para processar arquivos no método importFile
(este é o comportamento padrão de TestRunner
e BenchmarkRunner
).
ViteNodeRunner
expõe o método executeId
, que é usado para importar arquivos de teste em um ambiente amigável ao Vite. Ou seja, ele resolverá importações e transformará o conteúdo do arquivo em tempo de execução para que o Node possa entendê-lo.
TIP
O suporte a snapshots e alguns outros recursos dependem do runner. Se você não quiser perder esse suporte, pode estender seu runner a partir de VitestTestRunner
importado de vitest/runners
. Ele também expõe BenchmarkNodeRunner
, se você quiser estender a funcionalidade de benchmark.
Tarefas
Suites e testes são chamados internamente de tasks
. O runner do Vitest inicia uma tarefa File
antes de coletar qualquer teste - este é um superconjunto de Suite
com algumas propriedades adicionais. Ele está disponível em todas as tarefas (incluindo File
) como uma propriedade file
.
interface File extends Suite {
/**
* O nome do pool ao qual o arquivo pertence.
* @default 'forks'
*/
pool?: string;
/**
* O caminho para o arquivo no formato UNIX.
*/
filepath: string;
/**
* O nome do projeto do workspace ao qual o arquivo pertence.
*/
projectName: string | undefined;
/**
* O tempo que levou para coletar todos os testes no arquivo.
* Esse tempo também inclui a importação de todas as dependências do arquivo.
*/
collectDuration?: number;
/**
* O tempo que levou para importar o arquivo de setup.
*/
setupDuration?: number;
/**
* Se o arquivo foi iniciado sem executar nenhum teste.
* Isso é feito para popular o estado no lado do servidor pelo Vitest.
*/
local?: boolean;
}
Cada suite tem uma propriedade tasks
que é populada durante a fase de coleta. É útil percorrer a árvore de tarefas de cima para baixo.
interface Suite extends TaskBase {
type: 'suite';
/**
* Tarefa de arquivo. É a tarefa raiz do arquivo.
*/
file: File;
/**
* Um array de tarefas que fazem parte da suite.
*/
tasks: Task[];
}
Cada tarefa tem uma propriedade suite
que referencia a suite em que está localizada. Se test
ou describe
forem iniciados no nível superior, eles não terão uma propriedade suite
(ela não será igual a file
!). File
também nunca tem uma propriedade suite
. É útil percorrer as tarefas de baixo para cima.
interface Test<ExtraContext = object> extends TaskBase {
type: 'test';
/**
* Contexto do teste que será passado para a função de teste.
*/
context: TaskContext<Test> & ExtraContext & TestContext;
/**
* Tarefa de arquivo. É a tarefa raiz do arquivo.
*/
file: File;
/**
* Se a tarefa foi ignorada chamando `t.skip()`.
*/
pending?: boolean;
/**
* Se a tarefa deve ser bem-sucedida se falhar. Se a tarefa falhar, ela será marcada como bem-sucedida.
*/
fails?: boolean;
/**
* Hooks que serão executados se a tarefa falhar. A ordem depende da opção `sequence.hooks`.
*/
onFailed?: OnTestFailedHandler[];
/**
* Hooks que serão executados após a tarefa terminar. A ordem depende da opção `sequence.hooks`.
*/
onFinished?: OnTestFinishedHandler[];
/**
* Armazena promessas (de asserções assíncronas) para esperar por elas antes de finalizar o teste
*/
promises?: Promise<any>[];
}
Cada tarefa pode ter um campo result
. Suites só podem ter este campo se um erro lançado dentro de um callback de suite ou callbacks beforeAll
/afterAll
impedir que elas coletem testes. Testes sempre têm este campo após seus callbacks serem chamados - os campos state
e errors
estão presentes dependendo do resultado. Se um erro foi lançado em callbacks beforeEach
ou afterEach
, o erro lançado estará presente em task.result.errors
.
export interface TaskResult {
/**
* Estado da tarefa. Herda o `task.mode` durante a coleta.
* Quando a tarefa terminar, será alterado para `pass` ou `fail`.
* - **pass**: tarefa executada com sucesso
* - **fail**: tarefa falhou
*/
state: TaskState;
/**
* Erros que ocorreram durante a execução da tarefa. É possível ter vários erros
* se `expect.soft()` falhou várias vezes.
*/
errors?: ErrorWithDiff[];
/**
* Quanto tempo em milissegundos a tarefa levou para ser executada.
*/
duration?: number;
/**
* Tempo em milissegundos quando a tarefa começou a ser executada.
*/
startTime?: number;
/**
* Tamanho do heap em bytes após a tarefa terminar.
* Disponível apenas se a opção `logHeapUsage` estiver definida e `process.memoryUsage` estiver definido.
*/
heap?: number;
/**
* Estado dos hooks relacionados a esta tarefa. Útil durante a geração de relatórios.
*/
hooks?: Partial<
Record<'afterAll' | 'beforeAll' | 'beforeEach' | 'afterEach', TaskState>
>;
/**
* A quantidade de vezes que a tarefa foi tentada novamente. A tarefa é tentada novamente apenas se
* falhou e a opção `retry` estiver definida.
*/
retryCount?: number;
/**
* A quantidade de vezes que a tarefa foi repetida. A tarefa é repetida apenas se
* a opção `repeats` estiver definida. Este número também inclui `retryCount`.
*/
repeatCount?: number;
}
Sua Função de Tarefa
O Vitest expõe um tipo de tarefa Custom
que permite aos usuários reutilizar reporters integrados. É virtualmente o mesmo que Test
, mas tem um tipo 'custom'
.
Uma tarefa é um objeto que faz parte de uma suite. Ela é adicionada automaticamente à suite atual com o método suite.task
:
// ./utils/custom.js
import { createTaskCollector, getCurrentSuite, setFn } from 'vitest/suite';
export { afterAll, beforeAll, describe } from 'vitest';
// esta função será chamada durante a fase de coleta:
// não chame o manipulador da função aqui, adicione-o às tarefas da suite
// com o método "getCurrentSuite().task()"
// observação: createTaskCollector fornece suporte para "todo"/"each"/...
export const myCustomTask = createTaskCollector(function (name, fn, timeout) {
getCurrentSuite().task(name, {
...this, // para que "todo"/"skip"/... seja rastreado corretamente
meta: {
customPropertyToDifferentiateTask: true,
},
handler: fn,
timeout,
});
});
// ./garden/tasks.test.js
import { afterAll, beforeAll, describe, myCustomTask } from '../custom.js';
import { gardener } from './gardener.js';
describe('take care of the garden', () => {
beforeAll(() => {
gardener.putWorkingClothes();
});
myCustomTask('weed the grass', () => {
gardener.weedTheGrass();
});
myCustomTask.todo('mow the lawn', () => {
gardener.mowerTheLawn();
});
myCustomTask('water flowers', () => {
gardener.waterFlowers();
});
afterAll(() => {
gardener.goHome();
});
});
vitest ./garden/tasks.test.js
WARNING
Se você não tiver um runner personalizado ou não tiver definido o método runTest
, o Vitest tentará recuperar uma tarefa automaticamente. Se você não adicionou uma função com setFn
, ele falhará.