Como testar extensões do Chrome?

154

Existe uma boa maneira de fazer isso? Estou escrevendo uma extensão que interage com um site como um script de conteúdo e salva dados usando o armazenamento local. Existem ferramentas, estruturas etc. que posso usar para testar esse comportamento? Sei que existem algumas ferramentas genéricas para testar javascript, mas essas são poder suficiente para testar uma extensão? O teste de unidade é o mais importante, mas também estou interessado em outros tipos de teste (como teste de integração).

swampsjohn
fonte
8
Acabei de escrever uma resposta canônica que aborda testes de unidade e testes de integração para extensões de navegador em todos os navegadores, não apenas no Chrome. Consulte a resposta para "Testando extensões do navegador" .
Rob W

Respostas:

111

Sim, as estruturas existentes são bastante úteis.

No passado recente, coloquei todos os meus testes em uma página de "teste" incorporada ao aplicativo, mas não acessível, a menos que digitado fisicamente.

Por exemplo, eu teria todos os testes em uma página acessível em chrome-extension://asdasdasdasdad/unittests.html

Os testes teriam acesso a localStorageetc. Para acessar scripts de conteúdo, em teoria, você poderia testar isso através de IFRAMEs incorporados em sua página de teste; no entanto, esses são mais testes de nível de integração, os testes de unidade exigiriam que você abstraísse isso das páginas reais para que você não dependa deles, da mesma forma com acesso ao localStorage.

Se você quiser testar as páginas diretamente, poderá orquestrar sua extensão para abrir novas guias (chrome.tab.create ({"url": "someurl"})). Para cada uma das novas guias, seu script de conteúdo deve ser executado e você pode usar sua estrutura de teste para verificar se seu código fez o que deve fazer.

Quanto às estruturas, o JsUnit ou o Jasmine mais recente devem funcionar bem.

Kinlan
fonte
1
Você está certo, o teste de páginas reais não se enquadra no teste de unidade. Eu deveria ter tornado minha pergunta mais ampla. Mas ainda é algo que eu gostaria de testar, especialmente porque a estrutura html do site pode mudar a qualquer momento. Eu modifiquei a pergunta.
Swampsjohn
1
Ainda testaria através de IFrames na sua página de teste de unidade. Os scripts de conteúdo ainda deve fogo (se você permitir que os scripts sejam executados no iFrame)
Kinlan
3
A extensão de exemplo de proxy possui alguns testes que apenas zombam dos bits e APIs necessários: code.google.com/chrome/extensions/samples.html#chrome.proxy . Também nosso colega Boris usou o QUnit para testar sua camada "modelo": github.com/borismus/Question-Monitor-for-Stack-Exchange/tree/…
Paul Irish
63

Trabalhando em várias extensões do Chrome, criei um sinon-chromeprojeto que permite executar testes de unidade usando mocha, nodejse phantomjs.

Basicamente, ele cria zombarias sinon de toda chrome.*API, nas quais você pode colocar qualquer resposta json predefinida.

Em seguida, você carrega seus scripts usando os nós da vm.runInNewContextpágina de segundo plano e phantomjspara renderizar a janela pop-up / opções.

E, finalmente, você afirma que a API do Chrome foi chamada com os argumentos necessários.

Vamos dar um exemplo:
suponha que tenhamos uma extensão simples do chrome que exibe o número de guias abertas no emblema do botão.

página de fundo:

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

Para testá-lo, precisamos:

  1. mock chrome.tabs.querypara retornar uma resposta predefinida, por exemplo, duas guias.
  2. injetar nossa chrome.*API ridicularizada em algum ambiente
  3. execute nosso código de extensão neste ambiente
  4. afirmar que o emblema do botão é igual a '2'

O trecho de código é o seguinte:

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"
});

Agora podemos envolvê-lo nas describe..itfunções do mocha e executar no terminal:

$ mocha

background page
  ✓ should display opened tabs count in button badge

1 passing (98ms)

Você pode encontrar um exemplo completo aqui .

Além disso, o sinon-chrome permite acionar qualquer evento chrome com resposta predefinida, por exemplo

chrome.tab.onCreated.trigger({url: 'http://google.com'});
vitalets
fonte
O link para o exemplo parece estar morto - você poderia atualizá-lo?
Raisen
1
Link atualizado para o exemplo. Agora, o sinon-chrome agora foi movido para github.com/acvetkov e em breve haverá novos exemplos
vitalets
3

Embora sinon.jspareça funcionar muito bem, você também pode usar o Jasmine simples e zombar dos retornos de chamada do Chrome que você precisa. Exemplo:

Zombar

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

Teste

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

Basta modificar o padrão SpecRunner.htmlpara executar seu código.

serv-inc
fonte
2

Sobre a ferramenta já existente no Chrome:

  1. Na ferramenta de desenvolvedor do chrome, há uma seção para Recursos para armazenamento local.

    Ferramentas do desenvolvedor> Recursos> Armazenamento local

    Veja as alterações do armazenamento local lá.

  2. Você pode usar o console.profile para testar o desempenho e observar a pilha de chamadas em tempo de execução.

  3. para fileSystem Você pode usar este URL para verificar se o seu arquivo foi carregado ou não: filesystem: chrome-extension: /// temporary /

Se você usar o script de conteúdo e o armazenamento local juntos, sem a página / script em segundo plano e sem passar a mensagem, o armazenamento local estará acessível apenas nesse site. Portanto, para testar essas páginas, você deve injetar seu script de teste nessas guias.

Nafis Ahmad
fonte
1
Não funcionou para mim, mas me levou mais longe no meu javascript. +1 para isso.
mobibob
Para fileSystem Você pode usar: sistema de arquivos: cromo-extensão: // <yourextension-id> / temporário /
Nafis Ahmad
1

Descobri que posso usar o driver da web Selenium para iniciar uma nova instância do navegador com extensão pré-instalada e o pyautogui para cliques - porque o Selenium não pode impulsionar a "visualização" da extensão. Após os cliques, você pode fazer capturas de tela e compará-las com as 'esperadas', esperando 95% de semelhança (porque em navegadores diferentes são aceitáveis ​​movimentos de marcação para alguns pixels).

Vitaly Zdanevich
fonte
0

Para confirmar algumas respostas anteriores, o Jasmine parece funcionar bem com as extensões do Chrome. Estou usando a versão 3.4.0.

Você pode usar espiões Jasmine para criar com facilidade duplas de teste para as várias APIs. Não há necessidade de criar o seu próprio a partir do zero. Por exemplo:

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);

  });

});

Mais alguns detalhes, se ajudar:

Como mencionado em outra resposta, criei uma página HTML como parte da extensão do navegador que executa meus testes. A página HTML inclui a biblioteca Jasmine, além do código JavaScript da minha extensão, além do meu conjunto de testes. Os testes são executados automaticamente e os resultados são formatados para você. Não há necessidade de criar um executor de teste ou um formatador de resultados. Basta seguir as instruções de instalação e usar o HTML documentado lá para criar sua página do executor de testes e incluir seu conjunto de testes na página.

Eu não acho que você pode buscar a estrutura do Jasmine dinamicamente de outro host, então acabei de incluir o lançamento do Jasmine na minha extensão. Omitirei e também meus casos de teste quando construir minha extensão para produção, é claro.

Eu não olhei como executar meus testes na linha de comando. Isso seria útil para ferramentas de implantação automatizada.

Jon A
fonte