Подтвердить что ты не робот

Издевательские глобалы в Jest

Есть ли какой-либо способ в Jest, чтобы имитировать глобальные объекты, такие как navigator или Image *? Я в значительной степени отказался от этого и оставил его до целого ряда макетируемых методов утилиты. Например:

// Utils.js
export isOnline() {
    return navigator.onLine;
}

Тестирование этой крошечной функции прост, но круто и не детерминировано вообще. Я могу получить 75% пути, но это примерно так, насколько я могу:

// Utils.test.js
it('knows if it is online', () => {
    const { isOnline } = require('path/to/Utils');

    expect(() => isOnline()).not.toThrow();
    expect(typeof isOnline()).toBe('boolean');
});

С другой стороны, если я согласен с этим направлением, теперь я могу получить доступ к navigator с помощью этих утилит:

// Foo.js
import { isOnline } from './Utils';

export default class Foo {
    doSomethingOnline() {
        if (!isOnline()) throw new Error('Not online');

        /* More implementation */            
    }
}

... и детерминистически протестируйте вот так...

// Foo.test.js
it('throws when offline', () => {
    const Utils = require('../services/Utils');
    Utils.isOnline = jest.fn(() => isOnline);

    const Foo = require('../path/to/Foo').default;
    let foo = new Foo();

    // User is offline -- should fail
    let isOnline = false;
    expect(() => foo.doSomethingOnline()).toThrow();

    // User is online -- should be okay
    isOnline = true;
    expect(() => foo.doSomethingOnline()).not.toThrow();
});

Из всех тестовых фреймворков, которые я использовал, Jest чувствует себя как самое полное решение, но каждый раз, когда я пишу неудобный код, чтобы сделать его доступным для тестирования, я чувствую, что мои инструменты тестирования меня подведут.

Это единственное решение или мне нужно добавить Rewire?

* Не ухмыляйтесь. Image является фантастическим для проверки удаленного сетевого ресурса.

4b9b3361

Ответ 1

Поскольку каждый набор тестов запускает свою собственную среду, вы можете имитировать глобальные переменные, просто перезаписывая их. Все глобальные переменные могут быть доступны из пространства имен global.

global.navigator = {
  onLine: true
}

Перезапись влияет только на текущий тест и не влияет на других. Это также хороший способ справиться с Math.random или Date.now

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

Object.defineProperty(globalObject, key, { value, writable: true });

Ответ 2

Jest, возможно, изменился, так как принятый ответ был написан, но Jest, кажется, не сбрасывает ваш глобальный после тестирования. Пожалуйста, ознакомьтесь с прилагаемыми тестами.

https://repl.it/repls/DecentPlushDeals

Насколько я знаю, единственный способ обойти это с помощью afterEach() или afterAll(), чтобы очистить ваши назначения на global.

Ответ 3

Если кому-то нужно смоделировать глобальный со статическими свойствами, мой пример может помочь:

beforeAll(() => {
    global.EventSource = jest.fn().mockImplementation(() => ({
      readyState: 0,
      close: jest.fn()
    }))

    global.EventSource.CONNECTING = 0
    global.EventSource.OPEN = 1
    global.EventSource.CLOSED = 2
  })

Ответ 4

Если вы используете react-testing-library и используете метод cleanup, предоставляемый библиотекой. Он удалит все глобальные объявления, сделанные в этом файле, после выполнения всех тестов в файле. Это не будет перенесено на другие тесты.

пример:

import { cleanup } from 'react-testing-library'

afterEach(cleanup)

global.getSelection = () => {

}

describe('test', () => {
  expect(true).toBeTruthy()
})