Wie teste ich Chrome-Erweiterungen?

154

Gibt es eine gute Möglichkeit, dies zu tun? Ich schreibe eine Erweiterung, die mit einer Website als Inhaltsskript interagiert und Daten mithilfe von localstorage speichert. Gibt es Tools, Frameworks usw., mit denen ich dieses Verhalten testen kann? Mir ist klar, dass es einige generische Tools zum Testen von Javascript gibt, aber sind diese ausreichend leistungsfähig, um eine Erweiterung zu testen? Unit-Tests sind am wichtigsten, aber ich interessiere mich auch für andere Arten von Tests (z. B. Integrationstests).

Sumpfjohn
quelle
8
Ich habe gerade eine kanonische Antwort geschrieben, die sich mit Unit-Tests und Integrationstests für Browser-Erweiterungen für alle Browser befasst, nicht nur für Chrome. Siehe die Antwort auf "Testen von Browsererweiterungen" .
Rob W

Antworten:

111

Ja, die vorhandenen Frameworks sind ziemlich nützlich.

In der jüngeren Vergangenheit habe ich alle meine Tests auf einer "Testseite" platziert, die in die Anwendung eingebettet war, aber nur physisch eingegeben werden kann.

Zum Beispiel hätte ich alle Tests auf einer Seite unter zugänglich chrome-extension://asdasdasdasdad/unittests.html

Die Tests hätten Zugriff auf localStorageusw. Für den Zugriff auf Inhaltsskripte könnten Sie dies theoretisch über eingebettete IFRAMEs auf Ihrer Testseite testen. Bei diesen Tests handelt es sich jedoch eher um Tests auf Integrationsebene. Bei Komponententests müssten Sie diese von realen Seiten abstrahieren, damit Sie hängen Sie nicht von ihnen ab, auch nicht mit Zugriff auf localStorage.

Wenn Sie Seiten direkt testen möchten, können Sie Ihre Erweiterung so orchestrieren, dass neue Registerkarten geöffnet werden (chrome.tab.create ({"url": "someurl"}). Für jede der neuen Registerkarten sollte Ihr Inhaltsskript ausgeführt werden und Sie können verwenden Ihr Test-Framework, um zu überprüfen, ob Ihr Code das getan hat, was er tun sollte.

Bei Frameworks sollte JsUnit oder das neuere Jasmine einwandfrei funktionieren.

Kinlan
quelle
1
Sie haben Recht, das Testen realer Seiten fällt nicht unter Unit-Tests. Ich hätte meine Frage breiter stellen sollen. Aber es ist immer noch etwas, das ich gerne testen würde, zumal sich die HTML-Struktur der Website jederzeit ändern kann. Ich habe die Frage geändert.
Sumpfjohn
1
Ich würde immer noch über IFrames auf Ihrer Unit-Test-Seite testen. Die Inhaltsskripte sollten weiterhin ausgelöst werden (wenn Sie die Ausführung der Skripte im iFrame aktivieren)
Kinlan,
3
Die Proxy-Beispielerweiterung enthält einige Tests, die nur die erforderlichen Teile der Chrome-APIs verspotten: code.google.com/chrome/extensions/samples.html#chrome.proxy . Auch unser Kollege Boris hat QUnit zum Testen verwendet seine "Modell" -Schicht: github.com/borismus/Question-Monitor-for-Stack-Exchange/tree/…
Paul Irish
63

Bei der Arbeit an mehreren Chrome-Erweiterungen habe ich ein sinon-chromeProjekt entwickelt, mit dem Unit-Tests mit ausgeführt werden könnenmocha , nodejsund phantomjs.

Grundsätzlich werden sinon-Mocks aller chrome.*APIs erstellt, in die Sie vordefinierte JSON-Antworten einfügen können.

Als Nächstes laden Sie Ihre Skripte mithilfe von Knoten vm.runInNewContext für die Hintergrundseite undphantomjs für die Render-Popup- / Optionsseite.

Und schließlich behaupten Sie, dass Chrome API mit den erforderlichen Argumenten aufgerufen wurde.

Nehmen wir ein Beispiel:
Nehmen wir Angenommen, wir haben eine einfache Chrome-Erweiterung, die die Anzahl der geöffneten Registerkarten im Schaltflächenabzeichen anzeigt.

Hintergrundseite:

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

Um es zu testen, brauchen wir:

  1. spotten chrome.tabs.query , um eine vordefinierte Antwort zurückzugeben, z. B. zwei Registerkarten.
  2. spritzen unsere verspotteten chrome.* API in eine Umgebung
  3. Führen Sie unseren Erweiterungscode in dieser Umgebung aus
  4. behaupten, dass das Button-Badge gleich '2' ist

Das Code-Snippet lautet wie folgt:

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

Jetzt können wir es in Mokkas describe..itFunktionen einwickeln und vom Terminal aus ausführen:

$ mocha

background page
  ✓ should display opened tabs count in button badge

1 passing (98ms)

Sie können das vollständige Beispiel finden hier .

Darüber hinaus ermöglicht Sinon-Chrome das Auslösen eines beliebigen Chrome-Ereignisses mit vordefinierter Antwort, z

chrome.tab.onCreated.trigger({url: 'http://google.com'});
Vitalets
quelle
Der Link für das Beispiel scheint tot zu sein - könnten Sie ihn bitte aktualisieren?
Erhöht
1
Link zum Beispiel aktualisiert. Auch Sinon-Chrom wird jetzt auf github.com/acvetkov verschoben und es wird bald neue Beispiele geben
vitalets
3

Es sinon.jsscheint zwar großartig zu funktionieren, aber Sie können auch einfach Jasmine verwenden und die benötigten Chrome-Rückrufe verspotten. Beispiel:

Spotten

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

Prüfung

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

Ändern Sie einfach die Standardeinstellung SpecRunner.html, um Ihren Code auszuführen.

serv-inc
quelle
2

Informationen zu bereits vorhandenen Tools in Chrome:

  1. Im Chrome-Entwicklertool gibt es einen Abschnitt für Ressourcen für den lokalen Speicher.

    Entwicklertools> Ressourcen> Lokaler Speicher

    Sehen Sie sich dort die Änderungen von localstorage an.

  2. Mit console.profile können Sie die Leistung testen und den Aufrufstapel zur Laufzeit überwachen.

  3. für Dateisystem Mit dieser URL können Sie überprüfen, ob Ihre Datei hochgeladen wurde oder nicht: Dateisystem: Chrome-Erweiterung: /// temporär /

Wenn Sie Inhaltsskript und lokalen Speicher zusammen ohne Hintergrundseite / Skript und ohne Nachrichtenübermittlung verwenden, kann nur von dieser Site aus auf den lokalen Speicher zugegriffen werden. Um diese Seiten zu testen, müssen Sie Ihr Testskript in diese Registerkarten einfügen.

Nafis Ahmad
quelle
1
Hat bei mir nicht funktioniert, aber es hat mich in meinem Javascript weiter gebracht. +1 dafür.
Mobibob
Für Dateisystem Sie können Folgendes verwenden: Dateisystem: Chrome-Erweiterung: // <Ihre Erweiterungs-ID> / temporär /
Nafis Ahmad
1

Ich habe festgestellt, dass ich den Selenium-Webtreiber verwenden kann Webtreiber zum Starten einer neuen Browserinstanz mit vorinstallierter Erweiterung und pyautogui für Klicks verwenden kann, da Selenium die "Ansicht" der Erweiterung nicht steuern kann. Nach dem Klicken können Sie Screenshots erstellen und diese mit den erwarteten vergleichen, wobei Sie 95% der Ähnlichkeit erwarten (da in verschiedenen Browsern Markup-Bewegungen bis zu einigen Pixeln akzeptabel sind).

Vitaly Zdanevich
quelle
0

Um einige frühere Antworten zu bestätigen, scheint Jasmine gut mit Chrome-Erweiterungen zu funktionieren. Ich verwende Version 3.4.0.

Sie können Jasmine-Spione verwenden , um auf einfache Weise Test-Doubles für die verschiedenen APIs zu erstellen. Sie müssen Ihre eigenen nicht von Grund auf neu erstellen. Beispielsweise:

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

  });

});

Noch ein paar Details, wenn es hilft:

Wie in einer anderen Antwort erwähnt, habe ich als Teil meiner Browsererweiterung eine HTML-Seite erstellt, auf der meine Tests ausgeführt werden. Die HTML-Seite enthält die Jasmine-Bibliothek sowie den JavaScript-Code meiner Erweiterung und meine Testsuite. Die Tests werden automatisch ausgeführt und die Ergebnisse für Sie formatiert. Sie müssen keinen Testläufer oder Ergebnisformatierer erstellen. Befolgen Sie einfach die Installationsanweisungen und verwenden Sie den dort dokumentierten HTML-Code, um Ihre Testrunner-Seite zu erstellen, und fügen Sie Ihre Testsuite ebenfalls in die Seite ein.

Ich glaube nicht, dass Sie das Jasmine-Framework dynamisch von einem anderen Host abrufen können, deshalb habe ich nur die Jasmine-Version in meine Erweiterung aufgenommen. Ich werde es und auch meine Testfälle weglassen, wenn ich meine Erweiterung für die Produktion baue, natürlich.

Ich habe mir nicht angesehen, wie ich meine Tests in der Befehlszeile ausführen soll. Dies wäre praktisch für automatisierte Bereitstellungstools.

Jon A.
quelle