Extensiones de Chrome: El recorrido de Eyeo para probar la suspensión de los service worker

¿De qué se trata?

La transición de Manifest V2 a Manifest V3 implica un cambio fundamental. En Manifest V2, las extensiones residían en una página en segundo plano. Las páginas de fondo administraban la comunicación entre las extensiones y las páginas web. En su lugar, Manifest V3 usa service worker.

En esta publicación, profundizamos en el problema de probar los service workers de extensión. En particular, analizamos cómo asegurarnos de que nuestro producto funcione correctamente en caso de que se suspenda un service worker.

¿Quiénes somos?

eyeo es una empresa que se dedica a impulsar un intercambio de valor en línea equilibrado y sustentable para usuarios, navegadores, anunciantes y publicadores. Tenemos más de 300 millones de usuarios globales de filtros de anuncios que permiten mostrar Acceptable Ads, un estándar de anuncios que se obtiene de forma independiente y que determina si un anuncio es aceptable y no intrusivo.

Nuestro equipo del Motor de extensiones proporciona tecnología de filtrado de anuncios que impulsa algunas de las extensiones del navegador de bloqueo de anuncios más populares del mercado, como AdBlock y Adblock Plus, con más de 110 millones de usuarios en todo el mundo. Además, ofrecemos esta tecnología como una biblioteca de código abierto, que ahora está disponible para otras extensiones de navegador que utilizan filtros de anuncios.

¿Qué es un service worker?

Los service worker de extensiones son el controlador central de eventos de una extensión del navegador. Se ejecutan de forma independiente en segundo plano. En líneas generales, no hay problema. Podemos hacer la mayoría de las tareas que necesitamos en una página en segundo plano en el nuevo service worker. Pero hay algunos cambios en comparación con las páginas de fondo:

  • Los service workers terminan cuando no están en uso. Para ello, debemos conservar los estados de la aplicación en lugar de depender de variables globales. Esto significa que cualquier punto de entrada a nuestro sistema debe estar preparado para que se lo llame antes de que se inicialice.
  • Los objetos de escucha de eventos se deben adjuntar antes de esperar devoluciones de llamada asíncronas. Los service workers suspendidos pueden seguir recibiendo eventos a los que están suscritos. Si el objeto de escucha del evento no está registrado en el primer turno del bucle de eventos, no recibirá el evento si ese evento despertó al service worker.
  • La terminación inactiva puede interrumpir los cronómetros antes de que se completen.

¿Cuándo se suspenden los service worker?

En Chrome 119, notamos que se suspendieron los service workers:

  • Después de no recibir eventos ni llamar a las APIs de extensiones durante 30 segundos
  • Nunca si las herramientas para desarrolladores están abiertas o si usas una biblioteca de pruebas basada en ChromeDriver (consultar la solicitud de función).
  • Si haces clic en Detener en chrome://serviceworker-internals.

Para obtener información más reciente, consulta Ciclo de vida de los procesos de trabajo de servicio.

¿Por qué es un problema probarlas?

Idealmente, hubiera sido útil tener orientación oficial sobre “cómo probar los service workers de manera eficiente” o ejemplos de pruebas de trabajo. Durante nuestras aventuras con los service workers de prueba, nos enfrentamos a algunos desafíos:

  • Tenemos el estado en nuestra extensión de prueba. Cuando se detiene el service worker, perdemos su estado y sus eventos registrados. ¿Cómo conservaríamos los datos en nuestro flujo de prueba?
  • Si los service workers se pueden suspender en algún momento, debemos probar que todas las características se ejecuten en caso de que se interrumpan.
  • Incluso si en nuestras pruebas introducimos un mecanismo que suspenda los service workers de forma aleatoria, no hay una API en el navegador que pueda suspenderlo fácilmente. Le pedimos al equipo de W3C que agregue esta función, pero esa es una conversación en curso.

Prueba la suspensión de Service Worker

Probamos varios enfoques para activar la suspensión del service worker durante las pruebas:

Enfoque Problemas con el enfoque
Esperar una cantidad de tiempo arbitraria (por ejemplo, 30 segundos) Esto hace que las pruebas sean lentas y poco confiables, en especial cuando se ejecutan varias pruebas. No funciona cuando se usa WebDriver, ya que WebDriver usa la API de Herramientas para desarrolladores de Chrome, y el service worker no se suspende cuando Herramientas para desarrolladores está abierto. Incluso si pudiéramos evitarlo, aún tendríamos que verificar si el service worker está suspendido y no tenemos forma de hacerlo.
Ejecuta un bucle infinito en el service worker Según las especificaciones, esto puede provocar la rescisión según cómo el navegador implemente esta funcionalidad. En este caso, Chrome no cierra el service worker. Por lo tanto, no podemos probar la situación cuando se suspende el service worker.
Incluir un mensaje en el service worker para comprobar si se suspendió Si envías un mensaje, se activa el service worker. Se puede usar para comprobar si el service worker estuvo suspendido, pero interrumpe los resultados de las pruebas que deben realizar verificaciones inmediatamente después de suspender el service worker.
Finaliza el proceso del service worker con chrome.processes.terminate() El service worker de la extensión comparte un proceso con otras partes de la extensión, por lo que finalizar este proceso usando chrome.process.terminate() o la GUI del administrador de procesos de Chrome elimina no solo el service worker, sino también cualquier página de extensión.

Finalizamos con una prueba que verifica cómo responde nuestro código al proceso de suspensión. Para ello, se hace que Selenium WebDriver abra chrome://serviceworker-internals/ y haga clic en el botón "detener" del service worker.

Esta es la mejor opción hasta ahora, pero no es ideal porque nuestras pruebas de Mocha (que se ejecutan en una página de extensión) no pueden hacer esto por sí mismas, por lo que deben comunicarse con nuestro programa de nodos de WebDriver. Eso significa que estas pruebas no se pueden ejecutar solo con la extensión. Se deben activar con Selenium WebDriver.

A continuación, se muestra un diagrama de cómo nos comunicamos con la API del navegador a través de diferentes flujos y cómo se ve afectado por agregar el mecanismo de “suspensión de service workers”.

Diagrama que muestra el flujo de prueba
Flujo de prueba con suspensión de service worker.

En un nuevo flujo que suspende los service workers (azul), agregamos Selenium WebDriver para que haga clic en la suspensión a través de la IU, lo que activa una acción en la API del navegador.

Es importante mencionar que, debido a un error de Chrome, al hacer esto con Selenium WebDriver, el service worker no podía volver a empezar. Este problema se solucionó en Chrome 116 y, afortunadamente, también existe una solución alternativa: si configura Chrome para que abra Herramientas para desarrolladores automáticamente en cada pestaña, el service worker se iniciará correctamente.

Este es el enfoque que usamos cuando realizamos pruebas, aunque no es ideal, ya que hacer clic en el botón puede no ser una API estable y abrir Herramientas para desarrolladores (para navegadores más antiguos) parece tener un costo de rendimiento.

¿Cómo cubrimos toda la funcionalidad? Pruebas de fuzzing

Una vez que tuvimos un mecanismo para probar la suspensión, tuvimos que decidir cómo conectarlo a nuestros paquetes de pruebas de automatización. Ejecutamos nuestras pruebas estándar en un entorno en el que, antes de cada interacción con la página en segundo plano, el service worker se suspende cuando WebDriver hace clic en Stop en la página chrome://serviceworker-internals/.

Ejemplo de ejecución de prueba de fuzz
Imagen que muestra la configuración actual de las pruebas.

Ejecutamos la mayoría de las pruebas, y no todas, porque el mecanismo de suspensión no es completamente estable y, a veces, provoca inestabilidad. Además, ejecutar todos los paquetes de pruebas en modo fuzz lleva mucho tiempo. Por lo tanto, en lugar de abarcar todos los casos “similares”, elegimos las rutas más críticas para realizar pruebas en el modo fuzz. Vale la pena mencionar que ejecutar pruebas funcionales en el modo “fuzz” significa que tuvimos que aumentar los tiempos de espera de las pruebas, ya que suspender y reiniciar los service workers requiere tiempo adicional.

Estas pruebas son valiosas como una primera pasada poco detallada, que destaca muchos lugares en los que falla el código, pero es posible que no necesariamente descubra todas las formas sutiles en que la suspensión del service worker puede causar problemas en los errores.

A este tipo de pruebas, las llamamos "pruebas Fuzz". Tradicionalmente, las pruebas de fuzz se producen cuando arrojas una entrada no válida a tu programa y te aseguras de que responda de manera razonable o, al menos, no falle. En nuestro caso, la "entrada no válida" es el service worker que se suspende en cualquier momento, y el "comportamiento razonable" que esperamos es que nuestra funcionalidad de filtrado de anuncios siga funcionando como antes. Esta entrada no es realmente válida, ya que es el comportamiento esperado en Manifest V3, pero no sería válida en Manifest V2, por lo que parece una terminología razonable.

Resumen

Los service workers son uno de los cambios más grandes en Manifest V3 (además de las reglas declarativeNetRequest). La migración a Manifest V3 puede requerir muchos cambios de código en las extensiones del navegador y nuevos enfoques para las pruebas. También requiere que los desarrolladores de extensiones con estado persistente preparen sus extensiones para controlar la suspensión inesperada de service worker de forma elegante.

Lamentablemente, no existe una API para manejar la suspensión de una manera sencilla que se adapte a nuestro caso de uso. Debido a que, en una fase inicial, queríamos probar la solidez de la base de código de nuestra extensión con respecto a los mecanismos de suspensión, tuvimos que resolverlo. Otros desarrolladores de extensiones que enfrentan desafíos similares pueden usar esta solución alternativa, que, si bien requiere mucho tiempo en las fases de desarrollo y mantenimiento, vale la pena para que podamos asegurarnos de que nuestras extensiones puedan funcionar correctamente en un entorno en el que los service workers se suspenden regularmente.

Si bien ya hay asistencia básica para probar la suspensión de service worker, nos gustaría ver mejor la compatibilidad de la plataforma para probar service workers desde las extensiones en el futuro, ya que podría reducir en gran medida los tiempos de ejecución de las pruebas y los esfuerzos de mantenimiento.