https://jestjs.io/docs/expect

  • toBe использует Object.is для проверки точного равенства. Если вы хотите проверить значение объекта, используйте вместо этого toEqual
test('two plus two is four', () => {
  expect(2 + 2).toBe(4);
});
test('object assignment', () => {
  const data = {one: 1};
  data['two'] = 2;
  expect(data).toEqual({one: 1, two: 2});
});
  • проверять строки на соответствие регулярным выражениям с помощью toMatch
test('there is no I in team', () => {
  expect('team').not.toMatch(/I/);
});
test('but there is a "stop" in Christoph', () => {
  expect('Christoph').toMatch(/stop/);
});
  • проверьте, содержит ли массив или итерируемый объект определенный элемент, используя toContain
test('the shopping list has beer on it', () => {
  expect(shoppingList).toContain('beer');
  expect(new Set(shoppingList)).toContain('beer');
});

Асинхронный код

Когда у вас есть код, который выполняется асинхронно, Jest должен знать, когда код, который он тестирует, завершен, прежде чем он сможет перейти к другому тесту.

Вы хотите проверить, что эти возвращенные данные являются строкой «арахисовое масло».

// Don't do this!
test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter');
  }
  fetchData(callback);
});
// Promises
test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});
test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});
// Async - Await
test('the data is peanut butter', async () => {
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
  expect.assertions(1);
  try {
    await fetchData();
  } catch (e) {
    expect(e).toMatch('error');
  }
});
  • Пример

Давайте реализуем модуль, который извлекает пользовательские данные из API и возвращает имя пользователя.

// user.js
import request from './request';
export function getUserName(userID) {
  return request('/users/' + userID).then(user => user.name);
}

В приведенной выше реализации мы ожидаем, что модуль request.js вернет обещание. Мы связываем вызов с then, чтобы получить имя пользователя.

Теперь представьте реализацию request.js, которая обращается к сети и извлекает некоторые пользовательские данные:

// request.js
const http = require('http');
export default function request(url) {
  return new Promise(resolve => {
    http.get({path: url}, response => {
      let data = '';
      response.on('data', _data => (data += _data));
      response.on('end', () => resolve(data));
    });
  });
}

Поскольку в нашем тесте мы не хотим подключаться к сети, мы собираемся вручную создать макет для нашего модуля request.js в папке __mocks__.

// __mocks__/request.js
const users = {
  4: {name: 'Mark'},
  5: {name: 'Paul'},
};
export default function request(url) {
  return new Promise((resolve, reject) => {
    const userID = parseInt(url.substr('/users/'.length), 10);
    process.nextTick(() =>
      users[userID]
        ? resolve(users[userID])
        : reject({
            error: 'User with ' + userID + ' not found.',
          }),
    );
  });
}
// __tests__/user-test.js
jest.mock('../request');
import * as user from '../user';
// The assertion for a promise must be returned.
it('works with promises', () => {
  expect.assertions(1);
  return user.getUserName(4).then(data => expect(data).toEqual('Mark'));
});

Мы вызываем jest.mock(‘../request’), чтобы указать Jest использовать наш ручной макет. it ожидает, что возвращаемое значение будет обещанием, которое будет разрешено.

Настройка повторного теста

По умолчанию блоки before и after применяются к каждому тесту в файле. Вы также можете сгруппировать тесты вместе, используя блок describe. Когда они находятся внутри блока describe, блоки before и after применяются только к тестам внутри этого блока describe.

// Applies to all tests in this file
beforeEach(() => {
  return initializeCityDatabase();
});
test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});
describe('matching cities to foods', () => {
  // Applies only to tests in this describe block
  beforeEach(() => {
    return initializeFoodDatabase();
  });
  test('Vienna <3 sausage', () => {
    expect(isValidCityFoodPair('Vienna', 'Wiener Würstchen')).toBe(true);
  });
  test('San Juan <3 plantains', () => {
    expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
  });
});
beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));
test('', () => console.log('1 - test'));
describe('Scoped / Nested block', () => {
  beforeAll(() => console.log('2 - beforeAll'));
  afterAll(() => console.log('2 - afterAll'));
  beforeEach(() => console.log('2 - beforeEach'));
  afterEach(() => console.log('2 - afterEach'));
  test('', () => console.log('2 - test'));
});
// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 - afterAll
  • Чтобы запустить только один тест с помощью Jest, временно измените эту тестовую команду на test.only.
test.only('this will be the only test that runs', () => {
  expect(true).toBe(false);
});
test('this test will not run', () => {
  expect('A').toBe('A');
});

Тестирование моментальных снимков

Вместо рендеринга графического пользовательского интерфейса, который потребовал бы создания всего приложения, вы можете использовать тестовый рендерер, чтобы быстро сгенерировать сериализуемое значение для вашего дерева React.

Артефакт моментального снимка должен быть зафиксирован вместе с изменениями кода. При последующих тестовых запусках Jest будет просто сравнивать отрендеренный вывод с предыдущим снимком. Если они совпадают, тест пройден. Если они не совпадают, то либо реализация изменилась, и снапшот нужно обновить с помощью jest -u, либо программа запуска теста обнаружила ошибку в вашем коде, которую следует исправить.

Теперь вы знаете, что нужно либо принять изменения с помощью jest -u, либо исправить компонент, если изменения были непреднамеренными.

https://jestjs.io/blog/2016/07/27/jest-14

// Link.react.test.js
import React from 'react';
import renderer from 'react-test-renderer';
import Link from '../Link.react';
test('Link changes the class when hovered', () => {
  const component = renderer.create(
    <Link page="<http://www.facebook.com>">Facebook</Link>,
  );
  let tree = component.toJSON();
  expect(tree).toMatchSnapshot();
  // manually trigger the callback
  tree.props.onMouseEnter();
  // re-rendering
  tree = component.toJSON();
  expect(tree).toMatchSnapshot();
  // manually trigger the callback
  tree.props.onMouseLeave();
  // re-rendering
  tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});
// __tests__/__snapshots__/Link.react.test.js.snap
exports[`Link changes the class when hovered 1`] = `
<a
  className="normal"
  href="<http://www.facebook.com>"
  onMouseEnter={[Function]}
  onMouseLeave={[Function]}>
  Facebook
</a>
`;
exports[`Link changes the class when hovered 2`] = `
<a
  className="hovered"
  href="<http://www.facebook.com>"
  onMouseEnter={[Function]}
  onMouseLeave={[Function]}>
  Facebook
</a>
`;
exports[`Link changes the class when hovered 3`] = `
<a
  className="normal"
  href="<http://www.facebook.com>"
  onMouseEnter={[Function]}
  onMouseLeave={[Function]}>
  Facebook
</a>
`;

Поскольку мы только что обновили наш компонент, чтобы он указывал на другой адрес, разумно ожидать изменений в моментальном снимке для этого компонента. Наш тестовый пример моментального снимка терпит неудачу, потому что моментальный снимок для нашего обновленного компонента больше не соответствует артефакту моментального снимка для этого тестового примера.

Чтобы решить эту проблему, нам нужно будет обновить наши артефакты моментальных снимков. Вы можете запустить Jest с флагом, который сообщит ему о повторной генерации снимков jest -u