Jest: как отменить глобальную подделку для определенных тестов в файле

Я хочу издеваться над Math.random для определенных тестов и использовать его оригинальную реализацию для других тестов. Как я могу этого добиться? Я читал об использовании jest.doMock и jest.dontMock, но столкнулся с рядом проблем при их использовании, например:

  • Кажется, мне нужно require, чтобы использовать doMock и dontMock, но мой проект использует только модули ES6 для импорта модулей
  • У этих функций также есть проблемы с глобальным модулем, таким как Math. Я получаю сообщение об ошибке при попытке использовать jest.doMock("Math.random"), что результаты в Cannot find module 'Math' from 'app.test.js'

Мне не обязательно использовать doMock и dontMock для моих тестов. Они просто казались наиболее близкими вещами, которые я мог найти в документации по шуткам, к тому, чего я хочу достичь. Но я открыт для альтернативных решений.

Моя функция, которую я хочу протестировать внутри app.js...

export function getRandomId(max) {
    if (!Number.isInteger(max) || max <= 0) {
        throw new TypeError("Max is an invalid type");
    }
    return Math.floor(Math.random() * totalNumPeople) + 1;
}

Внутри app.test.js...

describe("getRandomId", () => {
  const max = 10;
  Math.random = jest.fn();

  test("Minimum value for an ID is 1", () => {
      Math.mockImplementationOnce(() => 0);
      const id = app.getRandomId(max);
      expect(id).toBeGreaterThanOrEqual(1);
  });

  test("Error thrown for invalid argument", () => {
      // I want to use the original implementation of Math.random here
      expect(() => getRandomId("invalid")).toThrow();
  })
});
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
1 004
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуй это:

describe("getRandomId", () => {
  const max = 10;
  let randomMock;

  beforeEach(() => {
    randomMock = jest.spyOn(global.Math, 'random');
  });

  test("Minimum value for an ID is 1", () => {
      randomMock.mockReturnValue(0);
      const id = getRandomId(max);
      expect(id).toBeGreaterThanOrEqual(1);
  });

  test("Error thrown for invalid argument", () => {
      // I want to use the original implementation of Math.random here
      randomMock.mockRestore(); // restores the original (non-mocked) implementation
      expect(() => getRandomId("invalid")).toThrow();
  })
});

Спасибо, это было очень полезно! Однако я заметил странное поведение при использовании mockRestore во втором тесте. Из любопытства захотелось посмотреть, что же вернул Math.random после восстановления randomMock. Поэтому я поставил expect(randomMock).toHaveReturnedWith(20), чтобы сделать тест непройденным и посмотреть, что Math.Random на самом деле вернул. Как ни странно, тест провалился, потому что Math.Random вообще не вызывался.

Eric 22.12.2020 20:05

Если я вместо этого использую mockReturnValueOnce(0) для первого теста и заменю mockRestore на mockClear во втором тесте, проблема будет решена. Результаты показывают, что Math.Random вызывается с исходной реализацией. Вы случайно не знаете, почему mockRestore не вызвали Math.Random?

Eric 22.12.2020 20:05

Причина, по которой это работает с вашей модификацией, заключается в том, что mockReturnValueOnce(0) восстановит макет после первого вызова Math.random. Восстановление randomMock просто означает, что любые последующие вызовы Math.random() не будут имитироваться. но randomMock больше нельзя использовать, так как он потерял привязку к Math.random

Christian 23.12.2020 10:23

Вы можете проверить, что ответ работает должным образом, добавив console.info(getRandomId(42) в оба теста (после насмешки в первом тесте и после восстановления во втором тесте). Запуск теста всегда будет печатать 1 в первом тесте и случайное целое число (в заданных границах) во втором случае.

Christian 23.12.2020 10:28

Это хорошо знать! Я не понимал, что randomMock потеряет свою привязку к Math.Random после вызова mockRestore. Я также смог проверить это поведение при запуске моих тестов. Спасибо за объяснение.

Eric 24.12.2020 00:44

Другие вопросы по теме