Почему эти заглушки sinon разрешаются до undefined? - PullRequest
0 голосов
/ 07 августа 2020

Я написал модульный тест для следующего кода и заглушил методы браузера (читай: API веб-расширения) с помощью Sinon (точнее: sinon- chrome, устаревший, но все еще работающий библиотеки для моего варианта использования).

/**
 * Returns an array of languages based on getAcceptLanguages and getUILanguage to use as defaults
 * for when no saved languages exist in browser storage.
 *
 * @memberof Helpers
 * @returns {array} Array of language codes i.e. ['en-US', 'fr']
 */
async function getDefaultLanguages () {
  const acceptedLanguages = await browser.i18n.getAcceptLanguages()
  const uiLanguage = browser.i18n.getUILanguage()

  return [uiLanguage].concat(acceptedLanguages)
}

Модульный тест:

const sinon = require('sinon')
const browser = require('sinon-chrome/extensions')
const { assert } = require('chai')
const helpers = require('../src/helpers')

// helpers that rely on the web-extension API (will need to be mocked)
describe('Helpers: Web-Extension API', function () {
  const { getDefaultLanguages } = helpers

  let languages

  before(async function () {
    global.browser = browser // need to patch global browser with mocked api
    browser.menus = browser.contextMenus // sinon-chrome doesn't wrap this method as it should
    
    sinon.stub(browser.i18n, 'getAcceptLanguages').resolves(['de-de', 'en-au'])
    sinon.stub(browser.i18n, 'getUILanguage').returns('en-en')

    languages = await getDefaultLanguages()
  })

  it('asserts that getDefaultLanguages() returns an array of strings', function () {
    assert.isTrue(languages.every(x => typeof x === 'string'))
  })

  it('asserts that getDefaultLanguages() includes UI and i18n languages', function () {
    assert.sameMembers(languages, ['de-de', 'en-en', 'en-au'])
  })
})

Тесты завершаются неудачно из-за того, что оба заглушенных метода возвращают undefined, но состояние Sinon docs совершенно очевидно, что stub.resolves(value):

Заставляет заглушку возвращать Promise, которое разрешается до предоставленного значения.

При создании Promise sinon использует метод Promise.resolve . Вы несете ответственность за предоставление полифиллов в средах, которые не предоставляют Promise. Библиотеку Promise можно перезаписать с помощью метода usingPromise.

Поскольку узел имеет встроенную поддержку Promise, я ожидаю, что указанные выше заглушки разрешатся с указанными значениями (массив строк локали и строка локали ), но оба разрешают / возвращают undefined.

Буду признателен за помощь с этим!

1 Ответ

0 голосов
/ 10 августа 2020

Оказывается, sinon- chrome по какой-то причине должен зарегистрировать плагин i18n во время выполнения и до запуска тестов.

Почему эта c часть API веб-расширений не реализован таким же образом, как и все остальные макеты, остается загадкой, но добавление двух строк устранило проблему и позволило заглушкам sinon работать должным образом:

const sinon = require('sinon')
const browser = require('sinon-chrome/extensions')
const I18nPlugin = require('sinon-chrome/plugins').I18nPlugin // I18n plugin constructor
const { assert } = require('chai')
const helpers = require('../src/helpers')

// helpers that rely on the web-extension API (will need to be mocked)
describe('Helpers: Web-Extension API', function () {
  const { getDefaultLanguages } = helpers

  let languages

  before(async function () {
    global.browser = browser // need to patch global browser with mocked api
    browser.menus = browser.contextMenus // sinon-chrome doesn't wrap this method as it should
    browser.registerPlugin(new I18nPlugin()) // register the plugin on browser instance
    
    sinon.stub(browser.i18n, 'getAcceptLanguages').resolves(['de-de', 'en-au'])
    sinon.stub(browser.i18n, 'getUILanguage').returns('en-en')

    languages = await getDefaultLanguages()
  })
})

Sinon- chrome выдает ошибку типа если вы пытаетесь шпионить за несуществующим свойством объекта или если данное свойство не является функцией. К сожалению, он не вызывает никаких ошибок и просто возвращает undefined, если пытается заглушить несуществующее свойство объекта, что кажется плохим выбором дизайна.

Вот почему заглушки returns() и resolves(), в исходном коде возвращается undefined.

...