Jak przetestować rozszerzenia Chrome?

154

Czy jest na to dobry sposób? Piszę rozszerzenie, które współdziała ze stroną internetową jako skrypt zawartości i zapisuje dane przy użyciu localstorage. Czy są jakieś narzędzia, struktury itp., Których mogę użyć do przetestowania tego zachowania? Zdaję sobie sprawę, że istnieje kilka ogólnych narzędzi do testowania javascript, ale czy są one wystarczająco mocne, aby przetestować rozszerzenie? Testowanie jednostkowe jest najważniejsze, ale interesują mnie również inne rodzaje testów (np. Testy integracyjne).

swampsjohn
źródło
8
Właśnie napisałem kanoniczną odpowiedź, która dotyczy testów jednostkowych i testów integracji rozszerzeń przeglądarki we wszystkich przeglądarkach, nie tylko w Chrome. Zobacz odpowiedź na temat „Testowanie rozszerzeń przeglądarki” .
Rob W

Odpowiedzi:

111

Tak, istniejące frameworki są całkiem przydatne.

Niedawno umieściłem wszystkie moje testy na stronie „testowej”, która była osadzona w aplikacji, ale nie była dostępna, chyba że została fizycznie wpisana.

Na przykład wszystkie testy miałbym na stronie dostępnej pod chrome-extension://asdasdasdasdad/unittests.html

Testy miałyby dostęp do localStorageitp. Aby uzyskać dostęp do skryptów zawartości, teoretycznie można sprawdzić, czy za pomocą osadzonych ramek IFRAME na stronie testowej są to bardziej testy na poziomie integracji, testy jednostkowe wymagałyby oderwania od prawdziwych stron, nie polegaj na nich, podobnie jak w przypadku dostępu do localStorage.

Jeśli chcesz bezpośrednio testować strony, możesz zaaranżować swoje rozszerzenie, aby otwierało nowe karty (chrome.tab.create ({"url": "someurl"}). Dla każdej nowej karty powinien działać skrypt zawartości. Możesz użyć framework testowy, aby sprawdzić, czy Twój kod zrobił to, co powinien.

Jeśli chodzi o frameworki, JsUnit lub nowszy Jasmine powinien działać dobrze.

Kinlan
źródło
1
Masz rację, testowanie prawdziwych stron nie podlega testom jednostkowym. Powinienem był rozszerzyć moje pytanie. Ale to wciąż coś, co chciałbym przetestować, zwłaszcza że struktura html strony może się zmienić w dowolnym momencie. Zmodyfikowałem pytanie.
swampsjohn
1
Testowałbym nadal za pomocą ramek iFrame na stronie testowej jednostki. Skrypty zawartości powinny nadal się uruchamiać (jeśli włączysz skrypty do uruchamiania w iFrame)
Kinlan
3
Przykładowe rozszerzenie proxy ma kilka testów, które po prostu kpią z niezbędnych fragmentów interfejsów API Chrome: code.google.com/chrome/extensions/samples.html#chrome.proxy . Również nasz kolega Boris użył QUnit do testów jego warstwa „model”: github.com/borismus/Question-Monitor-for-Stack-Exchange/tree/…
Paul Irish
63

Pracuje nad kilkoma rozszerzeniami chromowane wymyśliłem sinon-chromeprojekt, który pozwala uruchomić za pomocą testów jednostkowych mocha, nodejsi phantomjs.

Zasadniczo tworzy sinon makiety całego chrome.*interfejsu API, w którym można umieścić dowolne predefiniowane odpowiedzi json.

Następnie ładujesz swoje skrypty za pomocą węzła jako strony vm.runInNewContextw tle i phantomjswyskakującego okienka renderowania / strony opcji.

Na koniec zapewniasz, że wywołano chrome api z potrzebnymi argumentami.

Weźmy przykład:
Załóżmy, że mamy proste rozszerzenie Chrome, które wyświetla liczbę otwartych kart na plakietce przycisku.

strona w tle:

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

Aby to przetestować, potrzebujemy:

  1. mock, chrome.tabs.queryaby zwrócić predefiniowaną odpowiedź, np. dwie karty.
  2. wstrzyknąć nasz udawany chrome.*interfejs API do jakiegoś środowiska
  3. uruchomić nasz kod rozszerzenia w tym środowisku
  4. potwierdź, że znaczek przycisku jest równy „2”

Fragment kodu jest następujący:

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

Teraz możemy zawinąć go w describe..itfunkcje mokki i uruchomić z terminala:

$ mocha

background page
  ✓ should display opened tabs count in button badge

1 passing (98ms)

Pełen przykład można znaleźć tutaj .

Dodatkowo sinon-chrome pozwala na wywołanie dowolnego zdarzenia chrome z predefiniowaną odpowiedzią, np

chrome.tab.onCreated.trigger({url: 'http://google.com'});
witalety
źródło
Wydaje się, że link do przykładu jest martwy - czy mógłbyś go zaktualizować?
Raisen
1
Zaktualizowany link do przykładu. Również sinon-chrome został przeniesiony na github.com/acvetkov, a wkrótce pojawią się nowe przykłady
Vitalets
3

Choć sinon.jswydaje się doskonale, można też po prostu używać zwykłego jaśminu i drwić Chrome Callbacki potrzebujesz. Przykład:

Drwić

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

Test

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

Po prostu zmodyfikuj wartość domyślną, SpecRunner.htmlaby uruchomić kod.

serv-inc
źródło
2

O już istniejącym narzędziu w Chrome:

  1. W narzędziu programistycznym Chrome znajduje się sekcja Zasoby do lokalnego przechowywania.

    Narzędzia programistyczne> Zasoby> Pamięć lokalna

    Zobacz zmiany lokalnego magazynu.

  2. Możesz użyć console.profile do testowania wydajności i obserwowania stosu wywołań w czasie wykonywania.

  3. for fileSystem Możesz użyć tego adresu URL, aby sprawdzić, czy plik został przesłany, czy nie: filesystem: chrome-extension: ///porary /

Jeśli używasz skryptu zawartości i pamięci lokalnej razem bez strony / skryptu w tle i bez przekazywania wiadomości, pamięć lokalna będzie dostępna tylko z tej witryny. Tak więc, aby przetestować te strony, musisz wstrzyknąć swój skrypt testowy w tych zakładkach.

Nafis Ahmad
źródło
1
Nie zadziałało dla mnie, ale pomogło mi w dalszej pracy w javascript. +1 za to.
mobibob
Dla systemu plików Możesz użyć: filesystem: chrome-extension: // <yourextension-id> /porary /
Nafis Ahmad
1

Odkryłem, że mogę użyć sterownika sieciowego Selenium do uruchomienia nowej instancji przeglądarki z preinstalowanym rozszerzeniem i pyautogui dla kliknięć - ponieważ Selenium nie może sterować „widokiem” rozszerzenia. Po kliknięciu możesz zrobić zrzuty ekranu i porównać je z „oczekiwanymi”, spodziewając się 95% podobieństwa (ponieważ w różnych przeglądarkach dopuszczalne są ruchy znaczników do kilku pikseli).

Witalij Zdanevich
źródło
0

Aby potwierdzić kilka poprzednich odpowiedzi, Jasmine wydaje się dobrze współpracować z rozszerzeniami Chrome. Używam wersji 3.4.0.

Możesz użyć szpiegów Jasmine do łatwego tworzenia podwójnych testów dla różnych interfejsów API. Nie musisz budować własnego od podstaw. Na przykład:

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

  });

});

Więcej szczegółów, jeśli to pomoże:

Jak wspomniano w innej odpowiedzi, utworzyłem stronę HTML jako część rozszerzenia mojej przeglądarki, które uruchamia moje testy. Strona HTML zawiera bibliotekę Jasmine, kod JavaScript mojego rozszerzenia oraz mój zestaw testów. Testy są uruchamiane automatycznie, a wyniki są formatowane za Ciebie. Nie ma potrzeby tworzenia programu uruchamiającego testy ani programu do formatowania wyników. Po prostu postępuj zgodnie z instrukcjami instalacji i użyj udokumentowanego tam kodu HTML, aby utworzyć stronę do uruchamiania testów, a także dołączyć swój zestaw testów do strony.

Wydaje mi się, że nie można dynamicznie pobierać frameworka Jasmine z innego hosta, więc właśnie dołączyłem wydanie Jasmine do mojego rozszerzenia. Pominię to i oczywiście moje przypadki testowe, gdy będę budować rozszerzenie do produkcji.

Nie patrzyłem na to, jak wykonać moje testy w wierszu poleceń. Byłoby to przydatne w przypadku narzędzi do automatycznego wdrażania.

Jon A
źródło