Почему один из моих JEST-макетов не работает, а другой работает нормально? - PullRequest
0 голосов
/ 14 октября 2019

Я определил 2 JEST-макета. Проблема, которую я получаю. Первый макет не работает, а второй работает.

import Helper from '../../test-helper'

import Storage from '@/storage'
import GuestContext from '@/auth/guest-context'
import UserContext from '@/auth/user-context'

// import LocalStorageGateway from '@/storage/local/local-storage-gateway'
const mockContextUpsert = jest.fn()

jest.mock('@/storage/local/local-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext,
            context: {
                upsert: mockContextUpsert
            }
        }
    })
})

// import RemoteStorageGateway from '@/storage/remote/remote-storage-gateway'
const mockFetch = jest.fn()

jest.mock('@/storage/remote/remote-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext,
            fetch: mockFetch
        }
    })
})

Я пытался ...

  • Закомментировал второе определение макета
  • Переключениеorders
  • Использование mockFetch в первом макете вместо mockContentUpsert (после, конечно, перемещения определения mockFetch вверх).
  • Создание первого макета в качестве полной копии второгос изменением только строки '@ / storage / local / local-storage-gateway'.

Я получаю ошибку ...

ReferenceError: mockContextUpsertне определено

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

Это также будет работать, добавляя переменные макета во второе объявление (не имеет никакого смысла, так как это разные классы, но для справки) ...

const mockContextUpsert = jest.fn()
const mockFetch = jest.fn()

jest.mock('@/storage/remote/remote-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext: authContext,
            fetch: mockFetch,
            context: {
                upsert: mockContextUpsert
            }
        }
    })
})

Пересматриваемые здесь классы почти идентичны.

ОБНОВЛЕНИЕ

Удаление ссылки на GuestContext() [это дополнительное осложнение, имеетОн был удален и сбивает с толку фактическую проблему, которую пытается задать вопрос]

Ответы [ 2 ]

0 голосов
/ 17 октября 2019

В конце концов, я решил эту проблему - проблема не в самих макетах, а в том, что имитируется класс.

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

const guestLocal = new LocalStorageGateway(new GuestContext())

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

Есть несколько способов обойти это ...

Вы можете изменить это ...

import Helper from '../../test-helper'

import Storage from '@/storage'
import GuestContext from '@/auth/guest-context'
import UserContext from '@/auth/user-context'

(insert mocks here)

на ...

const mockContextUpsert = jest.fn()

import Helper from '../../test-helper'

import Storage from '@/storage'
import GuestContext from '@/auth/guest-context'
import UserContext from '@/auth/user-context'

например(юк?).

В качестве альтернативы вы можете заключить mockContextUpsert в функцию обтекания (мой ранее не очень хороший ответ) -> Мне это немного чище.

const mockContextUpsert = jest.fn()
jest.mock('@/storage/local/local-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext: authContext,
            context: {
                upsert: (cxt) => {
                    mockContextUpsert(cxt)
                }
            }
        }
    })
})

Я также мог бы сделать guestLocal функцией, но на самом деле я не хочу этого делать и создавать новые экземпляры шлюза каждый раз, когда я хочу его использовать (именно поэтому он существует). Если бы Storage был классом, он был бы создан в конструкторе, но это не так и не нужно.

Спасибо @Teneff за его вклад в этот вопрос, его ответ заставил мой мозг взглянуть наэто правильный путь. переменные не подняты был ключевым - они работают по-другому - я действовал неправильно, понимая, что все, что называется mockXXXX, будет поднято над ложными вызовами, но это не так, они просто «разрешены».

0 голосов
/ 17 октября 2019

Цитата из документации jest :

Jest автоматически поднимет вызовы jest.mock в верхнюю часть модуля (перед любым импортом)

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

Что вы можете сделать, это создать автоматическое макетирование

import localStorageGateway from '@/storage/local/local-storage-gateway';
jest.mock('@/storage/local/local-storage-gateway');

// and since localStorageGateway is a function 
// jest will automatically create jest.fn() for it
// so you will be able to create authContext
const authContext = new GuestContext();

// and use it within the return value
localStorageGateway.mockReturnValue({
  authContext,
  context: {
    upsert: jest.fn(),
  }
})
...