In diesem Leitfaden erfahren Sie, wie Sie robustere Erweiterungen erstellen, indem Sie die Beendigung von Dienstarbeitern mit Puppeteer testen. Es ist wichtig, jederzeit auf die Beendigung vorbereitet zu sein, da dies ohne Warnung passieren kann und nicht persistente Status im Dienstarbeiter verloren gehen. Daher müssen Erweiterungen wichtigen Status speichern und Anfragen verarbeiten können, sobald sie wieder gestartet werden, wenn ein Ereignis verarbeitet werden muss.
Vorbereitung
Klonen Sie das Repository chrome-extensions-samples oder laden Sie es herunter.
Wir verwenden die Testerweiterung in /functional-samples/tutorial.terminate-sw/test-extension
, die jedes Mal, wenn auf eine Schaltfläche geklickt wird, eine Nachricht an den Service Worker sendet und der Seite Text hinzufügt, wenn eine Antwort empfangen wird.
Außerdem müssen Sie Node.JS installieren, die Laufzeit, auf der Puppeteer basiert.
Schritt 1: Node.js-Projekt starten
Erstellen Sie die folgenden Dateien in einem neuen Verzeichnis. Gemeinsam erstellen sie ein neues Node.js-Projekt erstellen und die Grundstruktur einer Puppeteer-Testsuite bereitstellen Verwenden Sie Jest als Test-Runner. Weitere Informationen zu dieser Konfiguration finden Sie unter Chrome-Erweiterungen mit Puppeteer testen.
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;
});
Beachten Sie, dass in unserem Test die test-extension
aus dem Samples-Repository geladen wird.
Der Handler für chrome.runtime.onMessage
basiert auf dem Status, der im Handler festgelegt wurde
für das chrome.runtime.onInstalled
-Ereignis. Daher wird der Inhalt von data
gehen verloren, wenn der Service Worker beendet wird und auf zukünftige Anfragen
schlagen fehl. Wir beheben das Problem, nachdem wir den Test geschrieben haben.
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);
});
Schritt 2: Abhängigkeiten installieren
Führen Sie npm install
aus, um die erforderlichen Abhängigkeiten zu installieren.
Schritt 3: Einen einfachen Test schreiben
Fügen Sie den folgenden Test am Ende von index.test.js
hinzu. Damit wird der Test geöffnet
von unserer Testerweiterung aus, klickt auf das Schaltflächenelement und wartet auf eine Antwort
vom Service Worker erhalten.
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');
});
Sie können den Test mit npm start
ausführen und sehen, dass er abgeschlossen ist.
erfolgreich war.
Schritt 4: Dienstarbeiter beenden
Fügen Sie die folgende Hilfsfunktion hinzu, die Ihren Service Worker beendet:
/**
* 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();
}
Aktualisieren Sie den Test abschließend mit dem folgenden Code. Dienst beenden und klicken Sie erneut auf die Schaltfläche, um zu überprüfen, ob Sie eine Antwort erhalten haben.
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');
});
Schritt 5: Test ausführen
Führen Sie npm start
aus. Der Test sollte fehlschlagen, was darauf hinweist, dass der Dienst-Worker nach dem Beenden nicht geantwortet hat.
Schritt 6: Service Worker korrigieren
Als Nächstes beheben Sie den Dienst-Worker, indem Sie die Abhängigkeit vom temporären Status entfernen. Aktualisieren
die Testerweiterung, um den folgenden Code zu verwenden, der in folgendem Verzeichnis gespeichert ist:
service-worker-fixed.js
im Repository.
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;
});
Hier speichern wir die Version in chrome.storage.local
anstelle einer globalen Variablen, um den Status zwischen den Lebensdauern von Dienst-Workern beizubehalten. Da nur asynchron auf den Speicher zugegriffen werden kann, geben wir auch über den onMessage
-Listener den Wert „true“ zurück, damit der sendResponse
-Callback aktiv bleibt.
Schritt 7: Test noch einmal ausführen
Führen Sie den Test noch einmal mit npm start
aus. Es sollte jetzt funktionieren.
Nächste Schritte
Diesen Ansatz können Sie jetzt auch auf Ihre eigene Erweiterung anwenden. Beachten Sie dabei Folgendes:
- Erstelle deine Testsuite, um die Ausführung mit oder ohne unerwarteten Diensten zu unterstützen Beendigung von Arbeitskräften. Sie können dann beide Modi einzeln ausführen, um besser nachvollziehen zu können, was zu einem Fehler geführt hat.
- Schreiben Sie Code, um den Dienst-Worker an zufälligen Stellen innerhalb eines Tests zu beenden. So können Sie Probleme erkennen, die möglicherweise schwer vorhersehbar sind.
- Lernen Sie aus den Testfehlern und versuchen Sie, in Zukunft sicherer zu programmieren. Fügen Sie beispielsweise eine Lint-Regel hinzu, um die Verwendung globaler Variablen zu vermeiden, und versuchen Sie, Daten in einen dauerhafteren Zustand zu verschieben.