Rozszerzenia do Chrome: droga Eyeo do testowania zawieszenia skryptu service worker

O co chodzi?

Przejście z platformy Manifest V2 na Manifest V3 wiąże się z zasadniczą zmianą. W platformie Manifest V2 rozszerzenia działały na stronie w tle. Strony w tle zarządzały komunikacją między rozszerzeniami a stronami internetowymi. Manifest V3 korzysta z skryptów service worker.

W tym poście zagłębimy się w problem testowania mechanizmów Service Worker rozszerzenia. Przyglądamy się w szczególności tym, jak zapewnić prawidłowe działanie naszego produktu w przypadku zawieszenia działania skryptu service worker.

Kim jesteśmy?

eyeo to firma, której celem jest zapewnienie zrównoważonej i zrównoważonej wymiany wartości online dla użytkowników, przeglądarek, reklamodawców i wydawców. Mamy ponad 300 milionów użytkowników z całego świata filtrujących reklamy, którzy zezwalają na wyświetlanie zatwierdzonych reklam – standardu, który określa, czy dana reklama jest akceptowalna i nieuciążliwa.

Nasz zespół Extension Engine udostępnia technologię filtrowania reklam, która działa w niektórych najpopularniejszych rozszerzeniach do blokowania reklam na rynku, takich jak AdBlock i Adblock Plus, z których korzysta ponad 110 milionów użytkowników na całym świecie. Udostępniamy tę technologię także jako bibliotekę open source, udostępniając ją innym rozszerzeniom przeglądarki do filtrowania reklam.

Co to jest skrypt service worker?

Skrypty service worker rozszerzenia są głównym modułem obsługi zdarzeń rozszerzenia przeglądarki. Działają one niezależnie w tle. Ogólnie jest to w porządku. Większość wymaganych czynności możemy wykonywać na stronie w tle w nowym mechanizmie Service Worker. Wprowadziliśmy jednak kilka zmian w porównaniu ze stronami działającymi w tle:

  • Skrypty service worker kończą się, gdy nie są używane. Wymaga to, abyśmy utrzymywali stany aplikacji, zamiast polegać na zmiennych globalnych. Oznacza to, że wszystkie punkty wejścia do systemu muszą być przygotowane do wywołania przed jego zainicjowaniem.
  • Przed oczekiwaniem na asynchroniczne wywołania zwrotne należy dołączyć detektory zdarzeń. Zawieszone mechanizmy Service Worker nadal mogą otrzymywać zdarzenia, które zasubskrybowały. Jeśli detektor zdarzenia nie zostanie zarejestrowany w pierwszej turze pętli zdarzeń, nie otrzyma zdarzenia, jeżeli to zdarzenie wybudziło skrypt service worker.
  • Kończenie bezczynności może przerwać minutniki przed zakończeniem aktywności.

Kiedy mechanizmy Service Worker są zawieszane?

W Chrome 119 zaobserwowaliśmy, że mechanizmy Service Worker są zawieszone:

  • Po 30 sekundach nieotrzymywania zdarzeń ani wywoływania interfejsów API rozszerzeń.
  • Nigdy nie sprawdzaj, czy narzędzia dla programistów są otwarte lub jeśli używasz biblioteki testowej ChromeDriver (zobacz prośbę o dodanie funkcji).
  • Kliknij Zatrzymaj na stronie chrome://serviceworker-internals.

Najnowsze informacje znajdziesz w artykule o cyklu życia mechanizmów Service Workers.

Dlaczego testowanie tego rozwiązania stanowi problem?

W idealnej sytuacji przydałyby się oficjalne wskazówki dotyczące „wydajnego testowania pracowników usługowych” lub przykłady testów roboczych. Podczas naszych przygód związanych z testowaniem pracowników serwisowych napotkaliśmy kilka problemów:

  • Mamy stan w naszym rozszerzeniu testowym. Gdy skrypt service worker zatrzyma się, utracisz jego stan i zarejestrowane zdarzenia. W jaki sposób zachowamy dane w procesie testowania?
  • Jeśli mechanizmy Service Worker można w dowolnym momencie zawiesić, musimy sprawdzić, czy po przerwaniu ich działania wszystkie funkcje działają.
  • Nawet jeśli wprowadzimy w naszych testach mechanizm, który losowo zawiesza mechanizmy Service Worker, nie ma w przeglądarce interfejsu API, który mógłby łatwo zawiesić takie działanie. Poprosiliśmy zespół W3C o dodanie tej funkcji, ale ta rozmowa wciąż trwa.

Testowanie zawieszenia skryptu service worker

Próbowaliśmy na kilka sposobów na zawieszenie działania skryptu service worker podczas testów:

Metoda Problemy z podejściem
Odczekaj dowolny czas (np. 30 sekund) Sprawia to, że testy są powolne i niezawodne, zwłaszcza gdy przeprowadzasz wiele testów. Nie działa ona w przypadku korzystania z WebDriver, ponieważ korzysta z interfejsu DevTools API w Chrome, a skrypt service worker nie jest zawieszony, gdy jest otwarty Narzędzia deweloperskie. Nawet jeśli moglibyśmy je ominąć, musielibyśmy sprawdzić, czy skrypt service worker nie został zawieszony. Nie mamy sposobu, aby to zrobić.
Uruchamianie nieskończonej pętli w skrypcie service worker Zgodnie ze specyfikacją może to doprowadzić do zamknięcia konta w zależności od tego, jak przeglądarka wdroży tę funkcję. Chrome nie zamyka w tym przypadku skryptu service worker, więc nie możemy przetestować scenariusza jego zawieszenia.
Umieszczenie w skrypcie service worker komunikatu o tym, czy konto jest zawieszone Wysłanie wiadomości wybudza skrypt service worker. Można go użyć, aby sprawdzić, czy skrypt service worker był uśpiony, ale powoduje to uszkodzenie wyników testów, które muszą wykonać testy natychmiast po zawieszeniu skryptu service worker.
Zatrzymaj proces skryptu service worker za pomocą polecenia chrome.processes.terminate() Skrypt service worker rozszerzenia współdzieli proces z innymi częściami rozszerzenia, dlatego zamknięcie tego procesu za pomocą chrome.process.terminate() lub GUI menedżera procesów Chrome zatrzymuje nie tylko skrypt service worker, ale także wszystkie strony rozszerzeń.

Przeprowadziliśmy test, który sprawdza, jak nasz kod odpowiada na zawieszenie skryptu service worker. W tym celu narzędzie Selenium WebDriver o otwarciu strony chrome://serviceworker-internals/ i kliknięciem przycisku „stop” odpowiadającego skryptowi service worker.

Jak dotąd jest to najlepsza opcja, ale nie jest idealna, ponieważ nasze testy Mocha (które działają na stronie rozszerzenia) nie są w stanie wykonać tego samodzielnie, dlatego muszą się komunikować z naszym programem węzłów WebDriver. Oznacza to, że tych testów nie można przeprowadzić z użyciem samego rozszerzenia – trzeba je uruchamiać za pomocą narzędzia Selenium WebDriver.

Oto schemat, który przedstawia, jak komunikujemy się z interfejsem API przeglądarki przez różne przepływy, i jak wpływa na niego dodanie mechanizmu „zawieszonych mechanizmów Service Worker”.

Schemat procesu testowania
Testowanie procesu z zawieszeniem skryptu service worker.

W nowym procesie, który zawiesza mechanizmy Service Worker (w kolorze niebieskim), dodaliśmy funkcję Selenium WebDriver do zawieszania za pomocą interfejsu użytkownika, które uruchamiają działanie w interfejsie API przeglądarki.

Warto wspomnieć, że wystąpił błąd w Chrome, który powodował, że wykonanie tego działania w Selenium WebDriver uniemożliwiało ponowne uruchomienie skryptu service worker. Problem został rozwiązany w Chrome 116 i na szczęście istnieje rozwiązanie, które pomaga rozwiązać ten problem: ustawienie w Chrome automatycznego otwierania Narzędzi deweloperskich na każdej karcie sprawia, że skrypt service worker uruchamia się prawidłowo.

Stosujemy takie podejście podczas testowania, które nie jest idealne, ponieważ kliknięcie przycisku może nie być stabilnym interfejsem API, a otwarcie Narzędzi deweloperskich (w starszych przeglądarkach) może wiązać się z kosztami wydajności.

Jak uwzględnić całą funkcjonalność? Testy rozmycia

Kiedy mieliśmy już mechanizm testowania zawieszenia, musieliśmy zdecydować, jak uwzględnić go w naszych zestawach testów zautomatyzowanych. Nasze standardowe testy przeprowadziliśmy w środowisku, w którym przed każdą interakcją ze stroną w tle sektor service worker jest zawieszany przez WebDriver, klikając Zatrzymaj na stronie chrome://serviceworker-internals/.

Wykonanie przykładowego testu Fuzz
Obraz przedstawiający bieżącą konfigurację testów.

Przeprowadzamy większość testów, ale nie wszystkie, ponieważ mechanizm zawieszenia nie jest w pełni stabilny, a czasami powoduje niestabilne działanie. Poza tym uruchomienie wszystkich pakietów testowych w trybie rozmytym zajmuje dużo czasu. Dlatego zamiast omawiać wszystkie „podobne” przypadki, wybraliśmy najważniejsze ścieżki testowania w trybie rozmycia. Warto wspomnieć, że prowadzenie testów funkcjonalnych w trybie „fuzz” oznacza, że musieliśmy wydłużyć czasy oczekiwania testów, ponieważ zawieszanie i ponowne uruchamianie skryptu service worker zajmuje dodatkowy czas.

Testy te są wartościowe jako precyzyjne testy pierwsze i wyróżniają wiele miejsc, w których kod ulega awarii, ale niekoniecznie ujawnią wszystkie subtelne sposoby, w jakie zawieszenie skryptu service worker może spowodować awarię.

Wewnętrznie tego typu testy nazywamy „testami Fuzz”. Tradycyjnie test rozmycie polega na podaniu do programu nieprawidłowych danych wejściowych i upewnieniu się, że reaguje on w rozsądny sposób, a przynajmniej nie ulega awarii. W naszym przypadku „nieprawidłowe dane wejściowe” oznaczają, że skrypt service worker jest zawieszany w dowolnym momencie, a „zasadniczym zachowaniem” jest fakt, że funkcja filtrowania reklam musi działać bez zmian. To nie są nieprawidłowe dane wejściowe, ponieważ w pliku manifestu V3 jest to oczekiwane działanie, ale w platformie Manifest V2 byłoby to nieprawidłowe, więc wydaje się rozsądną terminologią.

Podsumowanie

Skrypty service worker to jedne z największych zmian w platformie Manifest V3 (oprócz reguł deklarativeNetRequest). Migracja do platformy Manifest V3 może wymagać wprowadzenia wielu zmian w kodzie w rozszerzeniach przeglądarki i nowych metod testowania. Wymaga to też od programistów rozszerzeń o stanie trwałym, aby sprawnie przygotowali rozszerzenia do obsługi nieoczekiwanego zawieszenia skryptu service worker.

Nie ma interfejsu API, który pozwalałby zastosować zawieszenie konta w taki sposób, który odpowiadałby naszym przypadku. We wczesnych fazach chcieliśmy przetestować wytrzymałość bazy kodu naszego rozszerzenia w porównaniu z mechanizmami zawieszania, więc musieliśmy go obejść. Z tego rozwiązania mogą korzystać inni deweloperzy rozszerzeń, którzy stoją przed podobnymi wyzwaniami. To rozwiązanie jest czasochłonne w fazie opracowywania i konserwacji. Dzięki temu możemy zapewnić prawidłowe działanie naszych rozszerzeń w środowisku, w którym mechanizmy Service Worker są regularnie zawieszane.

Mimo że podstawowa obsługa testów zawieszenia mechanizmów Service Worker jest już dostępna, chcielibyśmy wprowadzić lepszą obsługę platformy testowania mechanizmów Service Worker z poziomu rozszerzeń, ponieważ może to znacznie skrócić czas wykonywania testów i nakład pracy związany z konserwacją.