Перейти к основному содержимому

Внешняя среда

Запросы - это один из ключевых компонентов storyshots, работа с которым бывает не простой и требует особого внимания для сохранения качества тестирования.

Игнорирование query

🔧📈 Улучшает
🛡 Ухудшает

storyshots предоставляет методы для отслеживания вызовов функций, а именно журнал. Записывать можно абсолютно любой метод и тут зачастую возникает путаница. Рассмотрим пример:

const createMockUserRepository = (): UserRepository => {
return {
getUser: async () => createUserStub(),
};
};

UserRepository содержит метод getUser который не выполняет никаких сайд-эффектов в БД, но является недетерминированным. getUser относится к компоненту запросы - а значит данная функция не должна проверяться.

Вместо этого:

it('shows user', {
arrange: (externals, { journal }) => ({
...externals,
getUser: journal.asRecordable('getUser', externals.getUser),
}),
});

Делать это:

// Не маркировать метод getUser
it('shows user');

Отслеживание getUser является бессмысленным так как метод не выполняет сайд-эффект.

подсказка

Cайд-эффект - это не просто результат работы выходящий за пределы функции, в рамках спецификации это ещё и видимые сторонними клиентами данные:

  • Для сервера - это команды модифицирующие БД
  • Для пользователя - это функции рисующие интерфейс на экране

Такие внешние эффекты и фиксируются storyshots в эталоне.

Взаимодействие с getUser проверяется транзитивно, через отображение компонента в котором используются данные из метода:

const User: React.FC = () => {
const response = useQuery(userRepository.getUser);

if (response.loading) {
return <Preloader />;
}

return <UserInfo user={response.data} />;
};
Важно

У данного правила есть одно очень важное исключение - запросы, такие как getUser, хоть и не выполняют сайд-эффектов, однако могут реализовывать нетривиальную логику, опирающуюся на то, с какими аргументами был вызван метод.

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

Нестабильные представления

🛡 Улучшает
📈 Ухудшает

К сожалению, далеко не всегда существует возможность полного контроля над запросами приложения. Вследствие чего появляется вероятность получения нестабильного эталона.

подсказка

Примером может служить компонент сторонней библиотеки - нотификация, итоговая позиция которой при появлении не всегда одинаковая и из-за этого страдают снимки экрана.

В данного рода проблемой поможет справиться функция retries:

it('shows read notification', {
// У теста будет три попытки на успешное прохождение
retries: (config) => 3,
});
Внимание

Данный метод не рекомендуется использовать в общем случае. Следует либо подменить функцию виновника, либо целую библиотеку. Также можно исключить сам тестовый сценарий.

Таймеры

📈 Улучшает

UI интерфейсы полны асинхронных взаимодействий, частью которых являются таймеры.

Рассмотрим следующий пример:

// Показать уведомление
const notification = showMessage('Сообщение прочитано');

// Закрыть через 5 секунд
setTimeout(() => notification.close(), 5_000);

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

Вместо этого:

it('shows message to a user', {
act: (actor) => actor.screenshot('Message').wait(5_000).screenshot('Hidden'),
});

Делать это:

it('shows message to a user', {
act: (actor) =>
actor
.screenshot('Message')
// Отправить таймеры в будущее на 5 секунд вперёд
.exec(() => window.clock.tick(5_000))
.screenshot('Hidden'),
});

Функция wait из примера будет ожидать 5 секунд после чего продолжит выполнение теста. Это непозволительно, так как время выполнения теста - это крайне важная величина. Поэтому во втором примере используются ложные таймеры.

примечание

В данном примере используется библиотека @storyshots/web-api-mocks которая выполняет подмену через сайд-эффекты.

Внимание

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