expect
Os seguintes tipos são usados nas assinaturas de tipo abaixo.
type Awaitable<T> = T | PromiseLike<T>;
expect
é utilizado para criar asserções. Neste contexto, asserções
são funções que podem ser chamadas para validar uma condição. O Vitest oferece asserções chai
por padrão, além de asserções compatíveis com Jest
baseadas em chai
. Diferentemente do Jest
, o Vitest aceita uma mensagem como segundo argumento — se a asserção falhar, a mensagem de erro exibida será a mensagem fornecida.
export interface ExpectStatic
extends Chai.ExpectStatic,
AsymmetricMatchersContaining {
<T>(actual: T, message?: string): Assertion<T>;
extend: (expects: MatchersObject) => void;
anything: () => any;
any: (constructor: unknown) => any;
getState: () => MatcherState;
setState: (state: Partial<MatcherState>) => void;
not: AsymmetricMatchersContaining;
}
Por exemplo, este código afirma que um valor input
é igual a 2
. Se não for, a asserção lançará um erro e o teste falhará.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // API do chai
expect(input).toBe(2); // API do jest
Tecnicamente, este exemplo não utiliza a função test
. Portanto, no console, você verá um erro do Node.js em vez da saída gerada pelo Vitest. Para saber mais sobre test
, leia Referência da API de Teste.
Além disso, expect
pode ser usado estaticamente para acessar funções de matcher (descritas posteriormente) e outras funcionalidades.
WARNING
expect
não afeta a inferência de tipos ou a verificação estática de tipos, se a expressão não apresentar um erro de tipo. Se você quiser usar o Vitest como verificador de tipo, use expectTypeOf
ou assertType
.
soft
- Tipo:
ExpectStatic & (actual: any) => Assertions
expect.soft
funciona de forma semelhante a expect
, mas em vez de encerrar a execução do teste após uma asserção falha, ele continua executando e marca a falha como uma falha de teste. Todos os erros encontrados durante o teste serão exibidos até a conclusão do teste.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // marca o teste como falha e continua
expect.soft(1 + 2).toBe(4); // marca o teste como falha e continua
});
// o reporter irá relatar ambos os erros no final da execução
Também pode ser usado com expect
. Se a asserção expect
falhar, o teste será encerrado e todos os erros serão exibidos.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // marca o teste como falha e continua
expect(1 + 2).toBe(4); // falha e encerra o teste, todos os erros anteriores serão exibidos
expect.soft(1 + 3).toBe(5); // não executa
});
WARNING
expect.soft
só pode ser usado dentro da função test
.
poll
interface ExpectPoll extends ExpectStatic {
(actual: () => T, options: { interval; timeout; message }): Promise<
Assertions<T>
>;
}
expect.poll
reexecuta a asserção até que ela seja bem-sucedida. Você pode configurar quantas vezes o Vitest deve reexecutar o callback expect.poll
definindo as opções interval
e timeout
.
Se um erro for lançado dentro do callback expect.poll
, o Vitest tentará novamente até que o tempo limite expire.
import { expect, test } from 'vitest';
test('element exists', async () => {
asyncInjectElement();
await expect.poll(() => document.querySelector('.element')).toBeTruthy();
});
WARNING
expect.poll
torna toda asserção assíncrona, exigindo que você a aguarde (await
). A partir do Vitest 3, se você esquecer de aguardá-la, o teste falhará com um aviso indicando a necessidade de fazê-lo.
expect.poll
não funciona com vários matchers:
- Matchers de snapshot não são suportados porque sempre terão sucesso. Se sua condição for flaky (instável/intermitente), considere usar
vi.waitFor
para resolvê-la primeiro:
import { expect, vi } from 'vitest';
const flakyValue = await vi.waitFor(() => getFlakyValue());
expect(flakyValue).toMatchSnapshot();
.resolves
e.rejects
não são suportados.expect.poll
já aguarda a condição se ela for assíncrona.toThrow
e seus aliases não são suportados porque a condiçãoexpect.poll
é sempre resolvida antes que o matcher receba o valor
not
Usar not
negará a asserção. Por exemplo, este código afirma que um valor input
não é igual a 2
. Se for igual, a asserção lançará um erro e o teste falhará.
import { expect, test } from 'vitest';
const input = Math.sqrt(16);
expect(input).not.to.equal(2); // API do chai
expect(input).not.toBe(2); // API do jest
toBe
- Tipo:
(value: any) => Awaitable<void>
toBe
pode ser usado para afirmar se primitivos são iguais ou se objetos compartilham a mesma referência. É equivalente a chamar expect(Object.is(3, 3)).toBe(true)
. Se os objetos não forem os mesmos, mas você quiser verificar se suas estruturas são idênticas, você pode usar toEqual
.
Por exemplo, o código abaixo verifica se o comerciante tem 13 maçãs.
import { expect, test } from 'vitest';
const stock = {
type: 'apples',
count: 13,
};
test('stock has 13 apples', () => {
expect(stock.type).toBe('apples');
expect(stock.count).toBe(13);
});
test('stocks are the same', () => {
const refStock = stock; // mesma referência
expect(stock).toBe(refStock);
});
É recomendável evitar o uso de toBe
com números de ponto flutuante. Como o JavaScript os arredonda, 0.1 + 0.2
não é estritamente 0.3
. Para afirmar números de ponto flutuante de forma confiável, use a asserção toBeCloseTo
.
toBeCloseTo
- Tipo:
(value: number, numDigits?: number) => Awaitable<void>
Use toBeCloseTo
para comparar números de ponto flutuante. O argumento opcional numDigits
limita o número de dígitos a serem verificados após o ponto decimal. Por exemplo:
import { expect, test } from 'vitest';
test.fails('decimals are not equal in javascript', () => {
expect(0.2 + 0.1).toBe(0.3); // 0.2 + 0.1 é 0.30000000000000004
});
test('decimals are rounded to 5 after the point', () => {
// 0.2 + 0.1 é 0.30000 | "000000000004" removido
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
// nada de 0.30000000000000004 é removido
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50);
});
toBeDefined
- Tipo:
() => Awaitable<void>
toBeDefined
afirma que o valor não é igual a undefined
. Um uso prático seria verificar se a função retornou algo.
import { expect, test } from 'vitest';
function getApples() {
return 3;
}
test('function returned something', () => {
expect(getApples()).toBeDefined();
});
toBeUndefined
- Tipo:
() => Awaitable<void>
O oposto de toBeDefined
, toBeUndefined
afirma que o valor é igual a undefined
. É útil para verificar se a função não retornou nada.
import { expect, test } from 'vitest';
function getApplesFromStock(stock: string) {
if (stock === 'Bill') {
return 13;
}
}
test("mary doesn't have a stock", () => {
expect(getApplesFromStock('Mary')).toBeUndefined();
});
toBeTruthy
- Tipo:
() => Awaitable<void>
toBeTruthy
afirma que o valor é verdadeiro quando convertido para booleano. Útil quando o valor em si não é relevante, mas sim a sua capacidade de ser convertido para true
.
Por exemplo, com este código, o valor de retorno de stocks.getInfo
pode não ser relevante – ele pode ser um objeto complexo, uma string ou qualquer outra coisa. O código ainda funcionará.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (stocks.getInfo('Bill')) {
stocks.sell('apples', 'Bill');
}
Então, se você quiser testar se stocks.getInfo
resultará em um valor truthy, você pode escrever:
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test('if we know Bill stock, sell apples to him', () => {
stocks.sync('Bill');
expect(stocks.getInfo('Bill')).toBeTruthy();
});
Tudo em JavaScript é truthy, exceto false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
e document.all
.
toBeFalsy
- Tipo:
() => Awaitable<void>
toBeFalsy
afirma que o valor é falso quando convertido para booleano. Útil se você não se importa com o valor, mas apenas quer saber se ele pode ser convertido para false
.
Por exemplo, com este código, o valor de retorno de stocks.stockFailed
pode não ser relevante – ele pode retornar qualquer valor falsy, mas o código ainda funcionará.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (!stocks.stockFailed('Bill')) {
stocks.sell('apples', 'Bill');
}
Então, se você quiser testar se stocks.stockFailed
resultará em um valor falsy, você pode escrever:
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test("if Bill stock hasn't failed, sell apples to him", () => {
stocks.syncStocks('Bill');
expect(stocks.stockFailed('Bill')).toBeFalsy();
});
Tudo em JavaScript é truthy, exceto false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
e document.all
.
toBeNull
- Tipo:
() => Awaitable<void>
toBeNull
simplesmente afirma se algo é null
. Equivalente a .toBe(null)
.
import { expect, test } from 'vitest';
function apples() {
return null;
}
test("we don't have apples", () => {
expect(apples()).toBeNull();
});
toBeNaN
- Tipo:
() => Awaitable<void>
toBeNaN
simplesmente afirma se algo é NaN
. Equivalente a .toBe(NaN)
.
import { expect, test } from 'vitest';
let i = 0;
function getApplesCount() {
i++;
return i > 1 ? Number.NaN : i;
}
test('getApplesCount has some unusual side effects...', () => {
expect(getApplesCount()).not.toBeNaN();
expect(getApplesCount()).toBeNaN();
});
toBeOneOf
- Tipo:
(sample: Array<any>) => any
toBeOneOf
afirma se um valor corresponde a qualquer um dos valores no array fornecido.
import { expect, test } from 'vitest';
test('fruit is one of the allowed values', () => {
expect(fruit).toBeOneOf(['apple', 'banana', 'orange']);
});
O matcher assimétrico é particularmente útil ao testar propriedades opcionais que podem ser null
ou undefined
:
test('optional properties can be null or undefined', () => {
const user = {
firstName: 'John',
middleName: undefined,
lastName: 'Doe',
};
expect(user).toEqual({
firstName: expect.any(String),
middleName: expect.toBeOneOf([expect.any(String), undefined]),
lastName: expect.any(String),
});
});
TIP
Você pode usar expect.not
com este matcher para garantir que um valor NÃO corresponda a nenhuma das opções fornecidas.
toBeTypeOf
- Tipo:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
afirma se um valor real é do tipo do tipo recebido.
import { expect, test } from 'vitest';
const actual = 'stock';
test('stock is type of string', () => {
expect(actual).toBeTypeOf('string');
});
toBeInstanceOf
- Tipo:
(c: any) => Awaitable<void>
toBeInstanceOf
afirma se um valor real é uma instância da classe recebida.
import { expect, test } from 'vitest';
import { Stocks } from './stocks.js';
const stocks = new Stocks();
test('stocks are instance of Stocks', () => {
expect(stocks).toBeInstanceOf(Stocks);
});
toBeGreaterThan
- Tipo:
(n: number | bigint) => Awaitable<void>
toBeGreaterThan
afirma se o valor real é maior que o recebido. Valores iguais farão com que o teste falhe.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have more then 10 apples', () => {
expect(getApples()).toBeGreaterThan(10);
});
toBeGreaterThanOrEqual
- Tipo:
(n: number | bigint) => Awaitable<void>
toBeGreaterThanOrEqual
afirma se o valor real é maior ou igual ao recebido.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have 11 apples or more', () => {
expect(getApples()).toBeGreaterThanOrEqual(11);
});
toBeLessThan
- Tipo:
(n: number | bigint) => Awaitable<void>
toBeLessThan
afirma se o valor real é menor que o recebido. Valores iguais farão com que o teste falhe.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have less then 20 apples', () => {
expect(getApples()).toBeLessThan(20);
});
toBeLessThanOrEqual
- Tipo:
(n: number | bigint) => Awaitable<void>
toBeLessThanOrEqual
afirma se o valor real é menor ou igual ao recebido.
import { expect, test } from 'vitest';
import { getApples } from './stocks.js';
test('have 11 apples or less', () => {
expect(getApples()).toBeLessThanOrEqual(11);
});
toEqual
- Tipo:
(received: any) => Awaitable<void>
toEqual
afirma se o valor real é igual ao recebido ou tem a mesma estrutura, se for um objeto (compara-os recursivamente). A diferença entre toEqual
e toBe
pode ser observada neste exemplo:
import { expect, test } from 'vitest';
const stockBill = {
type: 'apples',
count: 13,
};
const stockMary = {
type: 'apples',
count: 13,
};
test('stocks have the same properties', () => {
expect(stockBill).toEqual(stockMary);
});
test('stocks are not the same', () => {
expect(stockBill).not.toBe(stockMary);
});
WARNING
Para objetos Error
, propriedades não enumeráveis como name
, message
, cause
e AggregateError.errors
também são comparadas. Para Error.cause
, a comparação é feita assimetricamente:
// sucesso
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi'));
// falha
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' }));
Para testar se algo foi lançado, use a asserção toThrowError
.
toStrictEqual
- Tipo:
(received: any) => Awaitable<void>
toStrictEqual
afirma se o valor real é igual ao recebido ou tem a mesma estrutura se for um objeto (compara-os recursivamente), e do mesmo tipo.
Diferenças de .toEqual
:
- Chaves com propriedades
undefined
são verificadas. Por exemplo,{a: undefined, b: 2}
não corresponde a{b: 2}
ao usar.toStrictEqual
. - A esparsidade do array é verificada. Por exemplo,
[, 1]
não corresponde a[undefined, 1]
ao usar.toStrictEqual
. - Os tipos de objeto são verificados para serem iguais. Por exemplo, uma instância de classe com campos
a
eb
não será igual a um objeto literal com camposa
eb
.
import { expect, test } from 'vitest';
class Stock {
constructor(type) {
this.type = type;
}
}
test('structurally the same, but semantically different', () => {
expect(new Stock('apples')).toEqual({ type: 'apples' });
expect(new Stock('apples')).not.toStrictEqual({ type: 'apples' });
});
toContain
- Tipo:
(received: string) => Awaitable<void>
toContain
afirma se o valor real está em um array. toContain
também pode verificar se uma string é uma substring de outra string. Se você estiver executando testes em um ambiente semelhante a um navegador, esta asserção também pode verificar se uma classe está presente em uma classList
, ou se um elemento está contido em outro.
import { expect, test } from 'vitest';
import { getAllFruits } from './stocks.js';
test('the fruit list contains orange', () => {
expect(getAllFruits()).toContain('orange');
const element = document.querySelector('#el');
// o elemento tem uma classe
expect(element.classList).toContain('flex');
// o elemento está dentro de outro
expect(document.querySelector('#wrapper')).toContain(element);
});
toContainEqual
- Tipo:
(received: any) => Awaitable<void>
toContainEqual
afirma se um item com uma estrutura e valores específicos está contido em um array. Funciona como toEqual
internamente para cada elemento.
import { expect, test } from 'vitest';
import { getFruitStock } from './stocks.js';
test('apple available', () => {
expect(getFruitStock()).toContainEqual({ fruit: 'apple', count: 5 });
});
toHaveLength
- Tipo:
(received: number) => Awaitable<void>
toHaveLength
afirma se um objeto tem uma propriedade .length
e se ela está definida para um determinado valor numérico.
import { expect, test } from 'vitest';
test('toHaveLength', () => {
expect('abc').toHaveLength(3);
expect([1, 2, 3]).toHaveLength(3);
expect('').not.toHaveLength(3); // não tem .length de 3
expect({ length: 3 }).toHaveLength(3);
});
toHaveProperty
- Tipo:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
afirma se uma propriedade na key
de referência fornecida existe para um objeto.
Você pode fornecer um argumento de valor opcional para comparar o valor da propriedade recebida, utilizando uma verificação de igualdade profunda, similar ao matcher toEqual
.
import { expect, test } from 'vitest';
const invoice = {
isActive: true,
'P.O': '12345',
customer: {
first_name: 'John',
last_name: 'Doe',
location: 'China',
},
total_amount: 5000,
items: [
{
type: 'apples',
quantity: 10,
},
{
type: 'oranges',
quantity: 5,
},
],
};
test('John Doe Invoice', () => {
expect(invoice).toHaveProperty('isActive'); // afirma que a chave existe
expect(invoice).toHaveProperty('total_amount', 5000); // afirma que a chave existe e o valor é igual
expect(invoice).not.toHaveProperty('account'); // afirma que esta chave não existe
// Referência profunda usando notação de ponto
expect(invoice).toHaveProperty('customer.first_name');
expect(invoice).toHaveProperty('customer.last_name', 'Doe');
expect(invoice).not.toHaveProperty('customer.location', 'India');
// Referência profunda usando um array contendo a chave
expect(invoice).toHaveProperty('items[0].type', 'apples');
expect(invoice).toHaveProperty('items.0.type', 'apples'); // notação de ponto também funciona
// Referência profunda usando um array contendo o keyPath
expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples');
expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // notação de string também funciona
// Envolva sua chave em um array para evitar que a chave seja analisada como uma referência profunda
expect(invoice).toHaveProperty(['P.O'], '12345');
});
toMatch
- Tipo:
(received: string | regexp) => Awaitable<void>
toMatch
afirma se uma string corresponde a uma expressão regular ou a uma string.
import { expect, test } from 'vitest';
test('top fruits', () => {
expect('top fruits include apple, orange and grape').toMatch(/apple/);
expect('applefruits').toMatch('fruit'); // toMatch também aceita uma string
});
toMatchObject
- Tipo:
(received: object | array) => Awaitable<void>
toMatchObject
afirma se um objeto corresponde a um subconjunto das propriedades de um objeto.
Você também pode passar um array de objetos. Isso é útil se você quiser verificar se dois arrays correspondem em seu número de elementos, em oposição a arrayContaining
, que permite elementos extras no array recebido.
import { expect, test } from 'vitest';
const johnInvoice = {
isActive: true,
customer: {
first_name: 'John',
last_name: 'Doe',
location: 'China',
},
total_amount: 5000,
items: [
{
type: 'apples',
quantity: 10,
},
{
type: 'oranges',
quantity: 5,
},
],
};
const johnDetails = {
customer: {
first_name: 'John',
last_name: 'Doe',
location: 'China',
},
};
test('invoice has john personal details', () => {
expect(johnInvoice).toMatchObject(johnDetails);
});
test('the number of elements must match exactly', () => {
// Afirma que um array de objetos corresponde
expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
{ foo: 'bar' },
{ baz: 1 },
]);
});
toThrowError
Tipo:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
afirma se uma função lança um erro quando é chamada.
Você pode fornecer um argumento opcional para testar se um erro específico é lançado:
RegExp
: a mensagem de erro corresponde ao padrãostring
: a mensagem de erro inclui a substringError
,AsymmetricMatcher
: compara com um objeto recebido semelhante atoEqual(received)
TIP
Você deve envolver o código em uma função, caso contrário o erro não será capturado e o teste falhará.
Isso não se aplica a chamadas assíncronas, pois rejects lida adequadamente com a promessa:
test('expect rejects toThrow', async ({ expect }) => {
const promise = Promise.reject(new Error('Test'));
await expect(promise).rejects.toThrowError();
});
Por exemplo, se quisermos testar se getFruitStock('pineapples')
lança um erro, poderíamos escrever:
import { expect, test } from 'vitest';
function getFruitStock(type: string) {
if (type === 'pineapples') {
throw new Error('Pineapples are not in stock');
}
// Faz outras coisas
}
test('throws on pineapples', () => {
// Testa se a mensagem de erro diz "stock" em algum lugar: estes são equivalentes
expect(() => getFruitStock('pineapples')).toThrowError(/stock/);
expect(() => getFruitStock('pineapples')).toThrowError('stock');
// Testa a mensagem de erro exata
expect(() => getFruitStock('pineapples')).toThrowError(
/^Pineapples are not in stock$/
);
expect(() => getFruitStock('pineapples')).toThrowError(
new Error('Pineapples are not in stock')
);
expect(() => getFruitStock('pineapples')).toThrowError(
expect.objectContaining({
message: 'Pineapples are not in stock',
})
);
});
TIP
Para testar funções assíncronas, use em combinação com rejects.
function getAsyncFruitStock() {
return Promise.reject(new Error('empty'));
}
test('throws on pineapples', async () => {
await expect(() => getAsyncFruitStock()).rejects.toThrowError('empty');
});
toMatchSnapshot
- Tipo:
<T>(shape?: Partial<T> | string, hint?: string) => void
Isso garante que um valor corresponda ao snapshot mais recente.
Você pode fornecer um argumento de string opcional chamado hint
, que será anexado ao nome do teste. Embora o Vitest sempre anexe um número ao final de um nome de snapshot, dicas descritivas curtas podem ser mais úteis do que números para diferenciar vários snapshots em um único bloco it
ou test
. O Vitest classifica os snapshots por nome no arquivo .snap
correspondente.
TIP
Quando um snapshot não corresponde e faz com que o teste falhe, se a incompatibilidade for esperada, você pode pressionar a tecla u
para atualizar o snapshot uma vez. Ou você pode passar as opções de CLI -u
ou --update
para fazer com que o Vitest sempre atualize os testes.
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot();
});
Você também pode fornecer uma forma de um objeto, se estiver testando apenas a forma de um objeto e não precisar que ele seja 100% compatível:
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot({ foo: expect.any(Set) });
});
toMatchInlineSnapshot
- Tipo:
<T>(shape?: Partial<T> | string, snapshot?: string, hint?: string) => void
Isso garante que um valor corresponda ao snapshot mais recente.
O Vitest adiciona e atualiza o argumento de string inlineSnapshot
ao matcher no arquivo de teste (em vez de um arquivo .snap
externo).
import { expect, test } from 'vitest';
test('matches inline snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
// O Vitest atualizará o seguinte conteúdo ao atualizar o snapshot
expect(data).toMatchInlineSnapshot(`
{
"foo": Set {
"bar",
"snapshot",
},
}
`);
});
Você também pode fornecer uma forma de um objeto, se estiver testando apenas a forma de um objeto e não precisar que ele seja 100% compatível:
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchInlineSnapshot(
{ foo: expect.any(Set) },
`
{
"foo": Any<Set>,
}
`
);
});
toMatchFileSnapshot
- Tipo:
<T>(filepath: string, hint?: string) => Promise<void>
Compara ou atualiza o snapshot com o conteúdo de um arquivo explicitamente especificado (em vez do arquivo .snap
).
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Observe que, como a operação do sistema de arquivos é assíncrona, você precisa usar await
com toMatchFileSnapshot()
. Se await
não for usado, o Vitest o trata como expect.soft
, o que significa que o código após a instrução continuará a ser executado mesmo que o snapshot não corresponda. Após o término do teste, o Vitest verificará o snapshot e falhará se houver uma incompatibilidade.
toThrowErrorMatchingSnapshot
- Tipo:
(hint?: string) => void
O mesmo que toMatchSnapshot
, mas espera o mesmo valor que toThrowError
.
toThrowErrorMatchingInlineSnapshot
- Tipo:
(snapshot?: string, hint?: string) => void
O mesmo que toMatchInlineSnapshot
, mas espera o mesmo valor que toThrowError
.
toHaveBeenCalled
- Tipo:
() => Awaitable<void>
Esta asserção é útil para testar se uma função foi chamada. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('função espiã', () => {
const buySpy = vi.spyOn(market, 'buy');
expect(buySpy).not.toHaveBeenCalled();
market.buy('apples', 10);
expect(buySpy).toHaveBeenCalled();
});
toHaveBeenCalledTimes
- Tipo:
(amount: number) => Awaitable<void>
Esta asserção verifica se uma função foi chamada um número específico de vezes. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('função espiã chamada duas vezes', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledTimes(2);
});
toHaveBeenCalledWith
- Tipo:
(...args: any[]) => Awaitable<void>
Esta asserção verifica se uma função foi chamada pelo menos uma vez com certos parâmetros. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('função espiã', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledWith('apples', 10);
expect(buySpy).toHaveBeenCalledWith('apples', 20);
});
toHaveBeenCalledBefore 3.0.0+
- Tipo:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
Esta asserção verifica se um Mock
foi chamado antes de outro Mock
.
test('calls mock1 before mock2', () => {
const mock1 = vi.fn();
const mock2 = vi.fn();
mock1();
mock2();
mock1();
expect(mock1).toHaveBeenCalledBefore(mock2);
});
toHaveBeenCalledAfter 3.0.0+
- Tipo:
(mock: MockInstance, failIfNoFirstInvocation?: boolean) => Awaitable<void>
Esta asserção verifica se um Mock
foi chamado depois de outro Mock
.
test('calls mock1 after mock2', () => {
const mock1 = vi.fn();
const mock2 = vi.fn();
mock2();
mock1();
mock2();
expect(mock1).toHaveBeenCalledAfter(mock2);
});
toHaveBeenCalledExactlyOnceWith 3.0.0+
- Tipo:
(...args: any[]) => Awaitable<void>
Esta asserção verifica se uma função foi chamada exatamente uma vez e com certos parâmetros. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('função espiã', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
expect(buySpy).toHaveBeenCalledExactlyOnceWith('apples', 10);
});
toHaveBeenLastCalledWith
- Tipo:
(...args: any[]) => Awaitable<void>
Esta asserção verifica se uma função foi chamada com certos parâmetros em sua última invocação. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('função espiã', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).not.toHaveBeenLastCalledWith('apples', 10);
expect(buySpy).toHaveBeenLastCalledWith('apples', 20);
});
toHaveBeenNthCalledWith
- Tipo:
(time: number, ...args: any[]) => Awaitable<void>
Esta asserção verifica se uma função foi chamada com certos parâmetros em um determinado momento. A contagem começa em 1. Então, para verificar a segunda entrada, você escreveria .toHaveBeenNthCalledWith(2, ...)
.
Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('primeira chamada da função espiã chamada com os parâmetros corretos', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenNthCalledWith(1, 'apples', 10);
});
toHaveReturned
- Tipo:
() => Awaitable<void>
Esta asserção verifica se uma função retornou um valor com sucesso pelo menos uma vez (ou seja, não lançou um erro). Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
function getApplesPrice(amount: number) {
const PRICE = 10;
return amount * PRICE;
}
test('função espiã retornou um valor', () => {
const getPriceSpy = vi.fn(getApplesPrice);
const price = getPriceSpy(10);
expect(price).toBe(100);
expect(getPriceSpy).toHaveReturned();
});
toHaveReturnedTimes
- Tipo:
(amount: number) => Awaitable<void>
Esta asserção verifica se uma função retornou um valor com sucesso um número exato de vezes (ou seja, não lançou um erro). Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('função espiã retorna um valor duas vezes', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveReturnedTimes(2);
});
toHaveReturnedWith
- Tipo:
(returnValue: any) => Awaitable<void>
Você pode chamar esta asserção para verificar se uma função retornou um valor com sucesso com certos parâmetros pelo menos uma vez. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('função espiã retorna um produto', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});
toHaveLastReturnedWith
- Tipo:
(returnValue: any) => Awaitable<void>
Você pode chamar esta asserção para verificar se uma função retornou um determinado valor com sucesso quando foi invocada pela última vez. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('função espiã retorna bananas na última chamada', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});
toHaveNthReturnedWith
- Tipo:
(time: number, returnValue: any) => Awaitable<void>
Você pode chamar esta asserção para verificar se uma função retornou um valor com sucesso com certos parâmetros em uma determinada chamada. Requer que uma função espiã seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('função espiã retorna bananas na segunda chamada', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' });
});
toHaveResolved
- Tipo:
() => Awaitable<void>
Esta asserção verifica se uma função resolveu um valor com sucesso pelo menos uma vez (ou seja, não rejeitou). Requer que uma função espiã seja passada para expect
.
Se a função retornar uma promessa que ainda não foi resolvida, a asserção falhará.
import { expect, test, vi } from 'vitest';
import db from './db/apples.js';
async function getApplesPrice(amount: number) {
return amount * (await db.get('price'));
}
test('função espiã resolveu um valor', async () => {
const getPriceSpy = vi.fn(getApplesPrice);
const price = await getPriceSpy(10);
expect(price).toBe(100);
expect(getPriceSpy).toHaveResolved();
});
toHaveResolvedTimes
- Tipo:
(amount: number) => Awaitable<void>
Esta asserção verifica se uma função resolveu um valor com sucesso um número exato de vezes (ou seja, não rejeitou). Requer que uma função espiã seja passada para expect
.
Isso contará apenas promessas resolvidas. Se a função retornar uma promessa que ainda não foi resolvida, ela não será contabilizada.
import { expect, test, vi } from 'vitest';
test('função espiã resolveu um valor duas vezes', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
await sell('bananas');
expect(sell).toHaveResolvedTimes(2);
});
toHaveResolvedWith
- Tipo:
(returnValue: any) => Awaitable<void>
Você pode chamar esta asserção para verificar se uma função resolveu um determinado valor com sucesso pelo menos uma vez. Requer que uma função espiã seja passada para expect
.
Se a função retornar uma promessa que ainda não foi resolvida, a asserção falhará.
import { expect, test, vi } from 'vitest';
test('função espiã resolveu um produto', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
expect(sell).toHaveResolvedWith({ product: 'apples' });
});
toHaveLastResolvedWith
- Tipo:
(returnValue: any) => Awaitable<void>
Você pode chamar esta asserção para verificar se uma função resolveu um determinado valor com sucesso quando foi invocada pela última vez. Requer que uma função espiã seja passada para expect
.
Se a função retornar uma promessa que ainda não foi resolvida, a asserção falhará.
import { expect, test, vi } from 'vitest';
test('função espiã resolve bananas na última chamada', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
await sell('bananas');
expect(sell).toHaveLastResolvedWith({ product: 'bananas' });
});
toHaveNthResolvedWith
- Tipo:
(time: number, returnValue: any) => Awaitable<void>
Você pode chamar esta asserção para verificar se uma função resolveu um determinado valor com sucesso em uma invocação específica. Requer que uma função espiã seja passada para expect
.
Se a função retornar uma promessa que ainda não foi resolvida, a asserção falhará.
import { expect, test, vi } from 'vitest';
test('função espiã retorna bananas na segunda chamada', async () => {
const sell = vi.fn((product: string) => Promise.resolve({ product }));
await sell('apples');
await sell('bananas');
expect(sell).toHaveNthResolvedWith(2, { product: 'bananas' });
});
toSatisfy
- Tipo:
(predicate: (value: any) => boolean) => Awaitable<void>
Esta asserção verifica se um valor satisfaz um determinado predicado.
import { describe, expect, it } from 'vitest';
const isOdd = (value: number) => value % 2 !== 0;
describe('toSatisfy()', () => {
it('pass with 0', () => {
expect(1).toSatisfy(isOdd);
});
it('pass with negation', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
- Tipo:
Promisify<Assertions>
resolves
destina-se a remover o código repetitivo ao afirmar código assíncrono. Use-o para desembrulhar o valor da promessa pendente e afirmar seu valor com asserções usuais. Se a promessa for rejeitada, a asserção falhará.
Ele retorna o mesmo objeto Assertions
, mas todos os matchers agora retornam Promise
, então você precisaria await
á-lo. Também funciona com asserções chai
.
Por exemplo, se você tem uma função que faz uma chamada de API e retorna alguns dados, você pode usar este código para afirmar seu valor de retorno:
import { expect, test } from 'vitest';
async function buyApples() {
return fetch('/buy/apples').then(r => r.json());
}
test('buyApples returns new stock id', async () => {
// toEqual retorna uma promessa agora, então você TEM que aguardá-la
await expect(buyApples()).resolves.toEqual({ id: 1 }); // API do jest
await expect(buyApples()).resolves.to.equal({ id: 1 }); // API do chai
});
WARNING
Se a asserção não for aguardada, você terá um teste falso-positivo que sempre passará. Para garantir que as asserções sejam realmente chamadas, você pode usar expect.assertions(number)
.
Desde o Vitest 3, se um método não for aguardado, o Vitest mostrará um aviso no final do teste. No Vitest 4, o teste será marcado como "falhou" se a asserção não for aguardada.
rejects
- Tipo:
Promisify<Assertions>
rejects
destina-se a remover o código repetitivo ao afirmar código assíncrono. Use-o para desembrulhar o motivo pelo qual a promessa foi rejeitada e afirmar seu valor com asserções usuais. Se a promessa for resolvida com sucesso, a asserção falhará.
Ele retorna o mesmo objeto Assertions
, mas todos os matchers agora retornam Promise
, então você precisaria await
á-lo. Também funciona com asserções chai
.
Por exemplo, se você tem uma função que falha quando você a chama, você pode usar este código para afirmar o motivo:
import { expect, test } from 'vitest';
async function buyApples(id) {
if (!id) {
throw new Error('no id');
}
}
test('buyApples throws an error when no id provided', async () => {
// toThrow retorna uma promessa agora, então você TEM que aguardá-la
await expect(buyApples()).rejects.toThrow('no id');
});
WARNING
Se a asserção não for aguardada, você terá um teste falso-positivo que sempre passará. Para garantir que as asserções foram realmente chamadas, você pode usar expect.assertions(number)
.
Desde o Vitest 3, se um método não for aguardado, o Vitest mostrará um aviso no final do teste. No Vitest 4, o teste será marcado como "falhou" se a asserção não for aguardada.
expect.assertions
- Tipo:
(count: number) => void
Depois que o teste for aprovado ou reprovado, verifique se um certo número de asserções foi chamado durante um teste. É útil para verificar se um código assíncrono foi chamado.
Por exemplo, se temos uma função que chama assincronamente dois matchers, podemos afirmar que eles foram realmente chamados.
import { expect, test } from 'vitest';
async function doAsync(...cbs) {
await Promise.all(cbs.map((cb, index) => cb({ index })));
}
test('all assertions are called', async () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
await doAsync(callback1, callback2);
});
WARNING
Ao usar assertions
com testes assíncronos concorrentes, o expect
do Contexto de Teste local deve ser usado para garantir que a asserção seja associada ao teste correto.
expect.hasAssertions
- Tipo:
() => void
Depois que o teste for aprovado ou reprovado, verifique se pelo menos uma asserção foi chamada durante um teste. É útil para verificar se um código assíncrono foi chamado.
Por exemplo, se você tem um código que chama um callback, podemos fazer uma asserção dentro de um callback, mas o teste sempre passará se não verificarmos se uma asserção foi chamada.
import { expect, test } from 'vitest';
import { db } from './db.js';
const cbs = [];
function onSelect(cb) {
cbs.push(cb);
}
// depois de selecionar do db, chamamos todos os callbacks
function select(id) {
return db.select({ id }).then(data => {
return Promise.all(cbs.map(cb => cb(data)));
});
}
test('callback was called', async () => {
expect.hasAssertions();
onSelect(data => {
// deve ser chamado na seleção
expect(data).toBeTruthy();
});
// se não for aguardado, o teste falhará
// se você não tiver expect.hasAssertions(), o teste passará
await select(3);
});
expect.unreachable
- Tipo:
(message?: string) => never
Este método é usado para afirmar que uma linha nunca deve ser alcançada.
Por exemplo, se quisermos testar se build()
lança um erro devido a diretórios de recebimento sem uma pasta src
, e também lidar com cada erro separadamente, poderíamos fazer isso:
import { expect, test } from 'vitest';
async function build(dir) {
if (dir.includes('no-src')) {
throw new Error(`${dir}/src does not exist`);
}
}
const errorDirs = [
'no-src-folder',
// ...
];
test.each(errorDirs)('build fails with "%s"', async dir => {
try {
await build(dir);
expect.unreachable('Should not pass build');
} catch (err: any) {
expect(err).toBeInstanceOf(Error);
expect(err.stack).toContain('build');
switch (dir) {
case 'no-src-folder':
expect(err.message).toBe(`${dir}/src does not exist`);
break;
default:
// para esgotar todos os testes de erro
expect.unreachable('All error test must be handled');
break;
}
}
});
expect.anything
- Tipo:
() => any
Este matcher assimétrico, quando usado em uma comparação de igualdade, sempre retornará true
. Útil, se você quiser apenas ter certeza de que a propriedade existe.
import { expect, test } from 'vitest';
test('object has "apples" key', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});
expect.any
- Tipo:
(constructor: unknown) => any
Este matcher assimétrico, quando usado em uma comparação de igualdade, retornará true
apenas se o valor for uma instância de um construtor especificado. É útil quando você tem um valor gerado dinamicamente e quer apenas verificar se ele existe e possui o tipo correto.
import { expect, test } from 'vitest';
import { generateId } from './generators.js';
test('"id" is a number', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) });
});
expect.closeTo
- Tipo:
(expected: any, precision?: number) => any
expect.closeTo
é útil ao comparar números de ponto flutuante em propriedades de objeto ou item de array. Se você precisar comparar um número, use .toBeCloseTo
em vez disso.
O argumento opcional precision
limita o número de dígitos a serem verificados após o ponto decimal. Para o valor padrão 2
, o critério de teste é Math.abs(expected - received) < 0.005 (ou seja, 10 ** -2 / 2)
.
Por exemplo, este teste passa com uma precisão de 5 dígitos:
test('compare float in object properties', () => {
expect({
title: '0.1 + 0.2',
sum: 0.1 + 0.2,
}).toEqual({
title: '0.1 + 0.2',
sum: expect.closeTo(0.3, 5),
});
});
expect.arrayContaining
- Tipo:
<T>(expected: T[]) => any
Quando usado em uma comparação de igualdade, este matcher assimétrico retornará true
se o valor for um array e contiver os itens especificados.
import { expect, test } from 'vitest';
test('basket includes fuji', () => {
const basket = {
varieties: ['Empire', 'Fuji', 'Gala'],
count: 3,
};
expect(basket).toEqual({
count: 3,
varieties: expect.arrayContaining(['Fuji']),
});
});
TIP
Você pode usar expect.not
com este matcher para negar o valor esperado.
expect.objectContaining
- Tipo:
(expected: any) => any
Quando usado em uma comparação de igualdade, este matcher assimétrico retornará true
se o valor tiver uma estrutura semelhante.
import { expect, test } from 'vitest';
test('basket has empire apples', () => {
const basket = {
varieties: [
{
name: 'Empire',
count: 1,
},
],
};
expect(basket).toEqual({
varieties: [expect.objectContaining({ name: 'Empire' })],
});
});
TIP
Você pode usar expect.not
com este matcher para negar o valor esperado.
expect.stringContaining
- Tipo:
(expected: any) => any
Quando usado em uma comparação de igualdade, este matcher assimétrico retornará true
se o valor for uma string e contiver a substring especificada.
import { expect, test } from 'vitest';
test('variety has "Emp" in its name', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringContaining('Emp'),
count: 1,
});
});
TIP
Você pode usar expect.not
com este matcher para negar o valor esperado.
expect.stringMatching
- Tipo:
(expected: any) => any
Quando usado em uma comparação de igualdade, este matcher assimétrico retornará true
se o valor for uma string e contiver a substring especificada ou se a string corresponder a uma expressão regular.
import { expect, test } from 'vitest';
test('variety ends with "re"', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringMatching(/re$/),
count: 1,
});
});
TIP
Você pode usar expect.not
com este matcher para negar o valor esperado.
expect.addSnapshotSerializer
- Tipo:
(plugin: PrettyFormatPlugin) => void
Este método adiciona serializadores personalizados que são chamados ao criar um snapshot. Este é um recurso avançado. Para saber mais, consulte o guia sobre serializadores personalizados.
Se você estiver adicionando serializadores personalizados, recomenda-se chamar este método dentro de setupFiles
. Isso afetará todos os snapshots.
TIP
Se você usou anteriormente o Vue CLI com Jest, talvez queira instalar jest-serializer-vue. Caso contrário, seus snapshots serão envolvidos em uma string, resultando na necessidade de escapar "
.
expect.extend
- Tipo:
(matchers: MatchersObject) => void
Você pode estender os matchers padrão com os seus próprios. Esta função é usada para estender o objeto matchers com matchers personalizados.
Ao definir matchers dessa maneira, você também cria matchers assimétricos que podem ser usados como expect.stringContaining
.
import { expect, test } from 'vitest';
test('custom matchers', () => {
expect.extend({
toBeFoo: (received, expected) => {
if (received !== 'foo') {
return {
message: () => `expected ${received} to be foo`,
pass: false,
};
}
},
});
expect('foo').toBeFoo();
expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() });
});
TIP
Se você quiser que seus matchers estejam disponíveis em todos os testes, recomenda-se chamar este método dentro de setupFiles
.
Esta função é compatível com expect.extend
do Jest, portanto, qualquer biblioteca que a utilize para criar matchers personalizados funcionará com o Vitest.
Se você estiver usando TypeScript, desde o Vitest 0.31.0 você pode estender a interface Assertion
padrão em um arquivo de declaração de ambiente (por exemplo: vitest.d.ts
) com o código abaixo:
interface CustomMatchers<R = unknown> {
toBeFoo: () => R;
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
WARNING
Certifique-se de incluir o arquivo de declaração de ambiente em seu tsconfig.json
.
TIP
Para saber mais, consulte o guia sobre como estender matchers.
expect.addEqualityTesters
- Tipo:
(tester: Array<Tester>) => void
Você pode usar este método para definir testadores personalizados, que são funções auxiliares utilizadas pelos matchers para verificar a igualdade entre dois objetos. É compatível com expect.addEqualityTesters
do Jest.
import { expect, test } from 'vitest';
class AnagramComparator {
public word: string;
constructor(word: string) {
this.word = word;
}
equals(other: AnagramComparator): boolean {
const cleanStr1 = this.word.replace(/ /g, '').toLowerCase();
const cleanStr2 = other.word.replace(/ /g, '').toLowerCase();
const sortedStr1 = cleanStr1.split('').sort().join('');
const sortedStr2 = cleanStr2.split('').sort().join('');
return sortedStr1 === sortedStr2;
}
}
function isAnagramComparator(a: unknown): a is AnagramComparator {
return a instanceof AnagramComparator;
}
function areAnagramsEqual(a: unknown, b: unknown): boolean | undefined {
const isAAnagramComparator = isAnagramComparator(a);
const isBAnagramComparator = isAnagramComparator(b);
if (isAAnagramComparator && isBAnagramComparator) {
return a.equals(b);
} else if (isAAnagramComparator === isBAnagramComparator) {
return undefined;
} else {
return false;
}
}
expect.addEqualityTesters([areAnagramsEqual]);
test('custom equality tester', () => {
expect(new AnagramComparator('listen')).toEqual(
new AnagramComparator('silent')
);
});