expect
Os seguintes tipos são usados nas assinaturas de tipo abaixo:
type Awaitable<T> = T | PromiseLike<T>;
expect
é usado para criar asserções. Neste contexto, asserções
são funções que podem ser chamadas para garantir uma condição. O Vitest fornece asserções chai
por padrão e também asserções compatíveis com Jest
construídas sobre o chai
.
Por exemplo, este código garante 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 chai
expect(input).toBe(2); // API jest
Tecnicamente, esse exemplo não usa a função test
, então você verá o erro do Node.js no console em vez da saída do Vitest. Para saber mais sobre test
, consulte a Referência da API de Teste.
Além disso, expect
pode ser usado estaticamente para acessar os matchers (descritos posteriormente) e muito mais.
WARNING
expect
não tem efeito na tipagem dos testes, a menos que a expressão tenha 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 interromper a execução do teste após uma asserção falhar, ele continua executando e marca o teste como falho. Todos os erros encontrados durante o teste serão exibidos ao final da execução.
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
});
// Ao final do teste, os erros acima serão exibidos.
Ele também pode ser usado em conjunto com expect
. Se a asserção expect
falhar, o teste será interrompido 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 interrompe 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
.
not
Usar not
irá negar a asserção. Por exemplo, este código garante 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 chai
expect(input).not.toBe(2); // API jest
toBe
- Tipo:
(value: any) => Awaitable<void>
toBe
pode ser usado para verificar se primitivos são iguais ou se objetos compartilham a mesma referência. É o mesmo que 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);
});
Evite usar toBe
com números de ponto flutuante. Como o JavaScript os arredonda, 0.1 + 0.2
não é estritamente 0.3
. Para garantir a comparação de 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 para verificar 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
garante que o valor não é igual a undefined
. Um caso de uso útil é verificar se a função retornou algum valor.
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
garante que o valor é igual a undefined
. Um caso de uso útil é 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
garante que o valor é verdadeiro quando convertido para booleano. Útil se você não se importa com o valor retornado, mas apenas quer saber se ele pode ser convertido para true
.
Por exemplo, com este código, você não se importa com o valor de retorno de stocks.getInfo
- 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
será 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
garante que o valor é falso quando convertido para booleano. Útil se você não se importa com o valor retornado, mas apenas quer saber se ele pode ser convertido para false
.
Por exemplo, com este código, você não se importa com o valor de retorno de stocks.stockFailed
- 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
será 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 garante se algo é null
. Alias para .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 garante se algo é NaN
. Alias para .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();
});
toBeTypeOf
- Tipo:
(c: 'bigint' | 'boolean' | 'function' | 'number' | 'object' | 'string' | 'symbol' | 'undefined') => Awaitable<void>
toBeTypeOf
verifica se um valor é do tipo especificado.
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
verifica se um valor é uma instância da classe especificada.
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
verifica se o valor é maior que o valor esperado. Valores iguais farão o teste falhar.
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
garante se o valor real é maior ou igual ao valor 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
garante se o valor real é menor que o valor recebido. Valores iguais farão o teste falhar.
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
garante se o valor real é menor ou igual ao valor 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
verifica se o valor é igual ao valor esperado ou se tem a mesma estrutura (comparando-os recursivamente, se forem objetos). Você pode ver a diferença entre toEqual
e toBe
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
Uma igualdade profunda não será realizada para objetos Error
. Apenas a propriedade message
de um Error é considerada para igualdade. Para customizar a igualdade e verificar propriedades além de message
, use expect.addEqualityTesters
. Para testar se algo foi lançado, use a asserção toThrowError
.
toStrictEqual
- Tipo:
(received: any) => Awaitable<void>
toStrictEqual
verifica se o valor é igual ao valor esperado, tem a mesma estrutura (comparando-os recursivamente, se forem objetos) e é do mesmo tipo.
Diferenças de .toEqual
:
- As chaves com propriedades
undefined
são verificadas. ex.{a: undefined, b: 2}
não corresponde a{b: 2}
ao usar.toStrictEqual
. - A dispersão do array é verificada. ex.
[, 1]
não corresponde a[undefined, 1]
ao usar.toStrictEqual
. - Os tipos de objeto são verificados para serem iguais. ex. 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 atual está em um array. toContain
também pode verificar se uma string é uma substring de outra string. Desde o Vitest 1.0, se você estiver executando testes em um ambiente semelhante ao navegador, esta asserção também pode verificar se a classe está contida em um classList
ou se um elemento está dentro de 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');
// element has a class
expect(element.classList).toContain('flex');
// element is inside another one
expect(document.querySelector('#wrapper')).toContain(element);
});
toContainEqual
- Tipo:
(received: any) => Awaitable<void>
toContainEqual
verifica se um item com a estrutura e os valores especificados está presente em um array. Funciona como toEqual
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
garante se um objeto tem uma propriedade .length
e ela está definida como 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
verifica se um objeto possui uma propriedade com a chave key
especificada.
Você pode fornecer um argumento de valor opcional, usando igualdade profunda (deep equality), similar ao matcher toEqual
, para comparar o valor da propriedade.
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 propriedade existe
expect(invoice).toHaveProperty('total_amount', 5000); // Afirma que a propriedade existe e o valor é igual
expect(invoice).not.toHaveProperty('account'); // Afirma que esta propriedade não existe
// Acesso profundo usando notação de ponto
expect(invoice).toHaveProperty('customer.first_name'); // Afirma que a propriedade 'customer.first_name' existe
expect(invoice).toHaveProperty('customer.last_name', 'Doe');
expect(invoice).not.toHaveProperty('customer.location', 'India');
// Acesso profundo usando um array contendo a chave
expect(invoice).toHaveProperty('items[0].type', 'apples');
expect(invoice).toHaveProperty('items.0.type', 'apples'); // A notação de ponto também funciona
// Acesso profundo usando um array contendo o caminho da chave
expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples');
expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // A notação de string também funciona
// Use um array para envolver sua chave para evitar que ela seja interpretada como um caminho de acesso profundo
expect(invoice).toHaveProperty(['P.O'], '12345');
});
toMatch
- Tipo:
(received: string | regexp) => Awaitable<void>
toMatch
verifica se uma string corresponde a uma expressão regular ou a outra 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
verifica se um objeto corresponde a um subconjunto das propriedades de outro objeto.
É útil para verificar se dois arrays têm o mesmo número de elementos e se os elementos correspondem, diferentemente de arrayContaining
, que permite elementos adicionais 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', () => {
// Verifica se um array de objetos corresponde
expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
{ foo: 'bar' },
{ baz: 1 },
]);
});
toThrowError
Tipo:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
verifica se uma função lança um erro quando invocada.
Você pode fornecer um argumento opcional para testar se um tipo específico de erro é lançado:
- expressão regular: a mensagem de erro corresponde ao padrão
- string: a mensagem de erro inclui a substring
TIP
Você deve envolver o código em uma função; caso contrário, o erro não será capturado e o teste falhará.
Por exemplo, se quisermos testar se getFruitStock('pineapples')
lança um erro, podemos escrever:
import { expect, test } from 'vitest';
function getFruitStock(type: string) {
if (type === 'pineapples') throw new Error('Pineapples are not in stock');
// Faça outras coisas
}
test('throws on pineapples', () => {
// Teste se a mensagem de erro contém "stock" em algum lugar: estes são equivalentes
expect(() => getFruitStock('pineapples')).toThrowError(/stock/);
expect(() => getFruitStock('pineapples')).toThrowError('stock');
// Teste a mensagem de erro exata
expect(() => getFruitStock('pineapples')).toThrowError(
/^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, message?: string) => void
Garante que um valor corresponda ao snapshot mais recente.
Você pode fornecer um argumento de string hint
(dica) opcional, 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 organiza os snapshots por nome no arquivo .snap
correspondente.
TIP
Quando o snapshot não corresponde e causa a falha do teste, se a não correspondência for esperada, você pode pressionar a tecla u
para atualizar o snapshot uma vez. Ou você pode usar as opções de linha de comando -u
ou --update
para que o Vitest sempre atualize os snapshots.
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot();
});
Você também pode fornecer um formato (shape) de um objeto, se você estiver testando apenas um formato 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, message?: string) => void
Garante que um valor corresponda ao snapshot mais recente.
O Vitest adiciona e atualiza o argumento inlineSnapshot
como uma string diretamente 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 um formato (shape) de um objeto, se você estiver testando apenas um formato 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 0.30.0+
- Tipo:
<T>(filepath: string, message?: 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');
});
Note que, por envolver operações assíncronas de sistema de arquivos, você precisa usar await
com toMatchFileSnapshot()
.
toThrowErrorMatchingSnapshot
- Tipo:
(message?: string) => void
Similar a toMatchSnapshot
, mas espera o mesmo valor que toThrowError
.
toThrowErrorMatchingInlineSnapshot
- Tipo:
(snapshot?: string, message?: string) => void
Similar a toMatchInlineSnapshot
, mas espera o mesmo valor que toThrowError
.
toHaveBeenCalled
- Tipo:
() => Awaitable<void>
Esta asserção verifica se uma função foi chamada. Requer que uma função espia (spy) seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function', () => {
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 espia (spy) seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function called two times', () => {
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 os parâmetros especificados. Requer que uma função espia (spy) seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function', () => {
const buySpy = vi.spyOn(market, 'buy');
market.buy('apples', 10);
market.buy('apples', 20);
expect(buySpy).toHaveBeenCalledWith('apples', 10);
expect(buySpy).toHaveBeenCalledWith('apples', 20);
});
toHaveBeenLastCalledWith
- Tipo:
(...args: any[]) => Awaitable<void>
Esta asserção verifica se uma função foi chamada com os parâmetros especificados em sua última invocação. Requer que uma função espia (spy) seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('spy function', () => {
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 os parâmetros especificados em um momento específico. A contagem começa em 1. Portanto, para verificar a segunda chamada, você usaria .toHaveBeenNthCalledWith(2, ...)
.
Requer que uma função espia (spy) seja passada para expect
.
import { expect, test, vi } from 'vitest';
const market = {
buy(subject: string, amount: number) {
// ...
},
};
test('first call of spy function called with right params', () => {
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 espia (spy) seja passada para expect
.
import { expect, test, vi } from 'vitest';
function getApplesPrice(amount: number) {
const PRICE = 10;
return amount * PRICE;
}
test('spy function returned a value', () => {
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 a quantidade exata de vezes (ou seja, não lançou um erro). Requer que uma função espia (spy) seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('spy function returns a value two times', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveReturnedTimes(2);
});
toHaveReturnedWith
- Tipo:
(returnValue: any) => Awaitable<void>
Você pode usar esta asserção para verificar se uma função retornou um valor específico com sucesso, pelo menos uma vez. Requer que uma função spy seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('função spy 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 usar esta asserção para verificar se uma função retornou um valor específico com sucesso na sua última invocação. Requer que uma função spy seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('função spy 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 usar esta asserção para verificar se uma função retornou um valor específico com sucesso em uma chamada específica. Requer que uma função spy seja passada para expect
.
import { expect, test, vi } from 'vitest';
test('função spy retorna bananas na segunda chamada', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveNthReturnedWith(2, { product: 'bananas' });
});
toSatisfy
- Tipo:
(predicate: (value: any) => boolean) => Awaitable<void>
Esta asserção verifica se um valor satisfaz uma condição definida por um predicado.
import { describe, expect, it } from 'vitest';
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('passa com valor ímpar', () => {
expect(1).toSatisfy(isOdd);
});
it('passa com valor par (negação)', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
- Tipo:
Promisify<Assertions>
resolves
simplifica o teste de código assíncrono. Use-o para extrair o valor de uma promise resolvida e validar seu valor com as asserções usuais. Se a promise for rejeitada, a asserção falhará.
Ele retorna o mesmo objeto Assertions
, mas todos os matchers agora retornam Promise
, então você precisará usar await
neles. 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 validar o valor de retorno:
import { expect, test } from 'vitest';
async function buyApples() {
return fetch('/buy/apples').then(r => r.json());
}
test('buyApples retorna o novo ID do estoque', async () => {
// toEqual retorna uma promise agora, então você PRECISA usar await
await expect(buyApples()).resolves.toEqual({ id: 1 }); // jest API
await expect(buyApples()).resolves.to.equal({ id: 1 }); // chai API
});
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)
.
rejects
- Tipo:
Promisify<Assertions>
rejects
simplifica o teste de código assíncrono. Use-o para extrair o motivo pelo qual a promise foi rejeitada e validar seu valor com as asserções usuais. Se a promise for resolvida com sucesso, a asserção falhará.
Ele retorna o mesmo objeto Assertions
, mas todos os matchers agora retornam Promise
, então você precisará usar await
neles. 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 validar o motivo da rejeição:
import { expect, test } from 'vitest';
async function buyApples(id) {
if (!id) throw new Error('no id');
}
test('buyApples lança um erro quando nenhum ID é fornecido', async () => {
// toThrow retorna uma promise agora, então você PRECISA usar await
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 sejam realmente chamadas, você pode usar expect.assertions(number)
.
expect.assertions
- Tipo:
(count: number) => void
Após o teste ter passado ou falhado, verifique se um número específico de asserções foi chamado durante um teste. Um caso de uso comum é verificar se um código assíncrono foi executado.
Por exemplo, se temos uma função que chama assincronamente dois matchers, podemos verificar se eles foram realmente chamados.
import { expect, test } from 'vitest';
async function doAsync(...cbs) {
await Promise.all(cbs.map((cb, index) => cb({ index })));
}
test('todas as asserções são chamadas', 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 concorrentes assíncronos, o expect
do Contexto de Teste local deve ser usado para garantir que o teste correto seja detectado.
expect.hasAssertions
- Tipo:
() => void
Após o teste ter passado ou falhado, verifique se pelo menos uma asserção foi chamada durante um teste. Um caso de uso comum é verificar se um código assíncrono foi executado.
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);
}
// after selecting from db, we call all callbacks
function select(id) {
return db.select({ id }).then(data => {
return Promise.all(cbs.map(cb => cb(data)));
});
}
test('callback foi chamado', async () => {
expect.hasAssertions();
onSelect(data => {
// should be called on select
expect(data).toBeTruthy();
});
// if not awaited, test will fail
// if you don't have expect.hasAssertions(), test will pass
await select(3);
});
expect.unreachable
- Tipo:
(message?: string) => never
Este método é usado para afirmar que uma linha de código nunca deve ser alcançada.
Por exemplo, se quisermos testar se build()
lança um erro devido ao recebimento de diretórios sem a pasta src
e também lidar com cada erro separadamente, podemos 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('build falha com "%s"', async dir => {
try {
await build(dir);
expect.unreachable('Não deveria passar no 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:
// to exhaust all error tests
expect.unreachable('Todos os casos de erro devem ser tratados');
break;
}
}
});
expect.anything
- Tipo:
() => any
Este matcher assimétrico, quando usado com verificação de igualdade, sempre retornará true
. Útil se você só quer garantir que a propriedade existe.
import { expect, test } from 'vitest';
test('objeto tem a chave "apples"', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});
expect.any
- Tipo:
(constructor: unknown) => any
Este matcher assimétrico, quando usado com uma verificação de igualdade, retornará true
somente se o valor for uma instância de um construtor especificado. Útil se você tem um valor que é gerado dinamicamente e você só quer saber se ele existe com o tipo correto.
import { expect, test } from 'vitest';
import { generateId } from './generators.js';
test('"id" é um número', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) });
});
expect.closeTo 1.0.0+
- Tipo:
(expected: any, precision?: number) => any
expect.closeTo
é útil quando se compara números de ponto flutuante em propriedades de objetos ou itens de array. Se você precisar comparar um número, use .toBeCloseTo
em vez disso.
O argumento opcional numDigits
limita o número de dígitos para verificar depois do ponto decimal. Para o valor padrão 2
, o critério de teste é Math.abs(expected - received) < 0.005 (isto é, 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 com uma verificaçã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('cesta contém maçãs 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 com uma verificação de igualdade, este matcher assimétrico retornará true
se o valor tiver uma forma semelhante.
import { expect, test } from 'vitest';
test('cesta tem maçãs empire', () => {
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 com uma verificação de igualdade, este matcher assimétrico retornará true
se o valor for uma string e contiver uma substring especificada.
import { expect, test } from 'vitest';
test('o nome da variedade contém "Emp"', () => {
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 com uma verificação de igualdade, este matcher assimétrico retornará true
se o valor for uma string e contiver uma substring especificada ou se a string corresponder a uma expressão regular.
import { expect, test } from 'vitest';
test('o nome da variedade termina com "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 - se você quiser saber mais, por favor, leia um guia sobre serializadores personalizados.
Se você estiver adicionando serializadores personalizados, você deve chamar este método dentro de setupFiles
. Isso afetará todos os snapshots.
TIP
Se você usou anteriormente o Vue CLI com Jest, você pode querer instalar jest-serializer-vue. Caso contrário, seus snapshots serão envolvidos em uma string, o que faz com que "
seja escapado.
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 de matchers com matchers personalizados.
Quando você define matchers dessa forma, você também cria matchers assimétricos que podem ser usados como expect.stringContaining
.
import { expect, test } from 'vitest';
test('matchers personalizados', () => {
expect.extend({
toBeFoo: (received, expected) => {
if (received !== 'foo') {
return {
message: () => `esperado que ${received} seja foo`,
pass: false,
};
}
},
});
expect('foo').toBeFoo();
expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() });
});
TIP
Se você quer que seus matchers apareçam em todos os testes, você deve chamar este método dentro de setupFiles
.
Esta função é compatível com expect.extend
do Jest, então qualquer biblioteca que a use 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 ambient (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
Não se esqueça de incluir o arquivo de declaração ambient em seu tsconfig.json
.
TIP
Se você quiser saber mais, confira o guia sobre como estender matchers.
expect.addEqualityTesters 1.2.0+
- Tipo:
(tester: Array<Tester>) => void
Você pode usar este método para definir testers customizados, que são métodos usados por matchers para testar se dois objetos são iguais. É compatível com o 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 = isBAnagramComparator(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')
);
});