Saltar al contenido principal
Versión: 29.7

Expect

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Cuando escribes pruebas, a menudo necesitas verificar que los valores cumplan ciertas condiciones. expect te da acceso a varios "matchers" que permiten validar diferentes aspectos.

consejo

Para matchers adicionales de Jest mantenidos por la comunidad, consulta jest-extended.

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

información

Los ejemplos de TypeScript en esta página solo funcionarán como se documenta si importas explícitamente las APIs de Jest:

import {expect, jest, test} from '@jest/globals';

Consulta la guía de Primeros pasos para obtener detalles sobre cómo configurar Jest con TypeScript.

Referencia


Expect

expect(value)

La función expect se utiliza cada vez que quieres probar un valor. Rara vez llamarás expect por sí sola. En su lugar, usarás expect junto con una función "matcher" para afirmar algo sobre un valor.

Es más fácil entenderlo con un ejemplo. Supongamos que tienes un método bestLaCroixFlavor() que debería devolver el string 'grapefruit'. Así es como lo probarías:

test('the best flavor is grapefruit', () => {
expect(bestLaCroixFlavor()).toBe('grapefruit');
});

En este caso, toBe es la función matcher. Existen muchas funciones matcher diferentes, documentadas a continuación, que te ayudarán a probar distintos aspectos.

El argumento de expect debe ser el valor que produce tu código, y cualquier argumento del matcher debe ser el valor correcto. Si los intercambias, tus pruebas seguirán funcionando, pero los mensajes de error en pruebas fallidas parecerán extraños.

Modificadores

.not

Si sabes cómo probar algo, .not te permite probar su opuesto. Por ejemplo, este código verifica que el mejor sabor de La Croix no es coco:

test('the best flavor is not coconut', () => {
expect(bestLaCroixFlavor()).not.toBe('coconut');
});

.resolves

Usa resolves para desenvolver el valor de una promesa resuelta y poder encadenar otros matchers. Si la promesa es rechazada, la aserción falla.

Por ejemplo, este código verifica que la promesa se resuelve y que el valor resultante es 'lemon':

test('resolves to lemon', () => {
// make sure to add a return statement
return expect(Promise.resolve('lemon')).resolves.toBe('lemon');
});
nota

Como aún estás probando promesas, la prueba sigue siendo asíncrona. Por lo tanto, necesitarás indicarle a Jest que espere devolviendo la aserción desenvuelta.

Alternativamente, puedes usar async/await combinado con .resolves:

test('resolves to lemon', async () => {
await expect(Promise.resolve('lemon')).resolves.toBe('lemon');
await expect(Promise.resolve('lemon')).resolves.not.toBe('octopus');
});

.rejects

Usa .rejects para desenvolver el motivo de una promesa rechazada y poder encadenar otros matchers. Si la promesa se resuelve, la aserción falla.

Por ejemplo, este código verifica que la promesa es rechazada con el motivo 'octopus':

test('rejects to octopus', () => {
// make sure to add a return statement
return expect(Promise.reject(new Error('octopus'))).rejects.toThrow(
'octopus',
);
});
nota

Como aún estás probando promesas, la prueba sigue siendo asíncrona. Por lo tanto, necesitarás indicarle a Jest que espere devolviendo la aserción desenvuelta.

Alternativamente, puedes usar async/await combinado con .rejects.

test('rejects to octopus', async () => {
await expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus');
});

Matchers

.toBe(value)

Usa .toBe para comparar valores primitivos o verificar la identidad referencial de instancias de objetos. Llama a Object.is para comparar valores, lo cual es incluso mejor para pruebas que el operador de igualdad estricta ===.

Por ejemplo, este código validará algunas propiedades del objeto can:

const can = {
name: 'pamplemousse',
ounces: 12,
};

describe('the can', () => {
test('has 12 ounces', () => {
expect(can.ounces).toBe(12);
});

test('has a sophisticated name', () => {
expect(can.name).toBe('pamplemousse');
});
});

No uses .toBe con números de punto flotante. Por ejemplo, debido al redondeo en JavaScript, 0.2 + 0.1 no es estrictamente igual a 0.3. Si trabajas con números decimales, usa .toBeCloseTo.

Aunque el matcher .toBe verifica la identidad referencial, reporta una comparación profunda de valores cuando la aserción falla. Si las diferencias entre propiedades no te ayudan a entender por qué falla una prueba, especialmente si el reporte es extenso, puedes mover la comparación a la función expect. Por ejemplo, para verificar si los elementos son la misma instancia:

  • reescribe expect(received).toBe(expected) como expect(Object.is(received, expected)).toBe(true)

  • reescribe expect(received).not.toBe(expected) como expect(Object.is(received, expected)).toBe(false)

.toHaveBeenCalled()

También disponible como alias: .toBeCalled()

Usa .toHaveBeenCalled para verificar que una función simulada (mock) fue llamada.

Por ejemplo, supongamos que tienes una función drinkAll(drink, flavour) que toma una función drink y la aplica a todas las bebidas disponibles. Puedes verificar que drink fue llamada con este conjunto de pruebas:

function drinkAll(callback, flavour) {
if (flavour !== 'octopus') {
callback(flavour);
}
}

describe('drinkAll', () => {
test('drinks something lemon-flavoured', () => {
const drink = jest.fn();
drinkAll(drink, 'lemon');
expect(drink).toHaveBeenCalled();
});

test('does not drink something octopus-flavoured', () => {
const drink = jest.fn();
drinkAll(drink, 'octopus');
expect(drink).not.toHaveBeenCalled();
});
});

.toHaveBeenCalledTimes(number)

También disponible como alias: .toBeCalledTimes(number)

Usa .toHaveBeenCalledTimes para asegurar que una función simulada fue llamada un número exacto de veces.

Por ejemplo, imagina una función drinkEach(drink, Array<flavor>) que toma una función drink y la aplica a un array de bebidas. Puedes verificar que la función drink fue llamada un número exacto de veces con esta prueba:

test('drinkEach drinks each drink', () => {
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenCalledTimes(2);
});

.toHaveBeenCalledWith(arg1, arg2, ...)

También disponible como alias: .toBeCalledWith()

Usa .toHaveBeenCalledWith para verificar que una función simulada fue llamada con argumentos específicos. Los argumentos se comparan con el mismo algoritmo que usa .toEqual.

Por ejemplo, supón que puedes registrar una bebida con una función register, y applyToAll(f) debería aplicar la función f a todas las bebidas registradas. Para verificarlo, podrías escribir:

test('registration applies correctly to orange La Croix', () => {
const beverage = new LaCroix('orange');
register(beverage);
const f = jest.fn();
applyToAll(f);
expect(f).toHaveBeenCalledWith(beverage);
});

.toHaveBeenLastCalledWith(arg1, arg2, ...)

También disponible como alias: .lastCalledWith(arg1, arg2, ...)

Para funciones simuladas, usa .toHaveBeenLastCalledWith para probar con qué argumentos fue llamada por última vez. Por ejemplo, si tienes una función applyToAllFlavors(f) que aplica f a varios sabores, y quieres asegurar que el último sabor procesado fue 'mango':

test('applying to all flavors does mango last', () => {
const drink = jest.fn();
applyToAllFlavors(drink);
expect(drink).toHaveBeenLastCalledWith('mango');
});

.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)

También disponible como alias: .nthCalledWith(nthCall, arg1, arg2, ...)

Para funciones simuladas, usa .toHaveBeenNthCalledWith para verificar los argumentos de la llamada número n. Por ejemplo, con una función drinkEach(drink, Array<flavor>) que aplica f a varios sabores, para verificar que el primer sabor fue 'lemon' y el segundo 'octopus':

test('drinkEach drinks each drink', () => {
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenNthCalledWith(1, 'lemon');
expect(drink).toHaveBeenNthCalledWith(2, 'octopus');
});
nota

El argumento nthCall debe ser un número entero positivo empezando desde 1.

.toHaveReturned()

También disponible como alias: .toReturn()

Para funciones simuladas, usa .toHaveReturned para verificar que la función retornó exitosamente (sin lanzar errores) al menos una vez. Por ejemplo, con una función simulada drink que retorna true:

test('drinks returns', () => {
const drink = jest.fn(() => true);

drink();

expect(drink).toHaveReturned();
});

.toHaveReturnedTimes(number)

También disponible como alias: .toReturnTimes(number)

Usa .toHaveReturnedTimes para asegurar que una función simulada retornó exitosamente (sin errores) un número exacto de veces. Las llamadas que lancen errores no cuentan.

Por ejemplo, con una función simulada drink que retorna true:

test('drink returns twice', () => {
const drink = jest.fn(() => true);

drink();
drink();

expect(drink).toHaveReturnedTimes(2);
});

.toHaveReturnedWith(value)

También disponible como alias: .toReturnWith(value)

Usa .toHaveReturnedWith para verificar que una función simulada retornó un valor específico.

Por ejemplo, imagina que tienes una función simulada drink que devuelve el nombre de la bebida consumida. Puedes escribir:

test('drink returns La Croix', () => {
const beverage = {name: 'La Croix'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage);

expect(drink).toHaveReturnedWith('La Croix');
});

.toHaveLastReturnedWith(value)

También disponible como alias: .lastReturnedWith(value)

Usa .toHaveLastReturnedWith para verificar el valor específico que una función simulada devolvió en su última ejecución. Si la última llamada a la función simulada lanzó un error, este matcher fallará independientemente del valor esperado que hayas proporcionado.

Por ejemplo, imagina que tienes una función simulada drink que devuelve el nombre de la bebida consumida. Puedes escribir:

test('drink returns La Croix (Orange) last', () => {
const beverage1 = {name: 'La Croix (Lemon)'};
const beverage2 = {name: 'La Croix (Orange)'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage1);
drink(beverage2);

expect(drink).toHaveLastReturnedWith('La Croix (Orange)');
});

.toHaveNthReturnedWith(nthCall, value)

También disponible como alias: .nthReturnedWith(nthCall, value)

Usa .toHaveNthReturnedWith para verificar el valor específico que una función simulada devolvió en su enésima llamada (nth call). Si la enésima llamada a la función simulada lanzó un error, este matcher fallará independientemente del valor esperado que hayas proporcionado.

Por ejemplo, imagina que tienes una función simulada drink que devuelve el nombre de la bebida consumida. Puedes escribir:

test('drink returns expected nth calls', () => {
const beverage1 = {name: 'La Croix (Lemon)'};
const beverage2 = {name: 'La Croix (Orange)'};
const drink = jest.fn(beverage => beverage.name);

drink(beverage1);
drink(beverage2);

expect(drink).toHaveNthReturnedWith(1, 'La Croix (Lemon)');
expect(drink).toHaveNthReturnedWith(2, 'La Croix (Orange)');
});
nota

El argumento nthCall debe ser un número entero positivo empezando desde 1.

.toHaveLength(number)

Usa .toHaveLength para verificar que un objeto tiene una propiedad .length con un valor numérico específico.

Es especialmente útil para comprobar el tamaño de arrays o cadenas de texto.

expect([1, 2, 3]).toHaveLength(3);
expect('abc').toHaveLength(3);
expect('').not.toHaveLength(5);

.toHaveProperty(keyPath, value?)

Usa .toHaveProperty para verificar si existe una propiedad en la ruta keyPath de un objeto. Para propiedades anidadas, puedes usar notación de punto o un array con la ruta completa.

Puedes proporcionar un argumento opcional value para comparar el valor de la propiedad recibida (usa igualdad profunda como el matcher toEqual).

El siguiente ejemplo contiene un objeto houseForSale con propiedades anidadas. Usamos toHaveProperty para verificar la existencia y valores de varias propiedades:

// Object containing house features to be tested
const houseForSale = {
bath: true,
bedrooms: 4,
kitchen: {
amenities: ['oven', 'stove', 'washer'],
area: 20,
wallColor: 'white',
'nice.oven': true,
},
livingroom: {
amenities: [
{
couch: [
['large', {dimensions: [20, 20]}],
['small', {dimensions: [10, 10]}],
],
},
],
},
'ceiling.height': 2,
};

test('this house has my desired features', () => {
// Example Referencing
expect(houseForSale).toHaveProperty('bath');
expect(houseForSale).toHaveProperty('bedrooms', 4);

expect(houseForSale).not.toHaveProperty('pool');

// Deep referencing using dot notation
expect(houseForSale).toHaveProperty('kitchen.area', 20);
expect(houseForSale).toHaveProperty('kitchen.amenities', [
'oven',
'stove',
'washer',
]);

expect(houseForSale).not.toHaveProperty('kitchen.open');

// Deep referencing using an array containing the keyPath
expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20);
expect(houseForSale).toHaveProperty(
['kitchen', 'amenities'],
['oven', 'stove', 'washer'],
);
expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven');
expect(houseForSale).toHaveProperty(
'livingroom.amenities[0].couch[0][1].dimensions[0]',
20,
);
expect(houseForSale).toHaveProperty(['kitchen', 'nice.oven']);
expect(houseForSale).not.toHaveProperty(['kitchen', 'open']);

// Referencing keys with dot in the key itself
expect(houseForSale).toHaveProperty(['ceiling.height'], 'tall');
});

.toBeCloseTo(number, numDigits?)

Usa toBeCloseTo para comparar números de punto flotante con igualdad aproximada.

El argumento opcional numDigits limita los dígitos a comprobar después del punto decimal. Por defecto (2), el criterio es Math.abs(expected - received) < 0.005 (equivalente a 10 ** -2 / 2).

Las comparaciones intuitivas a menudo fallan porque los valores decimales (base 10) tienen errores de redondeo en representación binaria (base 2). Por ejemplo, esta prueba falla:

test('adding works sanely with decimals', () => {
expect(0.2 + 0.1).toBe(0.3); // Fails!
});

Falla porque en JavaScript, 0.2 + 0.1 equivale realmente a 0.30000000000000004.

Por ejemplo, esta prueba pasa con una precisión de 5 dígitos:

test('adding works sanely with decimals', () => {
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
});

Como toBeCloseTo resuelve errores de punto flotante, no soporta valores enteros grandes.

.toBeDefined()

Usa .toBeDefined para verificar que una variable no es undefined. Por ejemplo, para comprobar que fetchNewFlavorIdea() devuelve algo:

test('there is a new flavor idea', () => {
expect(fetchNewFlavorIdea()).toBeDefined();
});

Podrías usar expect(fetchNewFlavorIdea()).not.toBe(undefined), pero es mejor evitar referenciar undefined directamente.

.toBeFalsy()

Usa .toBeFalsy cuando no te importe el valor concreto pero necesites verificar que es falso en contexto booleano. Por ejemplo, si tienes código como:

drinkSomeLaCroix();
if (!getErrors()) {
drinkMoreLaCroix();
}

Quizá no te importe qué devuelve específicamente getErrors - podría devolver false, null o 0, y tu código seguiría funcionando. Así que si quieres verificar que no hay errores después de beber un poco de La Croix, podrías escribir:

test('drinking La Croix does not lead to errors', () => {
drinkSomeLaCroix();
expect(getErrors()).toBeFalsy();
});

En JavaScript, existen seis valores falsy: false, 0, '', null, undefined y NaN. Todo lo demás es truthy.

.toBeGreaterThan(number | bigint)

Usa toBeGreaterThan para comparar received > expected con valores numéricos o big integer. Por ejemplo, para probar que ouncesPerCan() devuelve un valor superior a 10 onzas:

test('ounces per can is more than 10', () => {
expect(ouncesPerCan()).toBeGreaterThan(10);
});

.toBeGreaterThanOrEqual(number | bigint)

Usa toBeGreaterThanOrEqual para comparar received >= expected con valores numéricos o big integer. Por ejemplo, para probar que ouncesPerCan() devuelve un valor de al menos 12 onzas:

test('ounces per can is at least 12', () => {
expect(ouncesPerCan()).toBeGreaterThanOrEqual(12);
});

.toBeLessThan(number | bigint)

Usa toBeLessThan para comparar received < expected con valores numéricos o big integer. Por ejemplo, para probar que ouncesPerCan() devuelve un valor inferior a 20 onzas:

test('ounces per can is less than 20', () => {
expect(ouncesPerCan()).toBeLessThan(20);
});

.toBeLessThanOrEqual(number | bigint)

Usa toBeLessThanOrEqual para comparar received <= expected con valores numéricos o big integer. Por ejemplo, para probar que ouncesPerCan() devuelve un valor máximo de 12 onzas:

test('ounces per can is at most 12', () => {
expect(ouncesPerCan()).toBeLessThanOrEqual(12);
});

.toBeInstanceOf(Class)

Usa .toBeInstanceOf(Class) para verificar que un objeto es instancia de una clase. Este matcher utiliza internamente instanceof.

class A {}

expect(new A()).toBeInstanceOf(A);
expect(() => {}).toBeInstanceOf(Function);
expect(new A()).toBeInstanceOf(Function); // throws

.toBeNull()

.toBeNull() es equivalente a .toBe(null) pero con mensajes de error más claros. Usa .toBeNull() cuando quieras verificar que algo es null.

function bloop() {
return null;
}

test('bloop returns null', () => {
expect(bloop()).toBeNull();
});

.toBeTruthy()

Usa .toBeTruthy cuando no te importe el valor específico pero quieras asegurar que es verdadero en contexto booleano. Por ejemplo, imagina que tienes código como:

drinkSomeLaCroix();
if (thirstInfo()) {
drinkMoreLaCroix();
}

Quizá no te importe qué devuelve thirstInfo específicamente - podría devolver true o un objeto complejo, y tu código seguiría funcionando. Así que si quieres probar que thirstInfo será truthy después de beber La Croix, podrías escribir:

test('drinking La Croix leads to having thirst info', () => {
drinkSomeLaCroix();
expect(thirstInfo()).toBeTruthy();
});

En JavaScript, existen seis valores falsy: false, 0, '', null, undefined y NaN. Todo lo demás es truthy.

.toBeUndefined()

Usa .toBeUndefined para verificar que una variable es undefined. Por ejemplo, si quieres comprobar que bestDrinkForFlavor(flavor) devuelve undefined para el sabor 'octopus' porque no hay bebidas buenas con sabor a pulpo:

test('the best drink for octopus flavor is undefined', () => {
expect(bestDrinkForFlavor('octopus')).toBeUndefined();
});

Podrías escribir expect(bestDrinkForFlavor('octopus')).toBe(undefined), pero es mejor práctica evitar referenciar undefined directamente en tu código.

.toBeNaN()

Usa .toBeNaN para verificar que un valor es NaN.

test('passes when value is NaN', () => {
expect(NaN).toBeNaN();
expect(1).not.toBeNaN();
});

.toContain(item)

Usa .toContain para verificar que un elemento está en un array. Para los elementos del array, usa === (comparación estricta). .toContain también puede verificar si un string es subcadena de otro.

Por ejemplo, si getAllFlavors() devuelve un array de sabores y quieres asegurarte que lime está incluido:

test('the flavor list contains lime', () => {
expect(getAllFlavors()).toContain('lime');
});

Este matcher también acepta otros iterables como strings, sets, node lists y HTML collections.

.toContainEqual(item)

Usa .toContainEqual cuando quieras verificar que un elemento con estructura y valores específicos está contenido en un array. Para evaluar los elementos del array, este matcher comprueba recursivamente la igualdad de todos los campos, en lugar de verificar la identidad del objeto.

describe('my beverage', () => {
test('is delicious and not sour', () => {
const myBeverage = {delicious: true, sour: false};
expect(myBeverages()).toContainEqual(myBeverage);
});
});

.toEqual(value)

Usa .toEqual para comparar recursivamente todas las propiedades de instancias de objetos (conocido como igualdad "profunda"). Llama a Object.is para comparar valores primitivos, lo cual es incluso mejor para pruebas que el operador de igualdad estricta ===.

Por ejemplo, .toEqual y .toBe se comportan de forma diferente en esta suite de pruebas, por lo que todos los tests pasan:

const can1 = {
flavor: 'grapefruit',
ounces: 12,
};
const can2 = {
flavor: 'grapefruit',
ounces: 12,
};

describe('the La Croix cans on my desk', () => {
test('have all the same properties', () => {
expect(can1).toEqual(can2);
});
test('are not the exact same can', () => {
expect(can1).not.toBe(can2);
});
});
consejo

toEqual ignora claves de objeto con propiedades undefined, elementos de array undefined, arrays dispersos o discrepancias en el tipo de objeto. Para considerar estos casos, usa .toStrictEqual en su lugar.

información

.toEqual no realiza una verificación de igualdad profunda para dos errores. Solo se considera la propiedad message de un Error para la igualdad. Se recomienda usar el matcher .toThrow para probar errores.

Si las diferencias entre propiedades no te ayudan a entender por qué falla un test, especialmente si el informe es extenso, puedes trasladar la comparación a la función expect. Por ejemplo, usa el método equals de la clase Buffer para verificar si los buffers contienen el mismo contenido:

  • reescribe expect(received).toEqual(expected) como expect(received.equals(expected)).toBe(true)

  • reescribe expect(received).not.toEqual(expected) como expect(received.equals(expected)).toBe(false)

.toMatch(regexp | string)

Usa .toMatch para verificar que una cadena coincide con una expresión regular.

Por ejemplo, quizás no sepas qué devuelve exactamente essayOnTheBestFlavor(), pero sabes que es una cadena muy larga y que la subcadena grapefruit debería aparecer en algún lugar. Puedes probarlo así:

describe('an essay on the best flavor', () => {
test('mentions grapefruit', () => {
expect(essayOnTheBestFlavor()).toMatch(/grapefruit/);
expect(essayOnTheBestFlavor()).toMatch(new RegExp('grapefruit'));
});
});

Este matcher también acepta una cadena, que intentará coincidir:

describe('grapefruits are healthy', () => {
test('grapefruits are a fruit', () => {
expect('grapefruits').toMatch('fruit');
});
});

.toMatchObject(object)

Usa .toMatchObject para verificar que un objeto JavaScript coincide con un subconjunto de propiedades de otro objeto. Coincidirá con objetos recibidos que tengan propiedades que no están en el objeto esperado.

También puedes pasar un array de objetos, en cuyo caso el método devolverá true solo si cada objeto en el array recibido coincide (en el sentido de toMatchObject descrito) con el objeto correspondiente en el array esperado. Esto es útil si quieres verificar que dos arrays coinciden en su número de elementos, a diferencia de arrayContaining, que permite elementos adicionales en el array recibido.

Puedes comparar propiedades contra valores o contra otros matchers.

const houseForSale = {
bath: true,
bedrooms: 4,
kitchen: {
amenities: ['oven', 'stove', 'washer'],
area: 20,
wallColor: 'white',
},
};
const desiredHouse = {
bath: true,
kitchen: {
amenities: ['oven', 'stove', 'washer'],
wallColor: expect.stringMatching(/white|yellow/),
},
};

test('the house has my desired features', () => {
expect(houseForSale).toMatchObject(desiredHouse);
});
describe('toMatchObject applied to arrays', () => {
test('the number of elements must match exactly', () => {
expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}, {baz: 1}]);
});

test('.toMatchObject is called for each elements, so extra object properties are okay', () => {
expect([{foo: 'bar'}, {baz: 1, extra: 'quux'}]).toMatchObject([
{foo: 'bar'},
{baz: 1},
]);
});
});

.toMatchSnapshot(propertyMatchers?, hint?)

Esto asegura que un valor coincide con la instantánea más reciente. Consulta la guía de Snapshot Testing para más información.

Puedes proporcionar un argumento opcional propertyMatchers de tipo objeto, que contiene comparadores asimétricos como valores de un subconjunto de propiedades esperadas, si el valor recibido será una instancia de objeto. Es similar a toMatchObject con criterios flexibles para un subconjunto de propiedades, seguido de una prueba de instantánea como criterio exacto para las propiedades restantes.

Puedes proporcionar un argumento opcional hint (pista) de tipo cadena que se añade al nombre del test. Aunque Jest siempre añade un número al final del nombre de la instantánea, las pistas descriptivas breves pueden ser más útiles que números para diferenciar múltiples instantáneas en un único bloque it o test. Jest ordena las instantáneas por nombre en el archivo .snap correspondiente.

.toMatchInlineSnapshot(propertyMatchers?, inlineSnapshot)

Asegura que un valor coincide con la instantánea más reciente.

Puedes proporcionar un argumento opcional propertyMatchers de tipo objeto, que contiene comparadores asimétricos como valores de un subconjunto de propiedades esperadas, si el valor recibido será una instancia de objeto. Es similar a toMatchObject con criterios flexibles para un subconjunto de propiedades, seguido de una prueba de instantánea como criterio exacto para las propiedades restantes.

Jest añade el argumento de cadena inlineSnapshot al comparador en el archivo de prueba (en lugar de un archivo externo .snap) la primera vez que se ejecuta el test.

Consulta la sección sobre Inline Snapshots para más información.

.toStrictEqual(value)

Utiliza .toStrictEqual para verificar que los objetos tienen la misma estructura y tipo.

Diferencias con respecto a .toEqual:

  • se verifican las claves con propiedades undefined, ej. {a: undefined, b: 2} no será igual a {b: 2};

  • se consideran los elementos undefined, ej. [2] no será igual a [2, undefined];

  • se comprueba la dispersión en arrays, ej. [, 1] no será igual a [undefined, 1];

  • se verifican los tipos de objeto, ej. una instancia de clase con campos a y b no será igual a un objeto literal con campos a y b.

class LaCroix {
constructor(flavor) {
this.flavor = flavor;
}
}

describe('the La Croix cans on my desk', () => {
test('are not semantically the same', () => {
expect(new LaCroix('lemon')).toEqual({flavor: 'lemon'});
expect(new LaCroix('lemon')).not.toStrictEqual({flavor: 'lemon'});
});
});

.toThrow(error?)

También disponible como alias: .toThrowError(error?)

Utiliza .toThrow para comprobar que una función lanza un error al ser llamada. Por ejemplo, si queremos verificar que drinkFlavor('octopus') falla porque el sabor a pulpo es demasiado desagradable, podríamos escribir:

test('throws on octopus', () => {
expect(() => {
drinkFlavor('octopus');
}).toThrow();
});
consejo

Debes envolver el código en una función, de lo contrario el error no se capturará y la aserción fallará.

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

  • objeto de error: el mensaje de error es igual a la propiedad message del objeto

  • clase de error: el objeto de error es instancia de la clase

Por ejemplo, supongamos que drinkFlavor está implementada así:

function drinkFlavor(flavor) {
if (flavor === 'octopus') {
throw new DisgustingFlavorError('yuck, octopus flavor');
}
// Do some other stuff
}

Podríamos verificar que este error se lanza de varias formas:

test('throws on octopus', () => {
function drinkOctopus() {
drinkFlavor('octopus');
}

// Test that the error message says "yuck" somewhere: these are equivalent
expect(drinkOctopus).toThrow(/yuck/);
expect(drinkOctopus).toThrow('yuck');

// Test the exact error message
expect(drinkOctopus).toThrow(/^yuck, octopus flavor$/);
expect(drinkOctopus).toThrow(new Error('yuck, octopus flavor'));

// Test that we get a DisgustingFlavorError
expect(drinkOctopus).toThrow(DisgustingFlavorError);
});

.toThrowErrorMatchingSnapshot(hint?)

Utiliza .toThrowErrorMatchingSnapshot para comprobar que una función lanza un error que coincide con la instantánea más reciente al ser llamada.

Puedes proporcionar un argumento opcional hint (pista) de tipo cadena que se añade al nombre del test. Aunque Jest siempre añade un número al final del nombre de la instantánea, las pistas descriptivas breves pueden ser más útiles que números para diferenciar múltiples instantáneas en un único bloque it o test. Jest ordena las instantáneas por nombre en el archivo .snap correspondiente.

Por ejemplo, supongamos que tienes una función drinkFlavor que falla cuando el sabor es 'octopus', implementada así:

function drinkFlavor(flavor) {
if (flavor === 'octopus') {
throw new DisgustingFlavorError('yuck, octopus flavor');
}
// Do some other stuff
}

El test para esta función se vería así:

test('throws on octopus', () => {
function drinkOctopus() {
drinkFlavor('octopus');
}

expect(drinkOctopus).toThrowErrorMatchingSnapshot();
});

Y generará la siguiente instantánea:

exports[`drinking flavors throws on octopus 1`] = `"yuck, octopus flavor"`;

Consulta Pruebas de instantáneas de árboles de React para más información sobre pruebas de instantáneas.

.toThrowErrorMatchingInlineSnapshot(inlineSnapshot)

Utiliza .toThrowErrorMatchingInlineSnapshot para comprobar que una función lanza un error que coincide con la instantánea más reciente al ser llamada.

Jest añade el argumento de cadena inlineSnapshot al comparador en el archivo de prueba (en lugar de un archivo externo .snap) la primera vez que se ejecuta el test.

Consulta la sección sobre Inline Snapshots para más información.

Comparadores asimétricos

expect.anything()

expect.anything() coincide con cualquier valor excepto null o undefined. Puedes usarlo dentro de toEqual o toHaveBeenCalledWith en lugar de un valor literal. Por ejemplo, si quieres verificar que una función simulada (mock) fue llamada con un argumento no nulo:

test('map calls its argument with a non-null argument', () => {
const mock = jest.fn();
[1].map(x => mock(x));
expect(mock).toHaveBeenCalledWith(expect.anything());
});

expect.any(constructor)

expect.any(constructor) coincide con cualquier objeto creado con el constructor dado o con primitivos del tipo especificado. Puedes usarlo dentro de toEqual o toHaveBeenCalledWith en lugar de un valor literal. Por ejemplo, si quieres verificar que una función simulada fue llamada con un número:

class Cat {}
function getCat(fn) {
return fn(new Cat());
}

test('randocall calls its callback with a class instance', () => {
const mock = jest.fn();
getCat(mock);
expect(mock).toHaveBeenCalledWith(expect.any(Cat));
});

function randocall(fn) {
return fn(Math.floor(Math.random() * 6 + 1));
}

test('randocall calls its callback with a number', () => {
const mock = jest.fn();
randocall(mock);
expect(mock).toHaveBeenCalledWith(expect.any(Number));
});

expect.arrayContaining(array)

expect.arrayContaining(array) coincide con un array recibido que contiene todos los elementos del array esperado. Es decir, el array esperado es un subconjunto del array recibido. Por lo tanto, coincide incluso si el array recibido contiene elementos adicionales que no están en el array esperado.

Puedes usarla en lugar de un valor literal:

  • en toEqual o toHaveBeenCalledWith

  • para coincidir con una propiedad en objectContaining o toMatchObject

describe('arrayContaining', () => {
const expected = ['Alice', 'Bob'];
it('matches even if received contains additional elements', () => {
expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
});
it('does not match if received does not contain expected elements', () => {
expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected));
});
});
describe('Beware of a misunderstanding! A sequence of dice rolls', () => {
const expected = [1, 2, 3, 4, 5, 6];
it('matches even with an unexpected number 7', () => {
expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6]).toEqual(
expect.arrayContaining(expected),
);
});
it('does not match without an expected number 2', () => {
expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6]).not.toEqual(
expect.arrayContaining(expected),
);
});
});

expect.not.arrayContaining(array)

expect.not.arrayContaining(array) coincide con un array recibido que no contiene todos los elementos del array esperado. Es decir, el array esperado no es un subconjunto del array recibido.

Es el inverso de expect.arrayContaining.

describe('not.arrayContaining', () => {
const expected = ['Samantha'];

it('matches if the actual array does not contain the expected elements', () => {
expect(['Alice', 'Bob', 'Eve']).toEqual(
expect.not.arrayContaining(expected),
);
});
});

expect.closeTo(number, numDigits?)

expect.closeTo(number, numDigits?) es útil al comparar números de punto flotante en propiedades de objetos o elementos de arrays. Si necesitas comparar directamente un número, usa .toBeCloseTo.

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 es Math.abs(expected - received) < 0.005 (that is, 10 ** -2 / 2).

Por ejemplo, esta prueba pasa con una precisión 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.objectContaining(object)

expect.objectContaining(object) coincide con cualquier objeto recibido que contiene recursivamente las propiedades esperadas. Es decir, el objeto esperado es un subconjunto del objeto recibido. Por lo tanto, coincide incluso si el objeto recibido tiene propiedades adicionales que no están en el objeto esperado.

En lugar de valores literales, puedes usar otros comparadores como expect.anything() dentro del objeto esperado.

Por ejemplo, para verificar que se llamó a una función onPress con un objeto Event que tiene las propiedades event.x y event.y:

test('onPress gets called with the right thing', () => {
const onPress = jest.fn();
simulatePresses(onPress);
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({
x: expect.any(Number),
y: expect.any(Number),
}),
);
});

expect.not.objectContaining(object)

expect.not.objectContaining(object) coincide con cualquier objeto recibido que no contiene recursivamente todas las propiedades esperadas. Es decir, el objeto esperado no es un subconjunto del objeto recibido. Por lo tanto, coincide si el objeto recibido carece de alguna propiedad esperada o tiene valores diferentes.

Es la inversa de expect.objectContaining.

describe('not.objectContaining', () => {
const expected = {foo: 'bar'};

it('matches if the actual object does not contain expected key: value pairs', () => {
expect({bar: 'baz'}).toEqual(expect.not.objectContaining(expected));
});
});

expect.stringContaining(string)

expect.stringContaining(string) coincide con el valor recibido si es una cadena que contiene exactamente la cadena esperada.

expect.not.stringContaining(string)

expect.not.stringContaining(string) coincide con el valor recibido si no es una cadena o si es una cadena que no contiene exactamente la cadena esperada.

Es la inversa de expect.stringContaining.

describe('not.stringContaining', () => {
const expected = 'Hello world!';

it('matches if the received value does not contain the expected substring', () => {
expect('How are you?').toEqual(expect.not.stringContaining(expected));
});
});

expect.stringMatching(string | regexp)

expect.stringMatching(string | regexp) coincide con el valor recibido si es una cadena que coincide con la cadena o expresión regular esperada.

Puedes usarla en lugar de un valor literal:

  • en toEqual o toHaveBeenCalledWith

  • para coincidir con un elemento en arrayContaining

  • para coincidir con una propiedad en objectContaining o toMatchObject

Este ejemplo también muestra cómo puedes anidar múltiples comparadores asimétricos, con expect.stringMatching dentro de expect.arrayContaining.

describe('stringMatching in arrayContaining', () => {
const expected = [
expect.stringMatching(/^Alic/),
expect.stringMatching(/^[BR]ob/),
];
it('matches even if received contains additional elements', () => {
expect(['Alicia', 'Roberto', 'Evelina']).toEqual(
expect.arrayContaining(expected),
);
});
it('does not match if received does not contain expected elements', () => {
expect(['Roberto', 'Evelina']).not.toEqual(
expect.arrayContaining(expected),
);
});
});

expect.not.stringMatching(string | regexp)

expect.not.stringMatching(string | regexp) coincide con el valor recibido si no es una cadena o si es una cadena que no coincide con la cadena o expresión regular esperada.

Es la inversa de expect.stringMatching.

describe('not.stringMatching', () => {
const expected = /Hello world!/;

it('matches if the received value does not match the expected regex', () => {
expect('How are you?').toEqual(expect.not.stringMatching(expected));
});
});

Conteo de Aserciones

expect.assertions(number)

expect.assertions(number) verifica que se llame a cierto número de aserciones durante una prueba. Esto es útil cuando se prueba código asíncrono, para asegurarse de que las aserciones en un callback realmente se ejecuten.

Por ejemplo, supongamos que tenemos una función doAsync que recibe dos callbacks callback1 y callback2, y los llama asíncronamente en orden desconocido. Podemos probarlo así:

test('doAsync calls both callbacks', () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}

doAsync(callback1, callback2);
});

La llamada expect.assertions(2) asegura que ambos callbacks realmente se ejecuten.

expect.hasAssertions()

expect.hasAssertions() verifica que al menos una aserción sea llamada durante una prueba. Esto es útil cuando se prueba código asíncrono, para asegurarse de que las aserciones en un callback realmente se ejecuten.

Por ejemplo, supongamos que tenemos varias funciones que manejan estado. prepareState llama un callback con un objeto de estado, validateState opera sobre ese objeto, y waitOnState retorna una promesa que espera hasta que todos los callbacks de prepareState completen. Podemos probarlo así:

test('prepareState prepares a valid state', () => {
expect.hasAssertions();
prepareState(state => {
expect(validateState(state)).toBeTruthy();
});
return waitOnState();
});

La llamada expect.hasAssertions() asegura que el callback de prepareState realmente se ejecute.

Utilidades de Extensión

expect.addEqualityTesters(testers)

Puedes usar expect.addEqualityTesters para añadir tus propios métodos que prueben si dos objetos son iguales. Por ejemplo, supongamos que tienes una clase en tu código que representa volumen y puede determinar si dos volúmenes usando diferentes unidades son iguales. Puedes querer que toEqual (y otros comparadores de igualdad) usen este método personalizado al comparar clases Volume. Puedes añadir un tester de igualdad personalizado para que toEqual detecte y aplique lógica personalizada al comparar clases Volume:

Volume.js
// For simplicity in this example, we'll just support the units 'L' and 'mL'
export class Volume {
constructor(amount, unit) {
this.amount = amount;
this.unit = unit;
}

toString() {
return `[Volume ${this.amount}${this.unit}]`;
}

equals(other) {
if (this.unit === other.unit) {
return this.amount === other.amount;
} else if (this.unit === 'L' && other.unit === 'mL') {
return this.amount * 1000 === other.unit;
} else {
return this.amount === other.unit * 1000;
}
}
}
areVolumesEqual.js
import {expect} from '@jest/globals';
import {Volume} from './Volume.js';

function areVolumesEqual(a, b) {
const isAVolume = a instanceof Volume;
const isBVolume = b instanceof Volume;

if (isAVolume && isBVolume) {
return a.equals(b);
} else if (isAVolume === isBVolume) {
return undefined;
} else {
return false;
}
}

expect.addEqualityTesters([areVolumesEqual]);
__tests__/Volume.test.js
import {expect, test} from '@jest/globals';
import {Volume} from '../Volume.js';
import '../areVolumesEqual.js';

test('are equal with different units', () => {
expect(new Volume(1, 'L')).toEqual(new Volume(1000, 'mL'));
});

API de testers de igualdad personalizados

Los testers personalizados son funciones que retornan el resultado (true o false) de comparar la igualdad de dos argumentos dados, o undefined si el tester no maneja los objetos dados y quiere delegar la comparación a otros testers (por ejemplo, los testers de igualdad incorporados).

Los testers personalizados son llamados con 3 argumentos: los dos objetos a comparar y el array de testers personalizados (usado para testers recursivos, ver sección abajo).

Estas funciones auxiliares y propiedades pueden encontrarse en this dentro de un tester personalizado:

this.equals(a, b, customTesters?)

Esta es una función de igualdad profunda que devuelve true si dos objetos tienen los mismos valores (recursivamente). Opcionalmente acepta una lista de evaluadores de igualdad personalizados para aplicar en las comprobaciones de igualdad profunda. Si usas esta función, pasa los evaluadores personalizados que reciba tu evaluador para que las comprobaciones de igualdad posteriores que aplique equals también puedan usar los evaluadores personalizados que el autor de la prueba haya configurado. Consulta el ejemplo en la sección Evaluadores de igualdad personalizados recursivos para más detalles.

Comparadores frente a evaluadores

Los comparadores son métodos disponibles en expect, por ejemplo expect().toEqual(). toEqual es un comparador. Un evaluador es un método que usan los comparadores para realizar comprobaciones de igualdad y determinar si los objetos son iguales.

Los comparadores personalizados son útiles cuando quieres proporcionar una aserción personalizada que los autores de pruebas puedan usar en sus tests. Por ejemplo, el ejemplo toBeWithinRange en la sección expect.extend es un buen ejemplo de comparador personalizado. A veces un autor de pruebas querrá afirmar que dos números son exactamente iguales y debería usar toBe. Otras veces, sin embargo, querrá permitir cierta flexibilidad en su prueba, y toBeWithinRange sería una aserción más apropiada.

Los evaluadores de igualdad personalizados son útiles para extender globalmente los comparadores de Jest y aplicar lógica de igualdad personalizada en todas las comparaciones. Los autores de pruebas no pueden activar evaluadores personalizados para ciertas aserciones y desactivarlos para otras (si se desea ese comportamiento, debería usarse un comparador personalizado). Por ejemplo, definir cómo comprobar si dos objetos Volume son iguales para todos los comparadores sería un buen evaluador de igualdad personalizado.

Evaluadores de igualdad personalizados recursivos

Si tus evaluadores de igualdad personalizados comprueban objetos con propiedades donde quieres aplicar igualdad profunda, debes usar el ayudante this.equals disponible para los evaluadores de igualdad. Este método equals es el mismo que Jest usa internamente para todas sus comparaciones profundas. Es el método que invoca tu evaluador de igualdad personalizado. Acepta un array de evaluadores personalizados como tercer argumento. Los evaluadores personalizados también reciben un array de evaluadores como su tercer argumento. Pasa este argumento al tercer parámetro de equals para que las comprobaciones de igualdad más profundas también aprovechen los evaluadores personalizados.

Por ejemplo, imagina que tienes una clase Book que contiene un array de clases Author, y ambas clases tienen evaluadores personalizados. El evaluador personalizado de Book querría hacer una comprobación profunda del array de Author y pasarle los evaluadores personalizados que recibió, para que se aplique el evaluador de igualdad personalizado de Author:

customEqualityTesters.js
function areAuthorEqual(a, b) {
const isAAuthor = a instanceof Author;
const isBAuthor = b instanceof Author;

if (isAAuthor && isBAuthor) {
// Authors are equal if they have the same name
return a.name === b.name;
} else if (isAAuthor === isBAuthor) {
return undefined;
} else {
return false;
}
}

function areBooksEqual(a, b, customTesters) {
const isABook = a instanceof Book;
const isBBook = b instanceof Book;

if (isABook && isBBook) {
// Books are the same if they have the same name and author array. We need
// to pass customTesters to equals here so the Author custom tester will be
// used when comparing Authors
return (
a.name === b.name && this.equals(a.authors, b.authors, customTesters)
);
} else if (isABook === isBBook) {
return undefined;
} else {
return false;
}
}

expect.addEqualityTesters([areAuthorsEqual, areBooksEqual]);

Recuerda definir tus evaluadores de igualdad como funciones regulares, no como funciones flecha, para acceder a los ayudantes de contexto del evaluador (como this.equals).

expect.addSnapshotSerializer(serializer)

Puedes llamar a expect.addSnapshotSerializer para añadir un módulo que formatee estructuras de datos específicas de tu aplicación.

En un archivo de prueba individual, un módulo añadido tiene prioridad sobre los módulos de la configuración snapshotSerializers, que a su vez tienen prioridad sobre los serializadores predeterminados para tipos JavaScript nativos y elementos React. El último módulo añadido es el primer módulo que se prueba.

import serializer from 'my-serializer-module';
expect.addSnapshotSerializer(serializer);

// affects expect(value).toMatchSnapshot() assertions in the test file

Si añades un serializador de snapshots en archivos de prueba individuales en lugar de añadirlo a la configuración snapshotSerializers:

  • Haces la dependencia explícita en lugar de implícita.

  • Evitas límites de configuración que podrían forzarte a ejectuar create-react-app.

Consulta configuración de Jest para más información.

expect.extend(matchers)

Puedes usar expect.extend para añadir tus propios comparadores a Jest. Por ejemplo, imagina que estás probando una librería de utilidades numéricas y frecuentemente afirmas que los números están dentro de rangos específicos. Podrías abstraer esto en un comparador toBeWithinRange:

toBeWithinRange.js
import {expect} from '@jest/globals';

function toBeWithinRange(actual, floor, ceiling) {
if (
typeof actual !== 'number' ||
typeof floor !== 'number' ||
typeof ceiling !== 'number'
) {
throw new TypeError('These must be of type number!');
}

const pass = actual >= floor && actual <= ceiling;
if (pass) {
return {
message: () =>
`expected ${this.utils.printReceived(
actual,
)} not to be within range ${this.utils.printExpected(
`${floor} - ${ceiling}`,
)}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${this.utils.printReceived(
actual,
)} to be within range ${this.utils.printExpected(
`${floor} - ${ceiling}`,
)}`,
pass: false,
};
}
}

expect.extend({
toBeWithinRange,
});
__tests__/ranges.test.js
import {expect, test} from '@jest/globals';
import '../toBeWithinRange';

test('is within range', () => expect(100).toBeWithinRange(90, 110));

test('is NOT within range', () => expect(101).not.toBeWithinRange(0, 100));

test('asymmetric ranges', () => {
expect({apples: 6, bananas: 3}).toEqual({
apples: expect.toBeWithinRange(1, 10),
bananas: expect.not.toBeWithinRange(11, 20),
});
});
toBeWithinRange.d.ts
// optionally add a type declaration, e.g. it enables autocompletion in IDEs
declare module 'expect' {
interface AsymmetricMatchers {
toBeWithinRange(floor: number, ceiling: number): void;
}
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
}
}

export {};
consejo

La declaración de tipo del matcher puede estar en un archivo .d.ts o en un módulo .ts importado (ver ejemplos de JS y TS arriba respectivamente). Si guardas la declaración en un archivo .d.ts, asegúrate de que esté incluido en el programa y que sea un módulo válido, es decir, que tenga al menos un export {} vacío.

consejo

En lugar de importar el módulo toBeWithinRange al archivo de prueba, puedes habilitar el matcher para todas las pruebas moviendo la llamada expect.extend a un script setupFilesAfterEnv:

import {expect} from '@jest/globals';
// remember to export `toBeWithinRange` as well
import {toBeWithinRange} from './toBeWithinRange';

expect.extend({
toBeWithinRange,
});

Matchers Asíncronos

expect.extend también admite matchers asíncronos. Estos matchers devuelven una Promise, por lo que deberás esperar el valor devuelto. Usemos un matcher de ejemplo para ilustrar su uso. Vamos a implementar un matcher llamado toBeDivisibleByExternalValue, donde el número divisible se obtendrá de una fuente externa.

expect.extend({
async toBeDivisibleByExternalValue(received) {
const externalValue = await getExternalValueFromRemoteSource();
const pass = received % externalValue === 0;
if (pass) {
return {
message: () =>
`expected ${received} not to be divisible by ${externalValue}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${received} to be divisible by ${externalValue}`,
pass: false,
};
}
},
});

test('is divisible by external value', async () => {
await expect(100).toBeDivisibleByExternalValue();
await expect(101).not.toBeDivisibleByExternalValue();
});

API de Matchers Personalizados

Los matchers deben devolver un objeto (o una Promise de un objeto) con dos claves. pass indica si hubo coincidencia o no, y message proporciona una función sin argumentos que devuelve un mensaje de error en caso de fallo. Así, cuando pass es false, message debe devolver el mensaje de error para cuando falla expect(x).yourMatcher(). Y cuando pass es true, message debe devolver el mensaje de error para cuando falla expect(x).not.yourMatcher().

Los matchers se llaman con el argumento pasado a expect(x) seguido de los argumentos pasados a .yourMatcher(y, z):

expect.extend({
yourMatcher(x, y, z) {
return {
pass: true,
message: () => '',
};
},
});

Estas funciones y propiedades auxiliares están disponibles en this dentro de un matcher personalizado:

this.isNot

Un booleano que indica si este matcher fue llamado con el modificador negado .not, permitiéndote mostrar una pista de matcher clara y correcta (ver código de ejemplo).

this.promise

Una cadena que te permite mostrar una pista de matcher clara y correcta:

  • 'rejects' si el matcher fue llamado con el modificador .rejects de promesas

  • 'resolves' si el matcher fue llamado con el modificador .resolves de promesas

  • '' si el matcher no fue llamado con un modificador de promesas

this.equals(a, b, customTesters?)

Función de igualdad profunda que devuelve true si dos objetos tienen valores idénticos (recursivamente). Opcionalmente acepta una lista de testers de igualdad personalizados para aplicar en las comprobaciones (ver this.customTesters abajo).

this.expand

Booleano que indica si este matcher fue llamado con la opción expand. Cuando Jest se ejecuta con el flag --expand, this.expand determina si se deben mostrar diffs completos y errores detallados.

this.utils

Contiene herramientas útiles expuestas en this.utils, principalmente exportaciones de jest-matcher-utils.

Las más útiles son matcherHint, printExpected y printReceived para formatear mensajes de error claramente. Por ejemplo, observa la implementación del matcher toBe:

const {diff} = require('jest-diff');
expect.extend({
toBe(received, expected) {
const options = {
comment: 'Object.is equality',
isNot: this.isNot,
promise: this.promise,
};

const pass = Object.is(received, expected);

const message = pass
? () =>
// eslint-disable-next-line prefer-template
this.utils.matcherHint('toBe', undefined, undefined, options) +
'\n\n' +
`Expected: not ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(received)}`
: () => {
const diffString = diff(expected, received, {
expand: this.expand,
});
return (
// eslint-disable-next-line prefer-template
this.utils.matcherHint('toBe', undefined, undefined, options) +
'\n\n' +
(diffString && diffString.includes('- Expect')
? `Difference:\n\n${diffString}`
: `Expected: ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(received)}`)
);
};

return {actual: received, message, pass};
},
});

Esto imprimirá algo como:

  expect(received).toBe(expected)

Expected value to be (using Object.is):
"banana"
Received:
"apple"

Cuando una aserción falla, el mensaje de error debe dar suficientes pistas al usuario para resolver el problema rápidamente. Debes elaborar mensajes de fallo precisos para garantizar una buena experiencia a los desarrolladores que usen tus aserciones personalizadas.

this.customTesters

Si tu matcher realiza una comparación profunda usando this.equals, quizá quieras pasar testers personalizados proporcionados por el usuario a this.equals. Los testers de igualdad personalizados que el usuario haya agregado mediante la API addEqualityTesters están disponibles en esta propiedad. Los matchers incorporados de Jest pasan this.customTesters (junto con otros testers incorporados) a this.equals para realizar comparaciones profundas, y tus matchers personalizados podrían querer hacer lo mismo.

Matchers personalizados para snapshots

Para usar pruebas de snapshot dentro de tu matcher personalizado, puedes importar jest-snapshot y usarlo en tu matcher.

Este es un matcher para snapshots que recorta un string a una longitud específica, .toMatchTrimmedSnapshot(length):

const {toMatchSnapshot} = require('jest-snapshot');

expect.extend({
toMatchTrimmedSnapshot(received, length) {
return toMatchSnapshot.call(
this,
received.slice(0, length),
'toMatchTrimmedSnapshot',
);
},
});

it('stores only 10 characters', () => {
expect('extra long string oh my gerd').toMatchTrimmedSnapshot(10);
});

/*
Stored snapshot will look like:

exports[`stores only 10 characters: toMatchTrimmedSnapshot 1`] = `"extra long"`;
*/

También es posible crear matchers personalizados para snapshots en línea. Los snapshots se agregarán correctamente a los matchers personalizados. Sin embargo, los snapshots en línea siempre intentarán agregarse al primer argumento, o al segundo cuando el primero sea un property matcher, por lo que no es posible aceptar argumentos personalizados en los matchers personalizados.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
toMatchTrimmedInlineSnapshot(received, ...rest) {
return toMatchInlineSnapshot.call(this, received.slice(0, 10), ...rest);
},
});

it('stores only 10 characters', () => {
expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot();
/*
The snapshot will be added inline like
expect('extra long string oh my gerd').toMatchTrimmedInlineSnapshot(
`"extra long"`
);
*/
});

Asincronía

Si tu matcher personalizado para snapshots en línea es asíncrono (usa async-await), podrías encontrarte con errores como "No se admiten múltiples snapshots en línea para la misma llamada". Jest necesita información contextual adicional para ubicar dónde se usó el matcher personalizado y actualizar los snapshots correctamente.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
async toMatchObservationInlineSnapshot(fn, ...rest) {
// The error (and its stacktrace) must be created before any `await`
this.error = new Error();

// The implementation of `observe` doesn't matter.
// It only matters that the custom snapshot matcher is async.
const observation = await observe(async () => {
await fn();
});

return toMatchInlineSnapshot.call(this, recording, ...rest);
},
});

it('observes something', async () => {
await expect(async () => {
return 'async action';
}).toMatchTrimmedInlineSnapshot();
/*
The snapshot will be added inline like
await expect(async () => {
return 'async action';
}).toMatchTrimmedInlineSnapshot(`"async action"`);
*/
});

Interrupción anticipada

Normalmente jest intenta verificar cada snapshot esperado en una prueba.

A veces no tiene sentido continuar la prueba si un snapshot anterior falló. Por ejemplo, cuando haces snapshots de una máquina de estados después de varias transiciones, puedes abortar la prueba si una transición produce un estado incorrecto.

En ese caso, puedes implementar un matcher personalizado para snapshots que lance un error ante la primera discrepancia, en lugar de recolectar todas las discrepancias.

const {toMatchInlineSnapshot} = require('jest-snapshot');

expect.extend({
toMatchStateInlineSnapshot(...args) {
this.dontThrow = () => {};

return toMatchInlineSnapshot.call(this, ...args);
},
});

let state = 'initial';

function transition() {
// Typo in the implementation should cause the test to fail
if (state === 'INITIAL') {
state = 'pending';
} else if (state === 'pending') {
state = 'done';
}
}

it('transitions as expected', () => {
expect(state).toMatchStateInlineSnapshot(`"initial"`);

transition();
// Already produces a mismatch. No point in continuing the test.
expect(state).toMatchStateInlineSnapshot(`"loading"`);

transition();
expect(state).toMatchStateInlineSnapshot(`"done"`);
});