Ошибка MobX-State-Tree: насмешливое действие возвращает ошибку vi.spy

У меня есть проект React/Typescript, в котором я использую MobX-State-Tree для управления состоянием. В одном из моих тестов (с использованием библиотеки тестирования Vitest + React) я имитировал функцию, определенную в одном из хранилищ в дереве состояний, поэтому я могу проверить ее вызов (она должна вызываться в useEffect при монтировании). Но тест работает неправильно.

Образец магазина:

const SampleStore = types.model({
   ...
}).actions(self => ({
   sample_action: flow(function* (param: string) {
     //sample async action call with yield
   })
})
...
export const sample_store = SampleStore.create()

Компонент:

// all imports

export const SampleComponentPage = () => {
  ....

  useEffect(() => {
    // the action from the store gets called here
    sample_store.sample_action(arg)
  }, [])

  return (
    ...
  )
})

Тестовый файл:

...

describe('Sample component page', () => {
  it('sample test case', async () => {
    const mock_action = vi.fn()

    const initialStore = SampleStore.create({
       sample_action: mock_action
    })

    render(
      <StoreContextProvider value = {initialStore}>
        <SampleComponentPage />
      </StoreContextProvider>
    )

    ...
    waitFor(() => expect(mock_action).toHaveBeenCalled())
    ...
  })
})

Оператор waitFor возвращает ложноположительный тест — тест проходит независимо, например, с toHaveBeenCalledTimes(10), даже если его нужно было вызвать только один раз.

Без waitFor, то есть вызова expect(mock_action).toHaveBeenCalled(), возвращается эта ошибка:

AssertionError: expected "spy" to be called once, but got 0 times

Я пробовал использовать vi.spyOn(initialStore, 'sample_action') для указания действия магазина на фиктивную функцию, но это возвращает ошибку, связанную с MST:

Error: [mobx-state-tree] Cannot modify 'AnonymousModel@/...', the object is protected and can only be modified by using an action.
 ❯ fail node_modules/mobx-state-tree/dist/mobx-state-tree.js:3901:12

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

Как вы назвали mock_action?

Lin Du 17.05.2024 04:42

попробуйте обернуть ваш рендер, например await act( async () => { render(<MyComponent/>, container) });

Edgar Ortega 17.05.2024 18:34

@LinDu фактическая функция — это действие, определенное в хранилище дерева состояний MobX, и оно вызывается в useEffect() компонента, где я оставил комментарий. mock_action — моя попытка издеваться над функцией, чтобы проверить, действительно ли она вызывается

Airah 19.05.2024 20:00

@EdgarOrtega не уверен, что вы имели в виду с помощью container, но использование await и async для рендеринга не работает

Airah 19.05.2024 20:01

@LinDu Я обновил вопрос для большей ясности, спасибо.

Airah 19.05.2024 20:28
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
5
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я столкнулся с аналогичной проблемой при переносе нашего набора тестов с jest на vitest. Модель по умолчанию защищена MobX-State-Tree и не может быть изменена напрямую, как указано в ошибке. Однако вы можете отключить это в своем тесте, позвонив unprotect(initialStore) перед vi.spyOn.

import { unprotect } from "mobx-state-tree";

it('sample test case', async () => {
  const initialStore = SampleStore.create(...);
  unprotect(initialStore);
  const spy = vi.spyOn(initialStore, 'submit_answer')
  expect(spy).toHaveBeenCalled();
});

Ознакомьтесь с документацией MobX-State-Tree Unprotect API.

Это работает, спасибо, но я надеялся, что есть способ не снимать защиту магазина😬 Есть еще какие-нибудь предложения?

Airah 03.07.2024 17:55

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