#javascript #karma-runner #service-worker
Вопрос:
У меня есть набор интеграционных тестов, которые выполняются в Карме. К сожалению, они обращаются к внешней конечной точке производственного API. Я не хочу, чтобы интеграционные тесты вызывали и изучали мои варианты.
Мне интересно, являются ли работники сферы услуг жизнеспособным решением. Я предполагаю, что они не работают, потому что https://github.com/w3c/ServiceWorker/issues/1188 дает понять, что извлечение из разных источников не поддерживается, и localhost не является тем же источником, что и конечная точка производственного API.
Для ясности, вот некоторый код, который я запускаю:
try {
const { scope, installing, waiting, active } = await navigator.serviceWorker.register('./base/htdocs/test/imageMock.sw.js');
console.log('ServiceWorker registration successful with scope: ', scope, installing, waiting, active);
(installing || waiting || active).addEventListener('statechange', (e) => {
console.log('state', e.target.state);
});
} catch (error) {
console.error('ServiceWorker registration failed: ', error);
}
и работник сферы обслуживания
// imageMock.sw.js
if (typeof self.skipWaiting === 'function') {
console.log('self.skipWaiting() is supported.');
self.addEventListener('install', (e) => {
// See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-global-scope-skipwaiting
e.waitUntil(self.skipWaiting());
});
} else {
console.log('self.skipWaiting() is not supported.');
}
if (self.clients amp;amp; (typeof self.clients.claim === 'function')) {
console.log('self.clients.claim() is supported.');
self.addEventListener('activate', (e) => {
// See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#clients-claim-method
e.waitUntil(self.clients.claim());
});
} else {
console.log('self.clients.claim() is not supported.');
}
self.addEventListener('fetch', (event) => {
console.log('fetching resource', event);
if (/.jpg$/.test(event.request.url)) {
const response = new Response('<p>This is a response that comes from your service worker!</p>', {
headers: { 'Content-Type': 'text/html' },
});
event.respondWith(response);
}
});
и когда этот код запускается, я вижу в консоли
ServiceWorker registration successful with scope: http://localhost:9876/base/htdocs/test/ null null ServiceWorker
и затем запросы https://<productionServer>.com/image.php
не перехватываются обработчиком выборки.
Правильно ли, что в этом сценарии нет способа перехватить?
Ответ №1:
Вы можете использовать работника службы для перехвата запросов, сделанных браузером в рамках набора тестов. Пока сотрудник службы контролирует веб-страницу, он может перехватывать запросы разных источников и генерировать любой желаемый ответ.
(Проблема, на которую вы ссылаетесь по поводу «внешней выборки», — это нечто другое; думайте об этом как об удаленном производственном сервере, развертывающем своего собственного работника службы. Это было заброшено.)
«Прекратите издеваться над выборкой» — это всеобъемлющая статья, в которой рассказывается о том, как использовать библиотеку msw
service worker в контексте набора тестов.
Я не могу сказать с уверенностью, почему ваша текущая настройка не работает, но по прошлому опыту я могу сказать, что самое важное, что нужно помнить при этом, — это то, что вам нужно отложить выполнение любых запросов с тестовой страницы клиента до тех пор, пока сама страница не будет контролироваться активным сотрудником службы. В противном случае существует состояние гонки, при котором вы можете в конечном итоге отправить запрос, который должен вызвать fetch
обработчик, но не будет выполнен, если работник службы еще не контролирует ситуацию.
Вы можете подождать, пока это произойдет с помощью такой логики, как:
const controlledPromise = new Promise((resolve) => {
// Resolve right away if this page is already controlled.
if (navigator.serviceWorker.controller) {
resolve();
} else {
navigator.serviceWorker.addEventListener('controllerchange', () => {
resolve();
});
}
});
await controlledPromise;
// At this point, the page will be controlled by a service worker.
// You can start making requests at this point.
Обратите внимание, что в этом случае использования await navigator.serviceWorker.ready
вы не будете вести себя так, как вам нужно, так как может возникнуть промежуток времени между тем, когда navigator.serviceWorker.ready
обещание будет выполнено, и тем, когда недавно активированный сотрудник службы возьмет под контроль текущую страницу. Вы не хотите, чтобы этот промежуток времени привел к ошибочным тестам.