¿Cómo probar las extensiones de Chrome?

154

¿Existe una forma correcta de hacer esto? Estoy escribiendo una extensión que interactúa con un sitio web como una secuencia de comandos de contenido y guarda datos utilizando el almacenamiento local. ¿Hay alguna herramienta, marco, etc. que pueda usar para probar este comportamiento? Me doy cuenta de que hay algunas herramientas genéricas para probar JavaScript, pero ¿son lo suficientemente potentes para probar una extensión? Las pruebas unitarias son las más importantes, pero también me interesan otros tipos de pruebas (como las pruebas de integración).

Swampjohn
fuente
8
Acabo de escribir una respuesta canónica que aborda las pruebas unitarias y las pruebas de integración para extensiones de navegador en todos los navegadores, no solo Chrome. Consulte la respuesta a "Prueba de extensiones de navegador" .
Rob W

Respuestas:

111

Sí, los marcos existentes son bastante útiles.

En el pasado reciente, he colocado todas mis pruebas en una página de "prueba" que estaba incrustada en la aplicación pero que no es accesible a menos que esté escrita físicamente.

Por ejemplo, tendría todas las pruebas en una página accesible bajo chrome-extension://asdasdasdasdad/unittests.html

Las pruebas tendrían acceso a localStorageetc. Para acceder a los scripts de contenido, en teoría podría probarlo a través de IFRAME incrustados en su página de prueba, sin embargo, estas son más pruebas de nivel de integración, las pruebas unitarias requerirían que abstraiga eso de páginas reales para que pueda no dependa de ellos, del mismo modo con acceso a localStorage.

Si desea probar páginas directamente, puede orquestar su extensión para abrir pestañas nuevas (chrome.tab.create ({"url": "someurl"}). Para cada una de las pestañas nuevas, su script de contenido debe ejecutarse y puede usar su marco de prueba para verificar que su código haya hecho lo que debería hacer.

En cuanto a los frameworks, JsUnit o el Jasmine más reciente deberían funcionar bien.

Kinlan
fuente
1
Tienes razón, probar páginas reales no se incluye en las pruebas unitarias. Debería haber hecho mi pregunta más amplia. Pero todavía es algo que me gustaría probar, especialmente porque la estructura html del sitio web podría cambiar en cualquier momento. He modificado la pregunta.
swampsjohn
1
Todavía probaría a través de IFrames en la página de prueba de su unidad. Los scripts de contenido aún deberían
activarse
3
La extensión de muestra de proxy tiene algunas pruebas que simplemente se burlan de las partes de las API de Chrome que eran necesarias: code.google.com/chrome/extensions/samples.html#chrome.proxy .. También nuestro colega Boris usó QUnit para las pruebas su capa "modelo": github.com/borismus/Question-Monitor-for-Stack-Exchange/tree/…
Paul Irish
63

Trabajando en varias extensiones de Chrome, se me ocurrió un sinon-chromeproyecto que permite ejecutar pruebas unitarias usando mocha, nodejsy phantomjs.

Básicamente, crea simulacros de sinon de todas las chrome.*API donde puede colocar cualquier respuesta json predefinida.

Luego, carga sus scripts usando los nodos vm.runInNewContextpara la página de fondo y phantomjspara la página emergente / opciones de renderizado.

Y finalmente, usted afirma que la API de Chrome se llamó con los argumentos necesarios.

Tomemos un ejemplo:
supongamos que tenemos una extensión simple de Chrome que muestra el número de pestañas abiertas en la insignia del botón.

página de fondo:

chrome.tabs.query({}, function(tabs) {
  chrome.browserAction.setBadgeText({text: String(tabs.length)});
});

Para probarlo necesitamos:

  1. simulacro chrome.tabs.querypara devolver una respuesta predefinida, por ejemplo, dos pestañas.
  2. inyectar nuestra chrome.*api burlada en algún entorno
  3. ejecuta nuestro código de extensión en este entorno
  4. afirmar que la insignia del botón es igual a '2'

El fragmento de código es el siguiente:

const vm = require('vm');
const fs = require('fs');
const chrome = require('sinon-chrome');

// 1. mock `chrome.tabs.query` to return predefined response 
chrome.tabs.query.yields([
  {id: 1, title: 'Tab 1'}, 
  {id: 2, title: 'Tab 2'}
]);

// 2. inject our mocked chrome.* api into some environment
const context = {
  chrome: chrome
};

// 3. run our extension code in this environment
const code = fs.readFileSync('src/background.js');
vm.runInNewContext(code, context);

// 4. assert that button badge equals to '2'
sinon.assert.calledOnce(chrome.browserAction.setBadgeText);
sinon.assert.calledWithMatch(chrome.browserAction.setBadgeText, {
  text: "2"
});

Ahora podemos envolverlo en las describe..itfunciones de mocha y ejecutarlo desde la terminal:

$ mocha

background page
  ✓ should display opened tabs count in button badge

1 passing (98ms)

Puedes encontrar el ejemplo completo aquí .

Además, sinon-chrome permite activar cualquier evento de chrome con una respuesta predefinida, p. Ej.

chrome.tab.onCreated.trigger({url: 'http://google.com'});
vitalets
fuente
El enlace para el ejemplo parece estar muerto, ¿podría actualizarlo?
Levantado el
1
Enlace actualizado al ejemplo. También sinon-chrome ahora se mueve a github.com/acvetkov y pronto habrá nuevos ejemplos
vitalets
3

Si bien sinon.jsparece funcionar muy bien, también puede usar Jasmine simple y burlarse de las devoluciones de llamada de Chrome que necesita. Ejemplo:

Burlarse de

chrome = {
  runtime: {
    onMessage : {
      addListener : function() {}
    }
  }
}

Prueba

describe("JSGuardian", function() {

  describe("BlockCache", function() {

    beforeEach(function() {
      this.blockCache = new BlockCache();
    });

    it("should recognize added urls", function() {
      this.blockCache.add("http://some.url");
      expect(this.blockCache.allow("http://some.url")).toBe(false);
    });
} // ... etc

Simplemente modifique el valor predeterminado SpecRunner.htmlpara ejecutar su código.

serv-inc
fuente
2

Acerca de la herramienta ya existente en Chrome:

  1. En la herramienta para desarrolladores de Chrome, hay una sección de Recursos para el almacenamiento local.

    Herramientas para desarrolladores> Recursos> Almacenamiento local

    Vea los cambios de almacenamiento local allí.

  2. Puede usar console.profile para probar el rendimiento y ver la pila de llamadas en tiempo de ejecución.

  3. para el sistema de archivos Puede usar esta URL para verificar que su archivo esté cargado o no: sistema de archivos: extensión-cromo: /// temporal /

Si utiliza el script de contenido y el almacenamiento local juntos sin la página / script de fondo y sin pasar el mensaje, solo se podrá acceder al almacenamiento local desde ese sitio. Entonces, para probar esas páginas, debe inyectar su script de prueba en esas pestañas.

Nafis Ahmad
fuente
1
No funcionó para mí, pero me ayudó a avanzar en mi javascript. +1 por eso.
mobibob
Para fileSystem Puede usar: filesystem: chrome-extension: // <yourextension-id> / temporary /
Nafis Ahmad
1

Descubrí que puedo usar el controlador web Selenium para iniciar una nueva instancia del navegador con una extensión preinstalada y pyautogui para los clics, porque Selenium no puede manejar la "vista" de la extensión. Después de los clics, puede hacer capturas de pantalla y compararlas con las 'esperadas', esperando un 95% de similitud (porque en diferentes navegadores es aceptable realizar movimientos de marcado a unos pocos píxeles).

Vitaly Zdanevich
fuente
0

Para confirmar un par de respuestas anteriores, Jasmine parece funcionar bien con las extensiones de Chrome. Estoy usando la versión 3.4.0.

Puede usar espías Jasmine para crear fácilmente dobles de prueba para las diversas API. No es necesario construir el suyo desde cero. Por ejemplo:

describe("Test suite", function() {

  it("Test case", function() {

    // Set up spies and fake data.
    spyOn(chrome.browserAction, "setPopup");
    spyOn(chrome.identity, "removeCachedAuthToken");
    fakeToken = "faketoken-faketoken-faketoken";
    fakeWindow = jasmine.createSpyObj("window", ["close"]);

    // Call the function under test.
    logout(fakeWindow, fakeToken);

    // Perform assertions.
    expect(chrome.browserAction.setPopup).toHaveBeenCalledWith({popup: ""});
    expect(chrome.identity.removeCachedAuthToken).toHaveBeenCalledWith({token: fakeToken});
    expect(fakeWindow.close.calls.count()).toEqual(1);

  });

});

Algunos detalles más, si ayuda:

Como se mencionó en otra respuesta, creé una página HTML como parte de la extensión de mi navegador que ejecuta mis pruebas. La página HTML incluye la biblioteca Jasmine, más el código JavaScript de mi extensión, más mi conjunto de pruebas. Las pruebas se ejecutan automáticamente y los resultados están formateados para usted. No es necesario construir un corredor de prueba o un formateador de resultados. Simplemente siga las instrucciones de instalación , y use el HTML documentado allí para crear su página de corredor de prueba, e incluya también su conjunto de pruebas en la página.

No creo que pueda obtener el marco de Jasmine dinámicamente desde otro host, por lo que acabo de incluir el lanzamiento de Jasmine en mi extensión. Lo omitiré y también mis casos de prueba cuando construya mi extensión para producción, por supuesto.

No he visto cómo ejecutar mis pruebas en la línea de comando. Eso sería útil para las herramientas de implementación automatizadas.

Jon A
fuente