Z tego poradnika dowiesz się, jak tworzyć bardziej niezawodne rozszerzenia, testując za pomocą Puppeteer zakończenie działania wątku usługi. Przygotowanie na rozwiązanie w każdej chwili czas jest ważny, ponieważ może to nastąpić bez ostrzeżenia i w wyniku nietrwałego stanu gdy następuje utrata skryptu service worker. W związku z tym rozszerzenia muszą zapisywać ważne stany i być w stanie obsługiwać żądania, gdy tylko zostaną ponownie uruchomione, jeśli jest jakieś zdarzenie do obsłużenia.
Zanim rozpoczniesz
Skopiuj lub sklonuj repozytorium chrome-extensions-samples.
Użyjemy testowego rozszerzenia /functional-samples/tutorial.terminate-sw/test-extension
, które wysyła wiadomość do workera usługowego za każdym razem, gdy klikniesz przycisk, i dodaje tekst na stronie, jeśli otrzyma odpowiedź.
Musisz też zainstalować Node.js, czyli środowisko wykonawcze, na którym działa Puppeteer.
Krok 1. Uruchom projekt Node.js
Utwórz następujące pliki w nowym katalogu. Razem tworzą projektu Node.js i udostępniania podstawowej struktury pakietu testowego Puppeteer; podczas testowania biegu Jest. Więcej informacji o tej konfiguracji znajdziesz w artykule Testowanie rozszerzeń Chrome za pomocą Puppeteer.
package.json:
{
"name": "puppeteer-demo",
"version": "1.0",
"dependencies": {
"jest": "^29.7.0",
"puppeteer": "^22.1.0"
},
"scripts": {
"start": "jest ."
},
"devDependencies": {
"@jest/globals": "^29.7.0"
}
}
index.test.js:
const puppeteer = require('puppeteer');
const SAMPLES_REPO_PATH = 'PATH_TO_SAMPLES_REPOSITORY ';
const EXTENSION_PATH = `${SAMPLES_REPO_PATH}/functional-samples/tutorial.terminate-sw/test-extension`;
const EXTENSION_ID = 'gjgkofgpcmpfpggbgjgdfaaifcmoklbl';
let browser;
beforeEach(async () => {
browser = await puppeteer.launch({
// Set to 'new' to hide Chrome if running as part of an automated build.
headless: false,
args: [
`--disable-extensions-except=${EXTENSION_PATH}`,
`--load-extension=${EXTENSION_PATH}`
]
});
});
afterEach(async () => {
await browser.close();
browser = undefined;
});
Zwróć uwagę, że nasz test wczytuje test-extension
z repozytorium sample.
Moduł obsługi chrome.runtime.onMessage
korzysta ze stanu ustawionego w module obsługi
dla wydarzenia chrome.runtime.onInstalled
. W rezultacie zawartość pliku data
zostaną utracone po zakończeniu działania skryptu service worker i reagowaniu na ewentualne przyszłe
nie uda się wysłać wiadomości. Postaramy się rozwiązać ten problem po napisaniu testu.
service-worker-broken.js:
let data;
chrome.runtime.onInstalled.addListener(() => {
data = { version: chrome.runtime.getManifest().version };
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
sendResponse(data.version);
});
Krok 2. Zainstaluj zależności
Uruchom npm install
, aby zainstalować wymagane zależności.
Krok 3. Napisz test podstawowy
Dodaj poniższy test na dole strony index.test.js
. Spowoduje to otwarcie testowej strony z naszego testowego rozszerzenia, kliknięcie elementu przycisku i odczekanie na odpowiedź od service workera.
test('can message service worker', async () => {
const page = await browser.newPage();
await page.goto(`chrome-extension://${EXTENSION_ID}/page.html`);
// Message without terminating service worker
await page.click('button');
await page.waitForSelector('#response-0');
});
Możesz uruchomić test z użyciem parametru npm start
. Powinien on zakończyć się pomyślnie.
Krok 4. Zakończ działanie mechanizmu Service Worker
Dodaj tę funkcję pomocniczą, która zamyka skrypt service worker:
/**
* Stops the service worker associated with a given extension ID. This is done
* by creating a new Chrome DevTools Protocol session, finding the target ID
* associated with the worker and running the Target.closeTarget command.
*
* @param {Page} browser Browser instance
* @param {string} extensionId Extension ID of worker to terminate
*/
async function stopServiceWorker(browser, extensionId) {
const host = `chrome-extension://${extensionId}`;
const target = await browser.waitForTarget((t) => {
return t.type() === 'service_worker' && t.url().startsWith(host);
});
const worker = await target.worker();
await worker.close();
}
Na koniec zaktualizuj test, dodając ten kod. Teraz zakończ działanie usługi i ponownie kliknij przycisk, aby sprawdzić, czy otrzymasz odpowiedź.
test('can message service worker when terminated', async () => {
const page = await browser.newPage();
await page.goto(`chrome-extension://${EXTENSION_ID}/page.html`);
// Message without terminating service worker
await page.click('button');
await page.waitForSelector('#response-0');
// Terminate service worker
await stopServiceWorker(page, EXTENSION_ID);
// Try to send another message
await page.click('button');
await page.waitForSelector('#response-1');
});
Krok 5. Przeprowadź test
Uruchom npm start
. Test powinien zakończyć się niepowodzeniem, co oznacza, że skrypt service worker
nie odpowiedział po zamknięciu konta.
Krok 6. Napraw skrypt service worker
Następnie napraw skrypt service worker, usuwając jego zależność od stanu tymczasowego. Zaktualizuj rozszerzenie testowe, aby używać kodu, który znajduje się w service-worker-fixed.js
w repozytorium.
service-worker-fixed.js:
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.local.set({ version: chrome.runtime.getManifest().version });
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
chrome.storage.local.get('version').then((data) => {
sendResponse(data.version);
});
return true;
});
Tutaj zapisujemy wersję w wartości chrome.storage.local
zamiast w zmiennej globalnej, aby zachować stan między okresami działania usługi. Pamięć masowa może być
asynchronicznie, zwracamy również wartość „prawda” z detektora onMessage
do
aby wywołanie zwrotne sendResponse
było aktywne.
Krok 7. Uruchom test ponownie
Ponownie uruchom test za pomocą funkcji npm start
. Teraz powinno się udać.
Dalsze kroki
Tak samo możesz teraz zastosować do własnego rozszerzenia. Weź pod uwagę te kwestie:
- Utwórz zestaw testów, który będzie można uruchamiać z uwzględnieniem nieoczekiwanego zakończenia działania usługi. Możesz uruchomić oba tryby osobno, aby zwiększyć przejrzystość co spowodowało awarię.
- Napisać kod, który kończy działanie service workera w losowych momentach w ramach testu. Może to być dobry sposób na wykrywanie problemów, które są trudne do przewidzenia.
- Wyciągaj wnioski z porażek podczas testów i próbuj pisać kod w sposób zabezpieczający przed błędami. Możesz na przykład dodać regułę lintingu, aby zniechęcić do używania zmiennych globalnych i spróbować przenieść dane do bardziej trwałego stanu.