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

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

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

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

Выяснилось, что хороший двухкомпонентный тест должен выглядеть так:

(компонент страницы)

describe('message from page', function () {
  it('reaches background', async function () {
    let response = performOnBackground();
    sendMessage('test message');
    expect(await response).toBe('message arrived');
  });
});

(фоновый компонент)

describe('message from page', function () {
  body('reaches background', async function () {
    const msg = await messageListener.once('test message');
    return msg === 'test message' ? 'message arrived' : 'error';
  });
});

Одна из проблем заключалась в том, как сообщить performOnBackground, какой тест выполняется в данный момент, чтобы он мог найти соответствующее тело без дополнительных идентификаторов. Это можно решить, добавив дополнительный пользовательский репортер (репортеры обычно форматируют и выводят результаты теста):

jasmine.getEnv().addReporter({
  specStarted: function (desc) { markCurrentItName(desc); },
  suiteStarted: function (desc) { markCurrentDescribeName(desc); }, ...
});

Затем performOnBackground может просто опубликовать набор и имена тестов и дождаться результата выполнения. Фреймворк выполнения в фоновом режиме или другие компоненты — это вопрос нескольких строк, которые регистрируют тестовые тела:

function describe(suiteName, suiteBody) {
  tests[suiteName] = {};
  currentSuite = tests[suiteName];
  suiteBody();
}
function body(testName, testBody) {
  currentSuite[testName] = testBody;
}
function onRunTestCallback(descriptor, sendResponse) {
  var result = tests[descriptor.suiteName][descriptor.testName]();
  if (result && typeof result.then === 'function') {
    result.then(sendResponse);
  }
  else {
    sendResponse(result);
  }
}

И в этом почти весь трюк. Тесты, написанные в таком стиле, позволяли за считанные минуты находить и исправлять некогда загадочные ошибки и предотвращали регрессии. Полный код доступен на github.

Первоначально опубликовано на сайте pavelstudeny.wordpress.com 6 декабря 2018 г.