<p>jest.clearAllMocks(); не удаляет фиктивную реализацию в `afterEach`</p>

Созданный на 10 окт. 2018  ·  44Комментарии  ·  Источник: facebook/jest

🐛 Отчет об ошибке

jest.clearAllMocks(); не удаляет фиктивную реализацию в пределах afterEach

Воспроизвести

У меня есть файл с именем src/layouts/index.js

// ./src/layouts/index.js
const importAll = (r) =>
    r.keys().reduce(
        (acc, key) => ({
            ...acc,
            [key.replace(/^\.\/(.*).json$/, '$1')]: r(key)
        }),
        {}
    );

module.exports = importAll(require.context('./', true, /\.json$/));

Он использует веб-пакет require.context поэтому я пытаюсь издеваться над jest.mock.

У меня есть другой файл... скажем, файл util.js

//./src/util.js
import layouts from '../layouts';
export const getLayout(name) {
  return layouts[name];
}

в моем тесте я пытаюсь очистить макеты после каждого теста

//./src/util.test.js
describe('my test suite', () => {
  afterEach(() => {
     jest.clearAllMocks();
  })
  test('test number one', () => {
      jest.mock('./layouts', () => ({
          layout1 : { a : 1 },
          layout2 : { b: 2 },
     }));
     assert.equals(getLayout('layout1').a, 1);
     assert.equals(getLayout('layout2').b, 2);
  });
  test('test number two', () => {
     assert.equals(getLayout('layout1').a, 1);
     assert.equals(getLayout('layout2').b, 2);
  });
});

Ожидаемое поведение

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

Ссылка на repl или repo (настоятельно рекомендуется)

https://repl.it/@CharlieHoover/SorrowfulBackSandboxes

Самый полезный комментарий

К вашему сведению, насмешливая документация и API крайне неясны и слишком сложны ИМХО.

Все 44 Комментарий

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

К вашему сведению, насмешливая документация и API крайне неясны и слишком сложны ИМХО.

jest.clearAllMocks не удаляет фиктивные реализации по замыслу — попробуйте jest.resetAllMocks

Вот соответствующие документы:


Все еще не работает с resetAllMocks:

Пример включает:

https://repl.it/@CharlieHoover/SorrowfulBackSandboxes-2

Кроме того, что это очень двусмысленно. Почему функция под названием clearAllMocks не очищает моки... Назовите функцию resetMockState или что-то более описательное. clearAllMocks означает, что макеты очищаются.

@rickhanlonii мой вопрос еще не решен. Я хочу удалить мокасины.

Ах, да, похоже, что resetAllMocks не сбрасывает фиктивные _module factory_, а только реализации, установленные mockImplementation. Если вы хотите опубликовать то, что вы хотите сделать, в stackoverflow, я могу помочь вам сделать то, что вы хотите, но это не похоже на то, что здесь есть ошибка.

Почему функция под названием clearAllMocks не очищает макеты

Я думаю, что путаница в том, что «макет» в «clearAllMocks» не относится к фиктивным реализациям, он относится к фиктивным объектам Jest. Таким образом, эта функция означает «очистить все фиктивные объекты шутки», то есть вызвать .mockClear для всех фиктивных объектов (т.е. очистить вызовы)

@rickhanlonii

omg, так что # 1 кажется, что «очистить» и «сбросить» используются противоположно их логическому значению.

Кроме того, совершенно ясно, что он пытается сделать; удалите фиктивную реализацию, и вы говорите, что нет способа сделать это или ррр.....?????

Это должно быть вновь открыто

+1

+1

+1

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

+1

тоже борюсь с этим!

+1, пожалуйста, обновите документы, чтобы объяснить, как УДАЛИТЬ макет/шпион

+1, пожалуйста, обновите документы, чтобы объяснить, как УДАЛИТЬ макет/шпион

Разве не для этого предназначен mockRestore? https://jestjs.io/docs/en/mock-function-api#mockfnmockrestore

Я думаю, что конфигурация по умолчанию должна включать:

{
  restoreMocks: true,
  clearMocks: true,
  resetMocks: true
} 

Шокирует то, что поведение по умолчанию — рвота между тестами. Не могли бы вы оставить мои тесты изолированными по умолчанию? Затем [надеющееся меньшинство], которое хочет распространить состояние на несколько тестов, может сделать это, подписавшись.

`
описать('тест', () => {
перед каждым (() => {
const WelcomeService = require('./../SOME_MODULE')
WelcomeServiceSpyOfMessage = jest.spyOn(
Добро пожаловатьСервис,
'сообщение', // какая-то функция, над которой я издевался
)
const IsUserAuthentic = требуется ('./../SOME_MODULE')
IsUserAuthenticSpyOnIsUserAuthentic = jest.spyOn(
IsUserAuthentic,
'isUserAuthentic' // какая-то функция, над которой я издевался
)
app = require('../src/server') // мой сервер Express
})

afterEach(() => {
  jest.restoreAllMocks()
})

it('1. Mock implementation', async () => {
  const mockedMessage = faker.lorem.sentence()
  WelcomeServiceSpyOfMessage.mockImplementation(() => mockedMessage)
  IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => {
    console.log('>>> MOCKED MW 1')
    return true
  })
  const result = await request(app)
    .get('/api')
  expect(result.statusCode).toBe(200)
  expect(result.body).toHaveProperty('message', mockedMessage)
})

it('2. After restored implementation', async () => {
  IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => {
    console.log('>>> MOCKED MW 2')
    return true
  })
  const result = await request(app)
    .get('/api')
  expect(result.statusCode).toBe(200)
  expect(result.body).toHaveProperty('message', 'hello world')
})

})
`
Вывод:
console.log тест/routes.test.js:36

насмехается над мв 1

console.log тест/routes.test.js:36

насмехается над мв 1

Для обоих тестов вызывается одна и та же имитированная версия функции. Хотя я восстановил все макеты в вызове равно вызывается один и тот же макет. Подскажите, пожалуйста, где я пропустил.

Спасибо

+1 🥂

+1

+1
Мне кажется, что очистка макетов после каждого теста должна быть поведением по умолчанию.

+1
Мне кажется, что очистка макетов после каждого теста должна быть поведением по умолчанию.

+1

функции, имитированные с помощью .spyOn() могут быть восстановлены: jest.spyOn(object, method).mockImplementation(mockFunction) .

Я согласен с тем, что макеты должны автоматически очищаться между тестами.

+1

+1

Есть ли решение этой проблемы? +1

Столкнулся с такой же проблемой!

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

// jestUtil.js
const mockArr = [];
export function doAMock(moduleName, cb = null) {
  if (!mockArr.includes(moduleName)) {
    mockArr.push(moduleName);
  }
  if (cb) {
    jest.doMock(moduleName, cb);
  } else {
    jest.doMock(moduleName);

  }
}

export function removeAllMock() {
  mockArr.forEach(m => {
    jest.dontMock(m);
  });
  mockArr.length = 0;
}


// usage
// other.test.js
import * as jsUtil from './jestUtil.js';
jsUtil.doAMock('module');
jsUtil.removeAllMock();

IMO, это очень запутанное название API, и оно заслуживает того, чтобы его переименовали.

IMO, это очень запутанное название API, и оно заслуживает того, чтобы его переименовали.

да, полностью согласен - но мне все еще интересно, возможно ли это в настоящее время - не говоря уже об именах. Если да, то как?

Это действительно должно быть исправлено. Нет причин, по которым один модульный тест должен влиять на другой. Кто-нибудь нашел жизнеспособный обходной путь? Действительно странный функционал.

РЕДАКТИРОВАТЬ: Решение @damien-roche для обновления jest.config.js сработало хорошо, плюс добавлен мой вызов Class.mockImplementation в хуке beforeEach:

beforeEach(() => {
        CommunicationApi.mockImplementation(() => {
          return {
            getMessagePosition() {
              return new Promise(resolve => {
                resolve({
                  ok: true,
                  Id: '123',
                  json: function () {
                    return null
                  }
                });
              });
            },
            getMessageOptions() {
              return Promise.resolve(expectedMessageOptions);
            },
          };
        });
        getters = createGetters(baseGetters);
        wrapper = createWrapper(getters, actions)
      });

Кто-нибудь когда-нибудь собирается что-то делать с этим? Я также сталкиваюсь с той же проблемой.

Это все еще проблема

У меня тоже проблема с этим.

Для тех, кто сталкивается с этим, я установил флаг командной строки --restoreMocks который также можно установить в jest.config.js :

   restoreMocks: true,

По умолчанию для моих тестов, чтобы макеты всегда восстанавливались после запуска теста. Вот ссылка на документацию: https://jestjs.io/docs/en/configuration#restoremocks -boolean

Согласитесь, это странное значение по умолчанию, которое сохраняет состояние между модульными тестами.

@ewhauser у меня не

вы уверены, что это работает для вас?

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

Я только что наткнулся на mockRestore , который работает, если вы используете spyOn .

Делает все, что делает mockFn.mockReset(), а также восстанавливает исходную (не издевательскую) реализацию.

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

Имейте в виду, что mockFn.mockRestore работает только тогда, когда макет был создан с помощью jest.spyOn. Таким образом, вы должны сами позаботиться о восстановлении при ручном назначении jest.fn().

Параметр конфигурации restoreMocks доступен для автоматического восстановления макетов между тестами.

https://jestjs.io/docs/en/mock-function-api#mockfnmockrestore

Я нашел это полезным. Вызывайте эту функцию с ожиданием каждый раз сразу после того, как ожидается вызов фальшивой fn.

flushAllPromises() { return new Promise(resolve => setImmediate(resolve)); }

Это должно заставить работать последний вызов YourClass.yourFunction.mockResolvedValue() в выполняющемся тестовом примере вместо того, чтобы полагаться на разрешенное значение последнего выполненного модульного теста.

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

Эти API необходимо переименовать. Соглашаться на плохое название из-за инерции, по меньшей мере, непрофессионально.

Ребята, это полнейшая некомпетентность. Я использую Jest не по своему выбору, я использую его, потому что вы сделали его популярным. Этот вопрос был открыт с октября 2018 года. Вы просто оказываете медвежью услугу сообществу, которому пытаетесь служить..? Соберись.

Эти API необходимо переименовать. Соглашаться на плохое название из-за инерции, по меньшей мере, непрофессионально.

Я согласен, что это «непрофессионально», я и все остальные, кто поддерживал Jest за последние ~ 2 года, делали это в свободное время, поэтому не профессионально. Но я бы не стал говорить о «некомпетентности».
В любом случае, пожалуйста, не используйте трекер ошибок для комментариев не по теме или (успешных или неудачных) оскорблений; такие комментарии будут скрыты или о них будет сообщено.

Для меня jest.restoreAllMocks(); помог окончательно очистить шпиона на шутку

Была ли эта страница полезной?
0 / 5 - 0 рейтинги