Worum geht es?
Die Umstellung von Manifest V2 auf Manifest V3 ist eine grundlegende Änderung. Bei Manifest V2 waren Erweiterungen auf einer Hintergrundseite verfügbar. Hintergrundseiten verwalteten die Kommunikation zwischen Erweiterungen und Webseiten. In Manifest V3 werden stattdessen Dienst-Worker verwendet.
In diesem Beitrag gehen wir auf das Problem beim Testen von Erweiterungs-Dienstarbeitern ein. Insbesondere sehen wir uns an, wie wir dafür sorgen können, dass unser Produkt auch dann richtig funktioniert, wenn ein Dienstarbeiter angehalten wird.
Wer sind wir?
eyeo ist ein Unternehmen, das sich für einen ausgewogenen und nachhaltigen Online-Wertaustausch für Nutzer, Browser, Werbetreibende und Publisher einsetzt. Weltweit gibt es über 300 Millionen Nutzer, die Anzeigenfilter verwenden und die Auslieferung von Anzeigen zulassen, die den Acceptable Ads-Standards entsprechen. Dieser unabhängig entwickelte Anzeigenstandard bestimmt, ob eine Anzeige akzeptabel und nicht aufdringlich ist.
Unser Extension Engine-Team stellt die Technologie für die Anzeigenfilterung bereit, die einige der beliebtesten Werbeblocker-Browsererweiterungen auf dem Markt antreibt, z. B. AdBlock und Adblock Plus mit mehr als 110 Millionen Nutzern weltweit. Außerdem bieten wir diese Technologie als Open-Source-Bibliothek an, sodass sie auch für andere Browsererweiterungen zur Anzeigenfilterung verwendet werden kann.
Was ist ein Dienst-Worker?
Erweiterungs-Service Worker sind der zentrale Ereignis-Handler einer Browsererweiterung. Sie werden unabhängig voneinander im Hintergrund ausgeführt. Im Großen und Ganzen ist das in Ordnung. Die meisten Aufgaben, die wir auf einer Hintergrundseite erledigen müssen, können wir im neuen Service Worker ausführen. Im Vergleich zu Hintergrundseiten gibt es jedoch einige Änderungen:
- Dienstprogramme werden bei Nichtnutzung beendet. Dazu müssen wir Anwendungsstatus beibehalten, anstatt uns auf globale Variablen zu verlassen. Das bedeutet, dass alle Einstiegspunkte in unser System für den Aufruf vorbereitet sein müssen, bevor das System initialisiert wird.
- Ereignis-Listener müssen angehängt werden, bevor auf asynchrone Rückrufe gewartet wird. Ausgesetzte Dienstprogramme können weiterhin Ereignisse empfangen, die sie abonniert haben. Wenn der Listener für das Ereignis nicht in der ersten Runde des Ereignis-Loops registriert ist, wird er nicht über das Ereignis informiert, wenn dieses Ereignis den Dienst-Worker geweckt hat.
- Durch die Inaktivitätsbeendigung können Timer unterbrochen werden, bevor sie ablaufen.
Wann werden Dienstprogramme gesperrt?
Bei Chrome 119 haben wir festgestellt, dass Service Worker in folgenden Fällen angehalten werden:
- Wenn 30 Sekunden lang keine Ereignisse empfangen oder Erweiterungs-APIs aufgerufen wurden.
- Nie, wenn die Entwicklertools geöffnet sind oder Sie eine ChromeDriver-basierte Testbibliothek verwenden (siehe Funktionsanfrage).
- Wenn Sie unter chrome://serviceworker-internals auf Beenden klicken.
Aktuelle Informationen finden Sie unter Lebenszyklus von Dienst-Workern.
Warum ist das ein Problem?
Idealerweise wären offizielle Anleitungen zum effizienten Testen von Dienstprogrammen oder Beispiele für funktionierende Tests hilfreich gewesen. Bei unseren Tests von Service Workers sind uns einige Herausforderungen begegnet:
- In unserer Testerweiterung haben wir den Status. Wenn der Dienst-Worker beendet wird, gehen sein Status und seine registrierten Ereignisse verloren. Wie würden wir Daten in unserem Testablauf speichern?
- Wenn Service Worker jederzeit ausgesetzt werden können, müssen wir testen, ob alle Funktionen bei einer Unterbrechung funktionieren.
- Selbst wenn wir in unseren Tests einen Mechanismus einführen würden, der Service Worker zufällig anhält, gibt es im Browser keine API, mit der sie einfach angehalten werden können. Wir haben das W3C-Team gebeten, diese Funktion hinzuzufügen. Die Gespräche dazu laufen aber noch.
Service Worker-Sperrung testen
Wir haben verschiedene Ansätze ausprobiert, um die Sperrung von Dienstarbeitern während der Tests auszulösen:
Ansatz | Probleme mit dem Ansatz |
Warten Sie eine beliebige Zeitspanne (z. B. 30 Sekunden). | Das macht Tests langsam und unzuverlässig, insbesondere wenn mehrere Tests ausgeführt werden. Bei Verwendung von WebDriver funktioniert das nicht, da WebDriver die DevTools API von Chrome verwendet und der Service Worker nicht angehalten wird, wenn die DevTools geöffnet sind. Selbst wenn wir das Problem umgehen könnten, müssten wir trotzdem prüfen, ob der Dienst-Worker gesperrt wurde. Das ist jedoch nicht möglich. |
Endlosschleife im Dienstworker ausführen | Gemäß der Spezifikation kann dies je nach Implementierung dieser Funktion durch den Browser zur Kündigung führen. Chrome beendet den Service Worker in diesem Fall nicht, sodass wir das Szenario nicht testen können, wenn der Service Worker angehalten wird. |
Eine Nachricht im Dienstarbeiter, um zu prüfen, ob er gesperrt wurde | Durch das Senden einer Nachricht wird der Dienst-Worker geweckt. So lässt sich prüfen, ob der Dienstworker inaktiv war. Bei Tests, bei denen sofort nach dem Pausieren des Dienstworkers Prüfungen durchgeführt werden müssen, führt dies jedoch zu Fehlern. |
Service Worker-Prozess mit chrome.processes.terminate() beenden | Der Service Worker der Erweiterung teilt sich einen Prozess mit anderen Teilen der Erweiterung. Wenn Sie diesen Prozess mit chrome.process.terminate() oder der Benutzeroberfläche des Chrome-Prozessmanagers beenden, werden nicht nur der Service Worker, sondern auch alle Erweiterungsseiten beendet. |
Wir haben einen Test erstellt, mit dem geprüft wird, wie unser Code auf die Aussetzung des Diensts reagiert. Dazu haben wir Selenium WebDriver angewiesen, chrome://serviceworker-internals/ zu öffnen und auf die Schaltfläche „Stopp“ für den Dienst zu klicken.
Das ist die beste Option, die wir bisher gefunden haben, aber sie ist nicht ideal, da unsere Mocha-Tests (die auf einer Erweiterungsseite ausgeführt werden) dies nicht selbst tun können. Sie müssen also mit unserem WebDriver-Knotenprogramm kommunizieren. Das bedeutet, dass diese Tests nicht nur mit der Erweiterung ausgeführt werden können, sondern mit Selenium WebDriver ausgelöst werden müssen.
Im folgenden Diagramm wird dargestellt, wie wir über verschiedene Abläufe mit der Browser-API kommunizieren und wie sich das Hinzufügen des Mechanismus zum „Anhalten von Dienst-Workern“ darauf auswirkt.
In einem neuen Ablauf, der Dienst-Worker anhält (blau), haben wir Selenium WebDriver hinzugefügt, um die Funktion „Anhalten“ über die Benutzeroberfläche zu aktivieren, was eine Aktion in der Browser-API auslöst.
Es ist erwähnenswert, dass es einen Chrome-Fehler gab, bei dem der Service Worker nicht mehr gestartet werden konnte, wenn dies mit Selenium WebDriver durchgeführt wurde. Dieses Problem wurde in Chrome 116 behoben. Glücklicherweise gibt es auch eine Problemumgehung: Wenn Sie Chrome so einstellen, dass die Entwicklertools auf jedem Tab automatisch geöffnet werden, wird der Service Worker korrekt gestartet.
Dieser Ansatz wird bei Tests verwendet, obwohl er nicht ideal ist, da das Klicken auf die Schaltfläche möglicherweise keine stabile API ist und das Öffnen der DevTools (für ältere Browser) zu Leistungseinbußen führt.
Wie können wir die gesamte Funktionalität abdecken? Fuzz-Tests
Nachdem wir einen Mechanismus zum Testen von Sperrungen hatten, mussten wir entscheiden, wie wir ihn in unsere automatisierten Test-Suites einbinden. Wir haben unsere Standardtests in einer Umgebung durchgeführt, in der vor jeder Interaktion mit der Hintergrundseite der Dienstarbeiter angehalten wird, indem WebDriver auf der Seite chrome://serviceworker-internals/ auf Stop klickt.
Wir führen die meisten, aber nicht alle Tests durch, da der Sperrmechanismus nicht vollständig stabil ist und manchmal zu Instabilitäten führt. Außerdem dauert es sehr lange, alle Test-Suiten im Fuzz-Modus auszuführen. Anstatt alle „ähnlichen“ Fälle abzudecken, haben wir die kritischsten Pfade für die Tests im Fuzz-Modus ausgewählt. Wir mussten die Zeitlimits für die Tests erhöhen, da das Aussetzen und Neustarten von Dienstmitarbeitern zusätzliche Zeit in Anspruch nimmt.
Diese Tests sind als grober erster Durchlauf wertvoll, bei dem viele Stellen hervorgehoben werden, an denen der Code fehlschlägt. Sie decken jedoch möglicherweise nicht alle subtilen Möglichkeiten auf, wie die Sperrung von Dienstmitarbeitern zu Fehlern führen kann.
Intern bezeichnen wir diese Art von Tests als „Fuzz-Tests“. Beim Fuzz-Test wird Ihrem Programm eine ungültige Eingabe gegeben, um sicherzustellen, dass es angemessen reagiert oder zumindest nicht abstürzt. In unserem Fall ist die „ungültige Eingabe“ der Dienst-Worker, der jederzeit angehalten wird. Das „angemessene Verhalten“ besteht darin, dass unsere Anzeigenfilterfunktion wie gewohnt funktionieren muss. Dies ist eigentlich keine ungültige Eingabe, da dies in Manifest V3 ein erwartetes Verhalten ist. In Manifest V2 wäre dies jedoch ungültig gewesen. Daher ist die Terminologie angemessen.
Zusammenfassung
Service Worker sind neben declarativeNetRequest-Regeln eine der größten Änderungen in Manifest V3. Die Migration zu Manifest V3 kann viele Codeänderungen an Browsererweiterungen und neue Testmethoden erfordern. Außerdem müssen Entwickler von Erweiterungen mit dauerhaftem Status ihre Erweiterungen so vorbereiten, dass sie eine unerwartete Sperrung von Service Workern ordnungsgemäß verarbeiten können.
Leider gibt es keine API, mit der Sperrungen auf einfache Weise und passend zu unserem Anwendungsfall verarbeitet werden können. Da wir die Robustheit der Codebasis unserer Erweiterung in einer frühen Phase auf Sperrmechanismen testen wollten, mussten wir das Problem umgehen. Andere Erweiterungsentwickler, die vor ähnlichen Herausforderungen stehen, können diese Lösung verwenden. Sie ist zwar in der Entwicklungs- und Wartungsphase zeitaufwendig, lohnt sich aber, damit unsere Erweiterungen in einer Umgebung, in der Service Worker regelmäßig angehalten werden, ordnungsgemäß funktionieren.
Auch wenn es bereits grundlegende Unterstützung für das Testen der Sperrung von Dienstmitarbeitern gibt, würden wir uns in Zukunft eine bessere Plattformunterstützung für das Testen von Dienstmitarbeitern innerhalb von Erweiterungen wünschen, da sich dadurch die Ausführungszeiten und Wartungsaufwand für unsere Tests erheblich reduzieren ließen.