Di cosa parla?
La transizione da Manifest V2 a Manifest V3 comporta un cambiamento fondamentale. In Manifest V2, le estensioni vivevano in una pagina in background. Le pagine in background gestivano la comunicazione tra estensioni e pagine web. Manifest V3 utilizza invece i service worker.
In questo post, analizziamo il problema del test dei service worker delle estensioni. In particolare, daremo un'occhiata a come assicurarci che il nostro prodotto funzioni correttamente nel caso in cui un service worker venga sospeso.
Chi siamo?
eyeo è un'azienda che si impegna a promuovere uno scambio di valore online equilibrato e sostenibile per utenti, browser, inserzionisti e publisher. Abbiamo più di 300 milioni di utenti a livello globale che utilizzano il filtro degli annunci che consentono di visualizzare Acceptable Ads, uno standard pubblicitario derivato in modo indipendente che determina se un annuncio è accettabile e non invasivo.
Il nostro team di Extension Engine fornisce una tecnologia di filtro degli annunci alla base di alcune delle estensioni del browser di blocco degli annunci più popolari sul mercato, come AdBlock e Adblock Plus, che hanno oltre 110 milioni di utenti in tutto il mondo. Inoltre, offriamo questa tecnologia come libreria open source, rendendola disponibile per altre estensioni del browser che utilizzano il filtro degli annunci.
Che cos'è un service worker?
I service worker delle estensioni sono il gestore di eventi centrale di un'estensione del browser. Vengono eseguiti in modo indipendente in background. In generale, questo non è un problema. Nel nuovo service worker possiamo fare la maggior parte delle cose che dobbiamo fare su una pagina in background. Tuttavia, ci sono alcuni cambiamenti rispetto alle pagine in background:
- I service worker terminano quando non sono in uso. Questo ci richiede di rendere gli stati dell'applicazione anziché fare affidamento su variabili globali. Ciò significa che qualsiasi punto di ingresso nel nostro sistema deve essere preparato per essere chiamato prima dell'inizializzazione del sistema.
- È necessario collegare i listener di eventi prima di attendere i callback asincroni. I service worker sospesi possono comunque ricevere gli eventi a cui sono iscritti. Se il listener dell'evento non è registrato nel primo turno del loop di eventi, non riceverà l'evento se l'evento ha riattivato il service worker.
- La terminazione per inattività può interrompere i timer prima che vengano completati.
Quando vengono sospesi i service worker?
In Chrome 119, abbiamo riscontrato la sospensione dei service worker:
- Dopo non aver ricevuto eventi o aver chiamato le API delle estensioni per 30 secondi.
- Mai se gli strumenti per sviluppatori sono aperti o se utilizzi una libreria di test basata su ChromeDriver (vedi la richiesta di funzionalità).
- Se fai clic su Interrompi in chrome://serviceworker-internals.
Per informazioni più recenti, fai riferimento a Ciclo di vita dei service worker.
Perché eseguire test è un problema?
Idealmente, sarebbe stato utile avere una guida ufficiale su "come testare i service worker in modo efficiente" o esempi di test di lavoro. Durante le nostre avventure di test dei service worker, abbiamo dovuto affrontare alcune sfide:
- È presente lo stato nell'estensione di prova. Quando il service worker si arresta, perdiamo il suo stato e i relativi eventi registrati. In che modo potremmo conservare i dati nel nostro flusso di test?
- Se i Service worker possono essere sospesi in qualsiasi momento, dobbiamo verificare che tutte le funzionalità funzionino se vengono interrotte.
- Anche se introdurremo un meccanismo nei nostri test che sospende in modo casuale i service worker, nel browser non esiste un'API che consenta di sospenderlo facilmente. Abbiamo chiesto al team di W3C di aggiungere questa funzionalità, ma questa è una conversazione in corso.
Test della sospensione del service worker
Abbiamo provato diversi approcci per attivare la sospensione dei service worker durante i test:
Approccio | Problemi con l'approccio |
Attendi un periodo di tempo arbitrario (ad esempio 30 secondi) | Ciò rende i test lenti e inaffidabili, soprattutto nell'esecuzione di più test. Non funziona quando si utilizza WebDriver, poiché WebDriver utilizza l'API DevTools di Chrome e il service worker non è sospeso quando DevTools è aperto. Anche se potessimo aggirarlo, dovremmo comunque controllare se il service worker è stato sospeso e non abbiamo un modo per farlo. |
Eseguire un ciclo infinito nel service worker | Secondo le specifiche, questo può portare alla chiusura, a seconda di come il browser implementa questa funzionalità. Chrome non termina il service worker in questo caso, quindi non possiamo testare lo scenario quando il service worker viene sospeso. |
Ricezione di un messaggio nel service worker per verificare se è stato sospeso | L'invio di un messaggio riattiva il service worker. Questa opzione può essere utilizzata per verificare se il service worker era in stato di sospensione, ma interrompe i risultati per i test che devono eseguire i controlli immediatamente dopo la sospensione. |
Termina il processo del service worker utilizzando chrome.processes.terminate() | Il service worker dell'estensione condivide un processo con altre parti dell'estensione, quindi terminando questo processo utilizzando chrome.process.terminate() o la GUI del gestore di processi di Chrome, non si uccide solo il service worker, ma anche tutte le pagine delle estensioni. |
Al termine, abbiamo eseguito un test per verificare in che modo il codice risponde al service worker sospeso facendo clic su Selenium WebDriver su chrome://serviceworker-internals/ e facendo clic sul pulsante "Interrompi" relativo al service worker.
Questa è l'opzione migliore finora, ma non è l'ideale perché i nostri test Mocha (che vengono eseguiti su una pagina di estensione) non sono in grado di eseguire questa operazione autonomamente, pertanto deve comunicare di nuovo al nostro programma di nodi WebDriver. Ciò significa che questi test non possono essere eseguiti utilizzando solo l'estensione, ma devono essere attivati utilizzando Selenium WebDriver.
Ecco un diagramma di come comunichiamo con l'API del browser attraverso flussi diversi e di come l'aggiunta del meccanismo dei "service worker di sospensione" lo influisce.
In un nuovo flusso che sospende i service worker (blu), abbiamo aggiunto Selenium WebDriver per fare clic sulla sospensione tramite l'interfaccia utente, che attiva un'azione nell'API del browser.
Vale la pena ricordare che era presente un bug di Chrome a causa del quale l'esecuzione di questa operazione con Selenium WebDriver impediva il riavvio del service worker. Il problema è stato risolto in Chrome 116 e, fortunatamente, esiste anche una soluzione alternativa: impostare Chrome per aprire DevTools automaticamente in ogni scheda consente di avviare correttamente il service worker.
Questo è l'approccio che utilizziamo durante i test, anche se non è l'ideale, in quanto il clic sul pulsante potrebbe non essere un'API stabile e l'apertura di DevTools (per i browser meno recenti) sembra avere un costo in termini di prestazioni.
Come viene spiegata l'intera funzionalità? Test fuzz
Una volta ottenuto un meccanismo per testare la sospensione, abbiamo dovuto decidere come collegarla alle nostre suite di test di automazione. Abbiamo eseguito i nostri test standard in un ambiente in cui, prima di ogni interazione con la pagina in background, il service worker viene sospeso da WebDriver facendo clic su Interrompi nella pagina chrome://serviceworker-internals/.
Eseguiamo la maggior parte dei test, ma non tutti, perché il meccanismo di sospensione non è completamente stabile e a volte causa instabilità. Inoltre, l'esecuzione di tutte le suite di test in modalità fuzz richiede molto tempo. Quindi, invece di coprire tutti i casi "simili", abbiamo scelto i percorsi più critici per i test in modalità fuzz. È bene ricordare che eseguire test funzionali in modalità "fuzz" significa che abbiamo dovuto aumentare i timeout dei test perché la sospensione e il riavvio dei service worker richiedono più tempo.
Questi test sono importanti come un primo passaggio con granularità grossolana, che evidenzia molti punti in cui il codice ha esito negativo, ma potrebbero non necessariamente scoprire tutti i modi discreti in cui la sospensione del service worker potrebbe causare interruzioni.
Internamente, questo tipo di test viene chiamato "Fuzz test". Tradizionalmente, il test fuzz prevede l'invio di input non validi al programma e la certezza che risponda in modo ragionevole o che non subisca un arresto anomalo. Nel nostro caso, per "input non valido" si intende il service worker sospeso in qualsiasi momento e il "comportamento ragionevole" che ci aspettiamo è che la nostra funzionalità di filtro degli annunci debba continuare a funzionare come prima. Non si tratta di un input davvero non valido perché è un comportamento previsto in Manifest V3, ma non sarebbe stato valido in Manifest V2, quindi sembra una terminologia ragionevole.
Riepilogo
I Service worker rappresentano una delle principali modifiche in Manifest V3 (oltre alle regole declarativeNetRequest). La migrazione a Manifest V3 potrebbe richiedere molte modifiche al codice nelle estensioni del browser e nuovi approcci ai test. Richiede inoltre agli sviluppatori di estensioni con stato permanente di preparare le proprie estensioni per gestire in modo responsabile la sospensione imprevista dei service worker.
Purtroppo, non esiste un'API per gestire la sospensione in un modo semplice e adatto al nostro caso d'uso. Poiché volevamo testare la solidità del codebase della nostra estensione rispetto ai meccanismi di sospensione in una fase iniziale, abbiamo dovuto intervenire. Altri sviluppatori di estensioni che affrontano sfide simili possono utilizzare questa soluzione alternativa che, sebbene dispendiosa in termini di tempo nella fase di sviluppo e manutenzione, vale la pena farlo per assicurarci che le nostre estensioni possano funzionare correttamente in un ambiente in cui i service worker vengono regolarmente sospesi.
Anche se esiste già supporto di base per testare la sospensione dei service worker, un supporto migliore della piattaforma per testare i service worker dall'interno delle estensioni è qualcosa che vorremmo davvero vedere in futuro, in quanto potrebbe ridurre notevolmente i tempi di esecuzione dei test e lo sforzo di manutenzione.