Пользовательские сериализаторы

В Jest предусмотрена возможность создания собственных сериализаторов для сериализации объектов и их представления в тестах. Сериализация в Jest используется в основном для корректного отображения сложных объектов в выводе тестов, а также для более удобного сравнения значений при ассертах. Стандартные сериализаторы справляются с большинством случаев, но иногда нужно обеспечить особое представление для специфичных объектов. В таких ситуациях на помощь приходят пользовательские сериализаторы.

Что такое сериализатор?

Сериализатор — это функция, которая отвечает за преобразование значений в строку, которая будет выведена в отчетах Jest. Это важно для объектов, таких как даты, регулярные выражения, Map, Set, и другие нестандартные структуры данных. Стандартные сериализаторы Jest автоматически приводят эти объекты к строковому виду, который может быть не очень удобным для восприятия.

Создание пользовательского сериализатора позволяет:

  • Настроить вывод специфичных типов данных.
  • Улучшить читаемость отчетов тестов.
  • Оптимизировать работу с большими или сложными объектами.

Как создать пользовательский сериализатор

Чтобы создать пользовательский сериализатор, необходимо использовать API Jest. Основной принцип работы заключается в том, чтобы определить функцию, которая будет обрабатывать объект и возвращать строковое представление этого объекта. Для этого Jest предоставляет метод expect.addSnapshotSerializer, который позволяет добавить сериализатор для выбранного типа данных.

Пример базового сериализатора:

expect.addSnapshotSerializer({
  test: (val) => val instanceof MyCustomClass,
  print: (val) => `Custom object with id: ${val.id}`,
});

Здесь test — это функция, которая проверяет, подходит ли объект для данного сериализатора. В данном случае мы проверяем, является ли объект экземпляром MyCustomClass. Если это так, то используется метод print, который форматирует вывод.

Тестирование с пользовательскими сериализаторами

Когда сериализатор добавлен, Jest будет автоматически использовать его для всех объектов, которые соответствуют условию в функции test. Это значит, что вам не нужно вручную менять код тестов, чтобы воспользоваться преимуществами нового сериализатора. Когда объект передается в Jest для сравнения, он будет сначала обработан через ваш сериализатор, а затем выведен в отчет.

Пример использования:

class MyCustomClass {
  constructor(id) {
    this.id = id;
  }
}

expect.addSnapshotSerializer({
  test: (val) => val instanceof MyCustomClass,
  print: (val) => `Custom object with id: ${val.id}`,
});

test('test custom serializer', () => {
  const myObj = new MyCustomClass(123);
  expect(myObj).toMatchSnapshot();
});

В этом примере объект myObj будет сериализован с помощью пользовательского сериализатора, и в итоговом снимке будет выведено “Custom object with id: 123”.

Когда использовать пользовательские сериализаторы

Пользовательские сериализаторы особенно полезны в следующих случаях:

  1. Работа с нестандартными объектами. Например, если в тестах используются объекты с нестандартными методами или свойствами, которых нет в стандартных типах данных JavaScript.
  2. Оптимизация вывода. Если стандартное представление объекта слишком громоздкое или неудобное для восприятия, можно настроить сериализацию для упрощения отображения.
  3. Поддержка специфичных библиотек. Когда в проекте используются библиотеки с собственными типами данных, которые требуют особого форматирования в выводах тестов.

Расширение сериализаторов

Для сложных типов данных или коллекций, таких как Map, Set или WeakMap, можно создать сериализаторы, которые будут правильно отображать их содержимое, а не просто выводить внутреннее представление объектов.

Пример сериализатора для Map:

expect.addSnapshotSerializer({
  test: (val) => val instanceof Map,
  print: (val) => {
    const items = [];
    val.forEach((value, key) => {
      items.push(`${key}: ${value}`);
    });
    return `Map(${items.join(', ')})`;
  },
});

Этот сериализатор форматирует объекты Map в виде Map(key1: value1, key2: value2), что делает вывод гораздо более читабельным, чем стандартный вывод, например, [Map] или [object Map].

Сериализация ошибок и исключений

Ошибки в JavaScript (например, объекты Error) тоже можно сериализовать по-своему, чтобы их вывод в отчетах был более информативным.

Пример для сериализации объекта Error:

expect.addSnapshotSerializer({
  test: (val) => val instanceof Error,
  print: (val) => `Error: ${val.message} (stack: ${val.stack})`,
});

Этот сериализатор выводит сообщение ошибки и стек вызовов, что помогает понять, что произошло при выполнении теста.

Очистка и сброс сериализаторов

В случае, если нужно удалить пользовательский сериализатор, Jest предоставляет метод expect.removeSnapshotSerializer. Это позволяет сбросить все изменения и вернуться к стандартным сериализаторам.

Пример:

expect.removeSnapshotSerializer(customSerializer);

Таким образом, можно гибко управлять сериализаторами, добавляя и удаляя их в зависимости от требований проекта.

Рекомендации по использованию

  • Минимизация сложности. Сериализаторы должны быть простыми и направленными на улучшение читабельности тестов. Чем проще и понятнее будет вывод, тем легче будет анализировать результаты тестирования.
  • Тестирование сериализаторов. Важно проверять работу сериализаторов в тестах. Это гарантирует, что они правильно обрабатывают все типы данных и корректно выводятся в отчетах.
  • Поддержка многократного использования. Создавайте универсальные и повторно используемые сериализаторы, которые могут быть применены к разным типам данных в проекте.

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