Expect в основном используется для реализации операций проверки. Expect Jest предоставляет следующие методы проверки:
Вы используете функцию «ожидание» всякий раз, когда хотите проверить значение. Вероятно, вы редко будете вызывать функцию «ожидание». Вместо этого вы будете использовать функцию «ожидание» и «сопоставитель», чтобы утверждать что-то о значении. Для облегчения понимания мы предполагаем, что у вас есть метод bestLaCroixFlavor(), ожидаемый результат которого:
test('the best flavor is grapefruit', () => {
expect(bestLaCroixFlavor()).toBe('grapefruit');
});
В приведенном выше примере toBe — это функция сопоставления. Чтобы помочь вам протестировать различный контент, Jest предоставляет множество различных функций сопоставления. Аргументы Expect должны быть значениями, сгенерированными кодом, а любые аргументы соответствующей программы должны быть правильными значениями.
Вы можете добавить свои собственные средства сопоставления в Jest, используя ожидаемое.extend. Например, предположим, что вы тестируете теоретическую библиотеку и часто утверждаете, что числа делятся на другие числа, вы можете абстрагировать это в сопоставитель toBeDivisibleBy.
expect.extend({
toBeDivisibleBy(received, argument) {
const pass = received % argument == 0;
if (pass) {
return {
message: () =>
`expected ${received} not to be divisible by ${argument}`,
pass: true,
};
} else {
return {
message: () => `expected ${received} to be divisible by ${argument}`,
pass: false,
};
}
},
});
test('even and odd numbers', () => {
expect(100).toBeDivisibleBy(2);
expect(101).not.toBeDivisibleBy(2);
expect({apples: 6, bananas: 3}).toEqual({
apples: expect.toBeDivisibleBy(2),
bananas: expect.not.toBeDivisibleBy(2),
});
});
ожидаемое.extends также поддерживает асинхронные сопоставления, которые возвращают обещание, поэтому вам нужно дождаться возвращенного значения. Давайте воспользуемся примером сопоставления, чтобы проиллюстрировать их использование. Вместо toBeDivisibleBy мы собираемся реализовать очень похожий механизм сопоставления, с той лишь разницей, что делимые числа будут извлекаться из внешнего источника.
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();
});
Сопоставитель должен возвращать объект (или обещание объекта) с обоими ключами. pass указывает, есть ли совпадение, а message предоставляет функцию без параметров, которая возвращает сообщение об ошибке в случае сбоя. Поэтому, если pass имеет значение false, сообщение должно возвращать сообщение об ошибке в случае сбоя ожидаемого(x).yourmatcher(). Если pass истинен, сообщение должно возвращать ожидаемое(x).no Сообщение об ошибке при сбое yourmatcher().
Возвращает true, если два объекта имеют одинаковое значение (рекурсивно). this.utils содержит много полезных инструментов, utils в основном состоит из экспорта из jest-matcher-utils. Наиболее полезными из них являются matcherHint, printExpected и printReceived, которые хорошо форматируют сообщения об ошибках.
const diff = require('jest-diff');
expect.extend({
toBe(received, expected) {
const pass = Object.is(received, expected);
const message = pass
? () =>
this.utils.matcherHint('.not.toBe') +
'\n\n' +
`Expected value to not be (using Object.is):\n` +
` ${this.utils.printExpected(expected)}\n` +
`Received:\n` +
` ${this.utils.printReceived(received)}`
: () => {
const diffString = diff(expected, received, {
expand: this.expand,
});
return (
this.utils.matcherHint('.toBe') +
'\n\n' +
`Expected value to be (using Object.is):\n` +
` ${this.utils.printExpected(expected)}\n` +
`Received:\n` +
` ${this.utils.printReceived(received)}` +
(diffString ? `\n\nDifference:\n\n${diffString}` : '')
);
};
return {actual: received, message, pass};
},
});
Выполнение приведенного выше кода приведет к появлению следующего сообщения об ошибке:
expect(received).toBe(expected)
Expected value to be (using Object.is):
"banana"
Received:
"apple"
В случае сбоя утверждения сообщение об ошибке должно предоставлять пользователю столько сигналов, сколько необходимо, чтобы пользователь мог быстро решить проблему. Поэтому вам следует написать точное сообщение об ошибке, чтобы гарантировать, что пользователи пользовательских утверждений получат хороший опыт разработки.
Он соответствует чему угодно, кроме null или неопределенного. Вы можете использовать toEqual или toBeCalledWith вместо литеральных значений. Например, если вы хотите проверить, была ли вызвана фиктивная функция и ее аргументы были ненулевыми:
test('map calls its argument with a non-null argument', () => {
const mock = jest.fn();
[1].map(x => mock(x));
expect(mock).toBeCalledWith(expect.anything());
});
Соответствует всему, что создано данным конструктором. Вы можете использовать toEqual или toBeCalledWith вместо литеральных значений. Например, если вы хотите проверить, была ли вызвана фиктивная функция с номером.
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).toBeCalledWith(expect.any(Number));
});
Соответствует полученному массиву, содержащему все элементы ожидаемого массива, т. е. ожидаемый массив является подмножеством полученного массива, поэтому он соответствует полученному массиву, содержащему элементы, не являющиеся частью ожидаемого массива.
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),
);
});
});
Проверяет, что во время теста вызывается определенное количество утверждений. Это часто бывает полезно при тестировании асинхронного кода, чтобы гарантировать, что утверждения в обратных вызовах действительно вызываются. Предположим, у нас есть функция doAsync, которая получает два обратных вызова callback1 и callback2 и вызывает их асинхронно в неизвестном порядке.
test('doAsync calls both callbacks', () => {
expect.assertions(2);
function callback1(data) {
expect(data).toBeTruthy();
}
function callback2(data) {
expect(data).toBeTruthy();
}
doAsync(callback1, callback2);
});
Убедитесь, что во время теста было вызвано хотя бы одно утверждение. Это часто бывает полезно при тестировании асинхронного кода, чтобы убедиться, что утверждения в обратных вызовах действительно вызываются.
Предположим, у нас есть некоторые функции, которые обрабатывают состояние: «prepreState» вызывает обратный вызов для объекта состояния, validateState выполняется для этого объекта состояния, а waitOnState возвращает обещание до тех пор, пока все обратные вызовы «prepreState» не будут завершены.
test('prepareState prepares a valid state', () => {
expect.hasAssertions();
prepareState(state => {
expect(validateState(state)).toBeTruthy();
});
return waitOnState();
});
Соответствует полученному массиву, который не содержит элементов ожидаемого массива. То есть ожидаемый массив не является подмножеством полученного массива, что противоположно ожидаемому.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),
);
});
});
Соответствует любому принимающему объекту, который не соответствует ожидаемому свойству рекурсивно. Это означает, что ожидаемый объект не является подмножеством принимающего объекта. Таким образом, он соответствует полученному объекту, содержащему свойства, не являющиеся частью ожидаемого объекта. Это противоположность ожидаемому объекту.
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));
});
});
Соответствует полученной строке, которая не содержит точной ожидаемой строки, что противоположно ожидаемому.stringContaining.
describe('not.stringContaining', () => {
const expected = 'Hello world!';
it('matches if the actual string does not contain the expected substring', () => {
expect('How are you?').toEqual(expect.not.stringContaining(expected));
});
});
Соответствует полученной строке, которая не соответствует ожидаемому регулярному выражению, что противоположно ожидаемому.stringMatching.
describe('not.stringMatching', () => {
const expected = /Hello world!/;
it('matches if the actual string does not match the expected regex', () => {
expect('How are you?').toEqual(expect.not.stringMatching(expected));
});
});
Соответствует любому принимающему объекту, который рекурсивно соответствует ожидаемому свойству. То есть ожидаемый объект является подмножеством полученного объекта. Таким образом, он соответствует полученному объекту, содержащему свойства, не являющиеся частью ожидаемого объекта.
Вместо того, чтобы ожидать в объектах буквальных значений свойств, вы можете использовать сопоставители, ожидаемые.anything() и так далее. Предположим, мы хотим использовать объект события для вызова функции onPress. Нам нужно проверить, имеет ли событие атрибуты event.x и атрибуты y.
test('onPress gets called with the right thing', () => {
const onPress = jest.fn();
simulatePresses(onPress);
expect(onPress).toBeCalledWith(
expect.objectContaining({
x: expect.any(Number),
y: expect.any(Number),
}),
);
});
Соответствует полученной строке, соответствующей ожидаемому регулярному выражению, которое можно использовать вместо буквального значения:
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),
);
});
});
toBe просто проверяет, соответствует ли значение вашим ожиданиям. Если он использует объект, он проверяет точное равенство.
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');
});
});
Если вы хотите проверить, имеют ли два объекта одинаковое значение, используйте .toequal. Этот сопоставитель рекурсивно проверяет все поля на равенство вместо проверки идентификаторов объектов — это также называется «глубоким равенством». Например, toEqual и toBe ведут себя в этом наборе тестов по-разному, поэтому все тесты проходят успешно.
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);
});
});
Используйте .tomatobject, чтобы проверить, соответствует ли объект JavaScript подмножеству свойств объекта. Он сопоставит полученный объект со свойствами, которых нет в ожидаемом объекте.
Вы также можете передать массив объектов, и в этом случае метод будет работать только в том случае, если каждый объект в полученном массиве (в смысле объекта Tomato, описанном выше) соответствует соответствующему объекту в ожидаемом массиве. Возврат true. Это полезно, если вы хотите проверить совпадение двух массивов по количеству элементов, вместо arrayinclude, поскольку позволяет добавлять дополнительные элементы в полученный массив.
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 arrays', () => {
test('the number of elements must match exactly', () => {
expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}, {baz: 1}]);
});
// .arrayContaining "matches a received array which contains elements that
// are *not* in the expected array"
test('.toMatchObject does not allow extra elements', () => {
expect([{foo: 'bar'}, {baz: 1}]).toMatchObject([{foo: 'bar'}]);
});
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},
]);
});
});
Используйте .tohaveproperty, чтобы проверить, существует ли свойство объекта в указанном ссылочном ключевом пути. Чтобы проверить глубоко вложенные свойства объекта, вы можете использовать точечную запись или массив, содержащий ключевой путь с глубокой ссылкой.
При желании вы можете указать значение, чтобы проверить, равно ли оно значению в keyPath целевого объекта. Этот сопоставитель использует «глубокое равенство» (например, toEqual()) и рекурсивно проверяет все поля на равенство.
Следующий пример содержит объект houseForSale с вложенными свойствами. Мы используем атрибут tohave для проверки существования и значения различных свойств объекта.
const houseForSale = {
bath: true,
bedrooms: 4,
kitchen: {
amenities: ['oven', 'stove', 'washer'],
area: 20,
wallColor: 'white',
'nice.oven': true,
},
};
test('this house has my desired features', () => {
// Simple 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(['kitchen', 'nice.oven']);
expect(houseForSale).not.toHaveProperty(['kitchen', 'open']);
});
другой: Модульное фронтенд-тестирование Jest Фермент, среда тестирования React Серия синтаксисов тестов Globals of Jest Серия синтаксиса тестов Jest — Matchers