expect
Los siguientes tipos se utilizan en las firmas de tipo que se muestran a continuación:
type Awaitable<T> = T | PromiseLike<T>;
expect
se utiliza para crear aserciones. En este contexto, las aserciones son funciones que se invocan para verificar una afirmación. Vitest proporciona aserciones de chai
de forma predeterminada y también aserciones compatibles con Jest
construidas sobre chai
.
Por ejemplo, este código afirma que el valor de input
es igual a 2
. Si no lo es, la aserción lanzará un error y la prueba fallará.
import { expect } from 'vitest';
const input = Math.sqrt(4);
expect(input).to.equal(2); // API de chai
expect(input).toBe(2); // API de jest
Técnicamente, este ejemplo no usa la función test
, por lo que en la consola verá un error de Node.js en lugar de la salida de Vitest. Para obtener más información sobre test
, consulte Referencia de la API de prueba.
Además, expect
se puede usar estáticamente para acceder a las funciones de coincidencia (matchers), que se describen más adelante, y más.
WARNING
expect
no tiene efecto en las pruebas de tipos, si la expresión no genera un error de tipo. Si desea utilizar Vitest como verificador de tipos, utilice expectTypeOf
o assertType
.
soft
- Tipo:
ExpectStatic & (actual: any) => Assertions
expect.soft
funciona de manera similar a expect
, pero en lugar de detener la ejecución de la prueba tras un fallo en la aserción, continúa ejecutándose y marca el fallo como un fallo de prueba. Todos los errores encontrados durante la prueba se mostrarán al finalizar la prueba.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // Marca la prueba como fallida pero continúa
expect.soft(1 + 2).toBe(4); // Marca la prueba como fallida pero continúa
});
// Al final de la prueba, se mostrarán los errores anteriores.
También se puede utilizar con expect
. Si la aserción expect
falla, la prueba terminará y se mostrarán todos los errores.
import { expect, test } from 'vitest';
test('expect.soft test', () => {
expect.soft(1 + 1).toBe(3); // Marca la prueba como fallida pero continúa
expect(1 + 2).toBe(4); // Falla y termina la prueba, se mostrarán todos los errores anteriores
expect.soft(1 + 3).toBe(5); // No se llegará a ejecutar
});
WARNING
expect.soft
solo se puede utilizar dentro de la función test
.
not
El uso de not
negará la aserción. Por ejemplo, este código afirma que el valor de input
no es igual a 2
. Si lo es, la aserción lanzará un error y la prueba fallará.
import { expect, test } from 'vitest';
const input = Math.sqrt(16);
expect(input).not.to.equal(2); // API de chai
expect(input).not.toBe(2); // API de jest
toBe
- Tipo:
(value: any) => Awaitable<void>
toBe
se puede utilizar para afirmar si los tipos primitivos son iguales o si los objetos comparten la misma referencia. Es equivalente a expect(Object.is(3, 3)).toBe(true)
. Si los objetos no son los mismos, pero desea comprobar si sus estructuras son idénticas, puede utilizar toEqual
.
Por ejemplo, el siguiente código comprueba si el comerciante tiene 13 manzanas.
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; // misma referencia
expect(stock).toBe(refStock);
});
Intente no utilizar toBe
con números de punto flotante. Dado que JavaScript los redondea, 0.1 + 0.2
no es estrictamente 0.3
. Para afirmar de forma fiable los números de punto flotante, utilice la aserción toBeCloseTo
.
toBeCloseTo
- Tipo:
(value: number, numDigits?: number) => Awaitable<void>
Utilice toBeCloseTo
para comparar números de punto flotante. El argumento opcional numDigits
limita el número de decimales que se deben comprobar. Por ejemplo:
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 es 0.30000000000000004
});
test('decimals are rounded to 5 after the point', () => {
// 0.2 + 0.1 es 0.30000 | "000000000004" eliminado
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
// no se elimina nada de 0.30000000000000004
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 50);
});
toBeDefined
- Tipo:
() => Awaitable<void>
toBeDefined
afirma que el valor no es igual a undefined
. Un caso de uso común es comprobar si una función devolvió un valor.
import { expect, test } from 'vitest';
function getApples() {
return 3;
}
test('function returned something', () => {
expect(getApples()).toBeDefined();
});
toBeUndefined
- Tipo:
() => Awaitable<void>
Opuesto a toBeDefined
, toBeUndefined
afirma que el valor es igual a undefined
. Un caso de uso común es comprobar si una función no devolvió ningún valor.
import { expect, test } from 'vitest';
function getApplesFromStock(stock) {
if (stock === 'Bill') return 13;
}
test("mary doesn't have a stock", () => {
expect(getApplesFromStock('Mary')).toBeUndefined();
});
toBeTruthy
- Tipo:
() => Awaitable<void>
toBeTruthy
afirma que el valor es verdadero cuando se convierte a booleano. Útil si no importa el valor en sí, sino solo si se evalúa como true
en un contexto booleano.
Por ejemplo, si tiene este código, no le importa el valor de retorno de stocks.getInfo
: puede ser un objeto complejo, una cadena o cualquier otra cosa. El código seguirá funcionando.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (stocks.getInfo('Bill')) stocks.sell('apples', 'Bill');
Por lo tanto, si desea probar que stocks.getInfo
será verdadero, podría escribir:
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();
});
En JavaScript, todo se evalúa como verdadero, excepto false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
y document.all
.
toBeFalsy
- Tipo:
() => Awaitable<void>
toBeFalsy
afirma que el valor es falso cuando se convierte a booleano. Útil si no importa el valor en sí, sino solo si se evalúa como false
en un contexto booleano.
Por ejemplo, si tiene este código, no le importa el valor de retorno de stocks.stockFailed
: puede devolver cualquier valor falso, pero el código seguirá funcionando.
import { Stocks } from './stocks.js';
const stocks = new Stocks();
stocks.sync('Bill');
if (!stocks.stockFailed('Bill')) stocks.sell('apples', 'Bill');
Por lo tanto, si desea probar que stocks.stockFailed
será falso, podría escribir:
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();
});
En JavaScript, todo se evalúa como verdadero, excepto false
, null
, undefined
, NaN
, 0
, -0
, 0n
, ""
y document.all
.
toBeNull
- Tipo:
() => Awaitable<void>
toBeNull
simplemente afirma si algo es 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
simplemente afirma si algo es 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
comprueba si un valor es del 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
comprueba si un valor es una instancia de la clase 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
afirma si el valor real es mayor que el recibido. La prueba fallará si los valores son iguales.
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 si el valor real es mayor o igual que el recibido.
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 si el valor real es menor que el recibido. La prueba fallará si los valores son iguales.
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 si el valor real es menor o igual que el recibido.
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 si el valor real es igual al recibido o tiene la misma estructura, si es un objeto (comparación recursiva). Puede ver la diferencia entre toEqual
y toBe
en este ejemplo:
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
No se realizará una igualdad profunda para los objetos Error
. Solo la propiedad message
de un error se considera para la igualdad. Para personalizar la igualdad para verificar propiedades distintas de message
, use expect.addEqualityTesters
. Para probar si se lanzó algo, use la aserción toThrowError
.
toStrictEqual
- Tipo:
(received: any) => Awaitable<void>
toStrictEqual
afirma si el valor real es igual al recibido o tiene la misma estructura si es un objeto (comparación recursiva) y del mismo tipo.
Diferencias con .toEqual
:
- Se verifican las propiedades con valor
undefined
. Por ejemplo,{a: undefined, b: 2}
no coincide con{ b: 2 }
cuando se utiliza.toStrictEqual
. - Se verifica la dispersión en arrays. Por ejemplo,
[, 1]
no coincide con[ undefined, 1 ]
cuando se utiliza.toStrictEqual
. - Se verifica que los tipos de objeto coincidan. Por ejemplo, una instancia de clase con los campos
a
yb
no será igual a un objeto literal con los camposa
yb
.
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 si el valor real está en una matriz. toContain
también puede verificar si una cadena es una subcadena de otra cadena. Desde Vitest 1.0, si está ejecutando pruebas en un entorno similar a un navegador, esta aserción también puede verificar si la clase está contenida en una classList
, o si un elemento está dentro de otro.
import { expect, test } from 'vitest';
import { getAllFruits } from './stocks.js';
test('la lista de frutas contiene orange', () => {
expect(getAllFruits()).toContain('orange');
const element = document.querySelector('#el');
// element tiene una clase
expect(element.classList).toContain('flex');
// element está dentro de otro
expect(document.querySelector('#wrapper')).toContain(element);
});
toContainEqual
- Tipo:
(received: any) => Awaitable<void>
toContainEqual
afirma si un elemento con una estructura y valores específicos está contenido en un arreglo. Realiza una comparación similar a toEqual
para cada elemento del array.
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
comprueba si la propiedad .length
de un objeto coincide con un valor numérico específico.
import { expect, test } from 'vitest';
test('toHaveLength', () => {
expect('abc').toHaveLength(3);
expect([1, 2, 3]).toHaveLength(3);
expect('').not.toHaveLength(3); // no tiene longitud (.length) de 3
expect({ length: 3 }).toHaveLength(3);
});
toHaveProperty
- Tipo:
(key: any, received?: any) => Awaitable<void>
toHaveProperty
verifica si un objeto tiene una propiedad con la clave key
proporcionada.
Opcionalmente, puedes proporcionar un argumento de valor, similar al matcher toEqual
, para comparar el valor de la propiedad.
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'); // Verifica que la clave existe
expect(invoice).toHaveProperty('total_amount', 5000); // Verifica que la clave existe y el valor coincide
expect(invoice).not.toHaveProperty('account'); // Verifica que la clave no existe.
// Referencia profunda usando notación de puntos
expect(invoice).toHaveProperty('customer.first_name');
expect(invoice).toHaveProperty('customer.last_name', 'Doe');
expect(invoice).not.toHaveProperty('customer.location', 'India');
// Referencia profunda usando un array que contiene la clave
expect(invoice).toHaveProperty('items[0].type', 'apples');
expect(invoice).toHaveProperty('items.0.type', 'apples'); // La notación de puntos también es válida.
// Referencia profunda usando un array que contiene el keyPath
expect(invoice).toHaveProperty(['items', 0, 'type'], 'apples');
expect(invoice).toHaveProperty(['items', '0', 'type'], 'apples'); // La notación de string también es válida.
// Envuelve tu clave en un array para evitar que la clave se analice como una referencia profunda
expect(invoice).toHaveProperty(['P.O'], '12345');
});
toMatch
- Tipo:
(received: string | regexp) => Awaitable<void>
toMatch
verifica si una cadena coincide con una expresión regular o con otra cadena.
import { expect, test } from 'vitest';
test('top fruits', () => {
expect('top fruits include apple, orange and grape').toMatch(/apple/);
expect('applefruits').toMatch('fruit'); // toMatch también acepta una cadena
});
toMatchObject
- Tipo:
(received: object | array) => Awaitable<void>
toMatchObject
verifica si un objeto coincide con un subconjunto de las propiedades de otro objeto.
También puedes pasar un array de objetos. Esto es útil para comprobar que dos arrays coinciden exactamente en el número de elementos, a diferencia de arrayContaining
, que permite elementos adicionales en el array recibido.
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', () => {
// Comprueba que un array de objetos coincide
expect([{ foo: 'bar' }, { baz: 1 }]).toMatchObject([
{ foo: 'bar' },
{ baz: 1 },
]);
});
toThrowError
Tipo:
(received: any) => Awaitable<void>
Alias:
toThrow
toThrowError
verifica si una función lanza un error cuando se ejecuta.
Puedes proporcionar un argumento opcional para verificar que se lanza un error específico:
- expresión regular: el mensaje de error coincide con el patrón
- cadena: el mensaje de error incluye la subcadena
TIP
Debes envolver el código en una función; de lo contrario, el error no se capturará y la prueba fallará.
Por ejemplo, si queremos probar que getFruitStock('pineapples')
lanza un error, podríamos escribir:
import { expect, test } from 'vitest';
function getFruitStock(type: string) {
if (type === 'pineapples') throw new Error('Pineapples are not in stock');
// Do some other stuff
}
test('throws on pineapples', () => {
// Comprueba que el mensaje de error contiene "stock" en alguna parte: estos son equivalentes
expect(() => getFruitStock('pineapples')).toThrowError(/stock/);
expect(() => getFruitStock('pineapples')).toThrowError('stock');
// Prueba el mensaje de error exacto
expect(() => getFruitStock('pineapples')).toThrowError(
/^Pineapples are not in stock$/
);
});
TIP
Para probar funciones asíncronas, úsalo en combinación con 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
Asegura que un valor coincida con la última instantánea.
Puedes proporcionar un argumento de cadena hint
opcional que se agrega al nombre de la prueba. Aunque Vitest siempre agrega un número al final de un nombre de instantánea, las sugerencias descriptivas breves pueden ser más útiles que los números para diferenciar múltiples instantáneas en un solo bloque it
o test
. Vitest ordena las instantáneas por nombre en el archivo .snap
correspondiente.
TIP
Cuando la instantánea no coincide y causa que la prueba falle, si este desajuste es esperado, puedes presionar la tecla u
para actualizar la instantánea manualmente. O puedes pasar las opciones de CLI -u
o --update
para hacer que Vitest siempre actualice las pruebas.
import { expect, test } from 'vitest';
test('matches snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
expect(data).toMatchSnapshot();
});
También puedes proporcionar una forma de un objeto, si estás probando solo una forma de un objeto, y no necesitas que sea 100% compatible:
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
Asegura que un valor coincida con la última instantánea.
Vitest agrega y actualiza el argumento de cadena inlineSnapshot
al matcher en el archivo de prueba (en lugar de un archivo .snap
externo).
import { expect, test } from 'vitest';
test('matches inline snapshot', () => {
const data = { foo: new Set(['bar', 'snapshot']) };
// Vitest will update following content when updating the snapshot
expect(data).toMatchInlineSnapshot(`
{
"foo": Set {
"bar",
"snapshot",
},
}
`);
});
También puedes proporcionar una forma de un objeto, si estás probando solo una forma de un objeto, y no necesitas que sea 100% compatible:
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 o actualiza la instantánea con el contenido de un archivo especificado explícitamente (en lugar del archivo .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');
});
toThrowErrorMatchingSnapshot
- Tipo:
(message?: string) => void
Similar a toMatchSnapshot
, pero espera el mismo valor que toThrowError
.
toThrowErrorMatchingInlineSnapshot
- Tipo:
(snapshot?: string, message?: string) => void
Similar a toMatchInlineSnapshot
, pero espera el mismo valor que toThrowError
.
Si la función lanza un Error
, la instantánea será el mensaje de error. De lo contrario, la instantánea será el valor lanzado por la función.
toHaveBeenCalled
- Tipo:
() => Awaitable<void>
Esta afirmación es útil para verificar si una función ha sido llamada. Requiere que se pase una función espía a 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 afirmación comprueba si una función fue llamada una cantidad específica de veces. Requiere que se pase una función espía a 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 afirmación comprueba si una función fue llamada al menos una vez con ciertos parámetros. Requiere que se pase una función espía a 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 afirmación comprueba si una función fue llamada con ciertos parámetros en su última invocación. Requiere que se pase una función espía a 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 afirmación comprueba si una función fue llamada con ciertos parámetros en una invocación específica. El conteo comienza en 1. Por lo tanto, para verificar la segunda llamada, usarías .toHaveBeenNthCalledWith(2, ...)
.
Requiere que se pase una función espía a 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 afirmación comprueba si una función ha devuelto un valor correctamente al menos una vez (es decir, no lanzó un error). Requiere que se pase una función espía a 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 afirmación comprueba si una función ha devuelto un valor correctamente una cantidad exacta de veces (es decir, no lanzó un error). Requiere que se pase una función espía a 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>
Puedes usar esta aserción para verificar si una función espía (spy function) ha retornado un valor específico al menos una vez. Requiere que se pase una función espía a expect
.
import { expect, test, vi } from 'vitest';
test('la función espía retorna un producto', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
expect(sell).toHaveReturnedWith({ product: 'apples' });
});
toHaveLastReturnedWith
- Tipo:
(returnValue: any) => Awaitable<void>
Puedes usar esta aserción para verificar si una función espía (spy function) ha retornado un valor específico en su última invocación. Requiere que se pase una función espía a expect
.
import { expect, test, vi } from 'vitest';
test('la función espía retorna bananas en la última llamada', () => {
const sell = vi.fn((product: string) => ({ product }));
sell('apples');
sell('bananas');
expect(sell).toHaveLastReturnedWith({ product: 'bananas' });
});
toHaveNthReturnedWith
- Tipo:
(time: number, returnValue: any) => Awaitable<void>
Puedes usar esta aserción para verificar si una función espía (spy function) ha retornado un valor específico en una invocación determinada. Requiere que se pase una función espía a expect
.
import { expect, test, vi } from 'vitest';
test('la función espía retorna bananas en la segunda llamada', () => {
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 aserción verifica si un valor cumple con un predicado dado.
import { describe, expect, it } from 'vitest';
describe('toSatisfy()', () => {
const isOdd = (value: number) => value % 2 !== 0;
it('pasa con 1', () => {
expect(1).toSatisfy(isOdd);
});
it('pasa con negación', () => {
expect(2).not.toSatisfy(isOdd);
});
});
resolves
- Tipo:
Promisify<Assertions>
resolves
está diseñado para simplificar las aserciones en código asíncrono. Úsalo para extraer el valor resuelto de una promesa y realizar una aserción sobre ese valor utilizando las aserciones habituales. Si la promesa es rechazada, la aserción fallará.
Retorna el mismo objeto Assertions
, pero todos los matchers ahora retornan Promise
, por lo que necesitarás usar await
. También funciona con aserciones de chai
.
Por ejemplo, si tienes una función que realiza una llamada a una API y retorna datos, puedes usar este código para realizar una aserción sobre su valor de retorno:
import { expect, test } from 'vitest';
async function buyApples() {
return fetch('/buy/apples').then(r => r.json());
}
test('buyApples retorna el nuevo ID del stock', async () => {
// toEqual retorna una promesa ahora, así que debes usar await
await expect(buyApples()).resolves.toEqual({ id: 1 }); // API de Jest
await expect(buyApples()).resolves.to.equal({ id: 1 }); // API de Chai
});
WARNING
Si no esperas la aserción con await
, tendrás una prueba falsamente positiva que siempre pasará. Para asegurarte de que las aserciones se ejecuten realmente, puedes usar expect.assertions(number)
.
rejects
- Tipo:
Promisify<Assertions>
rejects
está diseñado para simplificar las aserciones en código asíncrono. Úsalo para extraer la razón por la cual una promesa fue rechazada y realizar una aserción sobre ese valor utilizando las aserciones habituales. Si la promesa se resuelve exitosamente, la aserción fallará.
Retorna el mismo objeto Assertions
, pero todos los matchers ahora retornan Promise
, por lo que necesitarás usar await
. También funciona con aserciones de chai
.
Por ejemplo, si tienes una función que falla cuando la llamas, puedes usar este código para realizar una aserción sobre la razón del rechazo:
import { expect, test } from 'vitest';
async function buyApples(id) {
if (!id) throw new Error('no id');
}
test('buyApples lanza un error cuando no se proporciona un ID', async () => {
// toThrow retorna una promesa ahora, así que debes usar await
await expect(buyApples()).rejects.toThrow('no id');
});
WARNING
Si no esperas la aserción con await
, tendrás una prueba falsamente positiva que siempre pasará. Para asegurarte de que las aserciones se ejecuten realmente, puedes usar expect.assertions(number)
.
expect.assertions
- Tipo:
(count: number) => void
Después de que la prueba haya finalizado (ya sea pasando o fallando), verifica que se haya llamado a un número específico de aserciones durante la prueba. Un caso de uso común es verificar si se ejecutó código asíncrono.
Por ejemplo, si tenemos una función que llama asíncronamente a dos matchers, podemos asegurar que ambos fueron realmente llamados.
import { expect, test } from 'vitest';
async function doAsync(...cbs) {
await Promise.all(cbs.map((cb, index) => cb({ index })));
}
test('todas las aserciones son llamadas', async () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
await doAsync(callback1, callback2);
});
WARNING
Cuando se usa assertions
con pruebas concurrentes asíncronas, el expect
del Contexto de Prueba local debe ser usado para asegurar que la prueba correcta sea detectada.
expect.hasAssertions
- Tipo:
() => void
Después de que la prueba haya finalizado (ya sea pasando o fallando), verifica que se haya llamado al menos a una aserción durante la prueba. Un caso de uso común es verificar si se ejecutó código asíncrono.
Por ejemplo, si tienes un código que llama a un callback, podemos hacer una aserción dentro del callback, pero la prueba siempre pasará si no verificamos si se llamó a alguna aserción.
import { expect, test } from 'vitest';
import { db } from './db.js';
const cbs = [];
function onSelect(cb) {
cbs.push(cb);
}
// después de seleccionar de la base de datos, llamamos a todos los callbacks
function select(id) {
return db.select({ id }).then(data => {
return Promise.all(cbs.map(cb => cb(data)));
});
}
test('el callback fue llamado', async () => {
expect.hasAssertions();
onSelect(data => {
// debería ser llamado en la selección
expect(data).toBeTruthy();
});
// si no se espera con await, la prueba fallará
// si no tienes expect.hasAssertions(), la prueba pasará
await select(3);
});
expect.unreachable
- Tipo:
(message?: string) => never
Este método se usa para asegurar que una línea de código nunca debería ser alcanzada.
Por ejemplo, si queremos probar que build()
lanza un error porque los directorios recibidos no tienen una carpeta src
, y también manejar cada error por separado, podríamos hacer esto:
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 falla con "%s"', async dir => {
try {
await build(dir);
expect.unreachable('No debería pasar la compilación'); // No debería completarse la compilación
} 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 agotar todas las pruebas de error
expect.unreachable('Todas las pruebas de error deben ser gestionadas'); // Todas las pruebas de error deben ser gestionadas
break;
}
}
});
expect.anything
- Tipo:
() => any
Este matcher asimétrico, cuando se usa en una verificación de igualdad, siempre retornará true
. Es útil si solo quieres asegurarte de que una propiedad existe.
import { expect, test } from 'vitest';
test('el objeto tiene la clave "apples"', () => {
expect({ apples: 22 }).toEqual({ apples: expect.anything() });
});
expect.any
- Tipo:
(constructor: unknown) => any
Este matcher asimétrico, cuando se usa en una verificación de igualdad, devolverá true
solo si el valor es una instancia del constructor especificado. Es útil si tienes un valor que se genera cada vez y solo quieres saber que existe con el tipo apropiado.
import { expect, test } from 'vitest';
import { generateId } from './generators.js';
test('"id" es un número', () => {
expect({ id: generateId() }).toEqual({ id: expect.any(Number) });
});
expect.closeTo 1.0.0+
- Tipo:
(expected: any, precision?: number) => any
expect.closeTo
es útil cuando se comparan números de punto flotante en propiedades de objetos o elementos de matriz. Si necesita comparar un número, utilice .toBeCloseTo
en su lugar.
El argumento opcional numDigits
limita el número de dígitos a verificar después del punto decimal. Para el valor predeterminado 2
, el criterio de prueba es Math.abs(expected - received) < 0.005 (es decir, 10 ** -2 / 2)
.
Por ejemplo, esta prueba pasa con una precisión de 5 dígitos:
test('comparar flotante en propiedades de objeto', () => {
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
Cuando se usa en una verificación de igualdad, este matcher asimétrico retornará true
si el valor es un array y contiene los elementos especificados.
import { expect, test } from 'vitest';
test('la cesta incluye fuji', () => {
const basket = {
varieties: ['Empire', 'Fuji', 'Gala'],
count: 3,
};
expect(basket).toEqual({
count: 3,
varieties: expect.arrayContaining(['Fuji']),
});
});
TIP
Puedes usar expect.not
con este matcher para negar el valor esperado.
expect.objectContaining
- Tipo:
(expected: any) => any
Cuando se usa en una verificación de igualdad, este matcher asimétrico retornará true
si el valor tiene una estructura similar.
import { expect, test } from 'vitest';
test('la cesta tiene manzanas empire', () => {
const basket = {
varieties: [
{
name: 'Empire',
count: 1,
},
],
};
expect(basket).toEqual({
varieties: [expect.objectContaining({ name: 'Empire' })],
});
});
TIP
Puedes usar expect.not
con este matcher para negar el valor esperado.
expect.stringContaining
- Tipo:
(expected: any) => any
Cuando se usa en una verificación de igualdad, este matcher asimétrico retornará true
si el valor es un string y contiene una subcadena especificada.
import { expect, test } from 'vitest';
test('la variedad tiene "Emp" en su nombre', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringContaining('Emp'),
count: 1,
});
});
TIP
Puedes usar expect.not
con este matcher para negar el valor esperado.
expect.stringMatching
- Tipo:
(expected: any) => any
Cuando se usa en una verificación de igualdad, este matcher asimétrico retornará true
si el valor es un string y contiene una subcadena especificada o si el string coincide con una expresión regular.
import { expect, test } from 'vitest';
test('la variedad termina con "re"', () => {
const variety = {
name: 'Empire',
count: 1,
};
expect(variety).toEqual({
name: expect.stringMatching(/re$/),
count: 1,
});
});
TIP
Puedes usar expect.not
con este matcher para negar el valor esperado.
expect.addSnapshotSerializer
- Tipo:
(plugin: PrettyFormatPlugin) => void
Este método agrega serializadores personalizados que se invocan al crear una instantánea (snapshot). Esta es una característica avanzada; si quieres saber más, consulta la guía sobre serializadores personalizados.
Si estás agregando serializadores personalizados, deberías invocar este método dentro de setupFiles
. Esto afectará a cada instantánea.
TIP
Si previamente usaste Vue CLI con Jest, es posible que desees instalar jest-serializer-vue. De lo contrario, tus instantáneas se envolverán en una cadena, lo que provocará que se escape "
."
expect.extend
- Tipo:
(matchers: MatchersObject) => void
Puedes extender los matchers predeterminados con los tuyos propios. Esta función se usa para extender el objeto de matchers con matchers personalizados.
Cuando defines matchers de esta manera, también creas matchers asimétricos que se pueden usar como expect.stringContaining
.
import { expect, test } from 'vitest';
test('matchers personalizados', () => {
expect.extend({
toBeFoo: (received, expected) => {
if (received !== 'foo') {
return {
message: () => `se esperaba que ${received} fuera foo`,
pass: false,
};
}
},
});
expect('foo').toBeFoo();
expect({ foo: 'foo' }).toEqual({ foo: expect.toBeFoo() });
});
TIP
Si quieres que tus matchers aparezcan en cada prueba, deberías invocar este método dentro de setupFiles
.
Esta función es compatible con expect.extend
de Jest, por lo que cualquier librería que lo use para crear matchers personalizados funcionará con Vitest.
Si estás usando TypeScript, a partir de Vitest 0.31.0 puedes extender la interfaz Assertion
predeterminada en un archivo de declaración de entorno (p. ej., vitest.d.ts
) con el siguiente código:
interface CustomMatchers<R = unknown> {
toBeFoo: () => R;
}
declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
WARNING
No olvides incluir el archivo de declaración en tu tsconfig.json
.
TIP
Si quieres saber más, revisa la guía sobre cómo extender matchers.
expect.addEqualityTesters 1.2.0+
- Tipo:
(tester: Array<Tester>) => void
Puede utilizar este método para definir evaluadores personalizados, que son métodos utilizados por los comparadores, para probar si dos objetos son iguales. Es compatible con expect.addEqualityTesters
de 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('evaluador de igualdad personalizado', () => {
expect(new AnagramComparator('listen')).toEqual(
new AnagramComparator('silent')
);
});