如何测试 chrome 扩展?

     2023-02-22     128

关键词:

【中文标题】如何测试 chrome 扩展?【英文标题】:How to test chrome extensions? 【发布时间】:2011-02-21 15:02:06 【问题描述】:

有什么好办法吗?我正在编写一个扩展,它作为内容脚本与网站交互并使用本地存储保存数据。是否有任何工具、框架等可用于测试此行为?我意识到有一些通用工具可以测试 javascript,但是这些工具是否足以测试扩展?单元测试是最重要的,但我也对其他类型的测试(例如集成测试)感兴趣。

【问题讨论】:

我刚刚写了一个规范的答案,它解决了跨所有浏览器的浏览器扩展的单元测试和集成测试,而不仅仅是 Chrome。见the answer to "Testing browser extensions"。 【参考方案1】:

要测试端到端,您可以使用puppeteer。 这是我为扩展程序编写的 sn-p,用于检查加载的扩展程序 title 并验证扩展程序是否在隐身模式下启用。

const path = require("path");
const puppeteer = require("puppeteer");
const assert = require("assert");
const Constants = require("../contants");
const Utils = require("./util");

const extensionID = Constants.EXTENSION_ID;
const extensionPath = path.join(__dirname, "../dist");
const extensionOptionHtml = "option.html";
const extPage = `chrome-extension://$extensionID/$extensionOptionHtml`;
let extensionPage = null;
let browser = null;

async function boot() 
  browser = await puppeteer.launch(
    // slowMo: 250,
    headless: false, // extension are allowed only in head-full mode
    args: [
      `--disable-extensions-except=$extensionPath`,
      `--load-extension=$extensionPath`,
      "--no-sandbox",
      "--disable-setuid-sandbox"
    ]
  );

  extensionPage = await browser.newPage();
  await extensionPage.goto(extPage);


describe("Extension UI Testing", function() 
  this.timeout(20000); // default is 2 seconds and that may not be enough to boot browsers and pages.
  before(async function() 
    await boot();
  );

  describe("option page home", async function() 
    it("check title", async function() 
      const h1 = "Allow extension in Incognito Mode";
      const extH1 = await extensionPage.evaluate(() =>
        document.querySelector("h1").textContent.trim()
      );
      assert.equal(extH1, h1);
    );
    it("show option ui after enabling extension in incognito", async () => 
      await extensionPage.goto(`chrome://extensions/?id=$extensionID`);
      extensionPage.evaluate(() =>
        document
          .querySelector("body > extensions-manager")
          .shadowRoot.querySelector("#viewManager > extensions-detail-view")
          .shadowRoot.querySelector("#allow-incognito")
          .shadowRoot.querySelector("#crToggle")
          .click()
      );
      await Utils.sleep(2000);
      await extensionPage.goto(
        `chrome-extension://$extensionID/$extensionOptionHtml`
      );
      const h3 = "Mark Incognito";
      const headingID = `#$Constants.OPTION_SCRIPT_HOST_ID > div > div > header > div > h6`;
      await extensionPage.waitFor(headingID);
      console.log( headingID );
      const extH3 = await extensionPage.evaluate(headingID => 
        return document.querySelector(headingID).textContent.trim();
      , headingID);
      console.log( extH3 );
      assert.equal(extH3, h3);
    );
  );

  after(async function() 
    await browser.close();
  );
);

【讨论】:

【参考方案2】:

在处理几个 chrome 扩展时,我提出了 sinon-chrome 项目,该项目允许使用 mochanodejsphantomjs 运行单元测试。

基本上,它会创建所有chrome.* API 的 sinon 模拟,您可以在其中放置任何预定义的 json 响应。

接下来,您使用节点的 vm.runInNewContext 加载脚本作为背景页面,使用 phantomjs 加载脚本弹出/选项页面。

最后,你断言 chrome api 是用所需的参数调用的。

举个例子: 假设我们有一个简单的 chrome 扩展,可以在按钮徽章中显示打开的标签页数。

背景页面:

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

为了测试它,我们需要:

    模拟chrome.tabs.query 以返回预定义的响应,例如两个标签。 将我们模拟的chrome.* api 注入到某个环境中 在这个环境中运行我们的扩展代码 断言按钮标记等于“2”

sn-p 代码如下:

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

现在我们可以将它包装到 mocha 的 describe..it 函数中并从终端运行:

$ mocha

background page
  ✓ should display opened tabs count in button badge

1 passing (98ms)

你可以找到完整的例子here。

此外,sinon-chrome 允许触发任何具有预定义响应的 chrome 事件,例如

chrome.tab.onCreated.trigger(url: 'http://google.com');

【讨论】:

该示例的链接似乎已失效 - 您能否更新一下? 更新了示例链接。 sinon-chrome 现在也移到了github.com/acvetkov,很快就会有新的例子 注意:项目似乎已过时:最后一次提交是在 2019 年 11 月 26 日,问题仍未得到解答。【参考方案3】:

为了确认之前的几个答案,Jasmine 似乎与 Chrome 扩展程序配合得很好。我使用的是 3.4.0 版本。

您可以使用Jasmine spies 轻松为各种 API 创建测试替身。无需从头开始构建自己的。例如:

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

  );

);

更多细节,如果有帮助的话:

正如另一个答案中提到的,我创建了一个 HTML 页面作为运行测试的浏览器扩展的一部分。 HTML 页面包括 Jasmine 库、我的扩展程序的 JavaScript 代码以及我的测试套件。测试会自动运行,结果会为您格式化。无需构建测试运行程序或结果格式化程序。只需关注installation instructions,并使用其中记录的 HTML 来创建您的测试运行器页面,并将您的测试套件也包含在该页面中。

我认为您不能从其他主机动态获取 Jasmine 框架,因此我只是将 Jasmine 版本包含在我的扩展中。当然,当我为生产构建扩展时,我会省略它以及我的测试用例。

我还没有研究如何在命令行中执行我的测试。这对于自动化部署工具会很方便。

【讨论】:

【参考方案4】:

我发现我可以使用 Selenium 网络驱动程序 来启动带有预安装扩展程序的全新浏览器实例,并使用 pyautogui 进行点击 - 因为 Selenium 无法驱动扩展程序的“视图”。点击后,您可以截取屏幕截图并将它们与“预期”的截图进行比较,预计有 95% 的相似度(因为在不同的浏览器上,标记移动到几个像素是可以接受的)。

【讨论】:

【参考方案5】:

虽然sinon.js 似乎工作得很好,但您也可以只使用普通的 Jasmine 并模拟您需要的 Chrome 回调。示例:

Mock

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

只需修改默认的SpecRunner.html 即可运行您的代码。

【讨论】:

【参考方案6】:

是的,现有的框架非常有用..

最近,我将所有测试都放在了嵌入到应用程序中但无法访问的“测试”页面上,除非进行物理输入。

例如,我可以在chrome-extension://asdasdasdasdad/unittests.html 下访问页面中的所有测试

测试可以访问localStorage 等。对于访问内容脚本,理论上您可以通过测试页面中的嵌入式 IFRAME 进行测试,但是这些是更多集成级别的测试,单元测试需要您将其抽象出来来自真实页面,这样您就不必依赖它们,同样可以访问 localStorage。

如果您想直接测试页面,您可以编排扩展程序以打开新标签页 (chrome.tab.create("url" : "someurl")。对于每个新标签页,您的内容脚本都应该运行并你可以使用你的测试框架来检查你的代码是否已经完成了它应该做的事情。

对于框架,JsUnit 或更新的Jasmine 应该可以正常工作。

【讨论】:

你说得对,测试真实页面不属于单元测试。我应该让我的问题更广泛。但这仍然是我想测试的东西,特别是因为网站的 html 结构随时可能发生变化。我已经修改了问题。 我仍然会在您的单元测试页面中通过 IFrame 进行测试。内容脚本仍应触发(如果您允许脚本在 iFrame 中运行) 代理示例扩展有一些测试,这些测试只是模拟了一些必要的 Chrome API:code.google.com/chrome/extensions/samples.html#chrome.proxy .. 我们的同事 Boris 也使用 QUnit 来测试他的“模型”层: github.com/borismus/Question-Monitor-for-Stack-Exchange/tree/…【参考方案7】:

关于 Chrome 中已有的工具:

    在 chrome 开发者工具中,有用于本地存储的资源部分。

    开发者工具 > 资源 > 本地存储

    查看本地存储的变化。

    您可以使用 console.profile 来测试性能并观察运行时调用堆栈。

    for fileSystem 您可以使用此 URL 检查您的文件是否已上传: 文件系统:chrome-extension:///temporary/

如果您同时使用内容脚本和本地存储,而没有后台页面/脚本且没有消息传递,则只能从该站点访问本地存储。 因此,要测试这些页面,您必须在这些选项卡中注入测试脚本。

【讨论】:

对我不起作用,但它确实让我在我的 javascript 中走得更远。为此 +1。 对于文件系统可以使用:filesystem:chrome-extension:///temporary/

如何在chrome中方便快捷地切换分辨率(chrome浏览器分辨率测试)

如何在Chrome中方便快捷地切换分辨率?使用Chrome插件ResolutionTest!!!1.下载Chrome插件ResolutionTest.crx2.浏览器--更多工具--扩展程序页面--开发者模式3.将ResolutionTest.crx用鼠标拖放到扩展程序页面4.Chrome会弹出安装插件的提示.点击继续即可... 查看详情

命令行 chrome 扩展加载和测试

】命令行chrome扩展加载和测试【英文标题】:Commandlinechromeextensionloadingandtesting【发布时间】:2015-09-0414:16:36【问题描述】:我目前在chromium浏览器的chrome://extensions页面上使用“开发者模式”,通过单击“重新加载(Ctrl+R)”来加载... 查看详情

如何从 JS 开发控制台访问用 Chrome 扩展编写的功能?

】如何从JS开发控制台访问用Chrome扩展编写的功能?【英文标题】:HowtogetaccesstofunctionswritteninChromeextensionfromtheJSdevconsole?【发布时间】:2013-03-2419:08:27【问题描述】:我希望能够从Chrome中的JS控制台调用我在Chrome扩展程序中编写... 查看详情

如何在chrome浏览器安装第三方扩展

简单教你·Chrome浏览器如何安装第三方扩展程序谷歌在2012年ChromeV21+开始禁止第三方扩展静默安装,2014年ChromeV30+开始任何非Chrome网上应用店(ChromeWebStore)下载的扩展将自动停用。自己瞎折腾一个Chrome插件crx打包之后拖进chrome://exten... 查看详情

使用 selenium 加载 chrome 扩展

...网上商店加载一个chrome扩展。在我的研究中,我只发现了如何从本地机器加载扩展。selenium是否可以从WebStore加载扩展程序?【问题讨论】:一个选项是每次运行测试脚本时使用java从webstore下载crx文 查看详情

如何在chrome下使用postman进行rest请求测试

...行测试,通过测试后才开始在开发中使用。这里介绍一下如何在chrome浏览器利用postman应用进行restfulapi接口请求测试。http://jingyan.baidu.com/article/90808022ff18defd91c80f9a.html详细可以参考这个,有图解教程,希望可以帮到你参考技术A1、... 查看详情

如何给selenium.chrome写扩展拦截或转发请求(代码片段)

SeleniumWebDriver是一组开源API,用于自动测试Web应用程序,利用它可以通过代码来控制chrome浏览器!有时候我们需要mock接口的返回,或者拦截和转发请求,今天就来实现这个功能代码已开源:https://github.com/yu... 查看详情

如何安装webdriverchrome浏览器支持

参考技术A1、先进入Chrome网上应用店,进入方法有多种,可以直接在浏览器地址栏输入应用店的地址或者点击“设置”→“扩展程序”→“安装扩展程序”2、在左侧搜索框输入扩展程序的名称,可以用全名精确搜索,也可以键入... 查看详情

如何开发一个chrome扩展

chrome是一个不错的浏览器,web开发者工作中一般都会使用chrome做为默认浏览器,它有很多扩展,给浏览器补充了各种功能,增强了用户体验。chrome具体能干什么?怎么做出来的呢?chrome扩展是什么?本质上是HTML+CSS+JavaScript组成... 查看详情

如何同步 chrome 扩展选项

】如何同步chrome扩展选项【英文标题】:Howtosyncchromeextensionoptions【发布时间】:2011-05-1123:06:46【问题描述】:我制作了一个带有选项页面的Chrome扩展程序。数据保存在本地存储中并且可以正常工作。Chrome不会将本地存储同步到... 查看详情

Chrome 扩展程序:如何在 chrome 扩展程序更新后删除孤立的脚本

】Chrome扩展程序:如何在chrome扩展程序更新后删除孤立的脚本【英文标题】:Chromeextension:Howtoremoveorphanedscriptafterchromextensionupdate【发布时间】:2019-12-1910:45:25【问题描述】:我有一个带有弹出页面的chrome扩展,它通过简单的一次... 查看详情

如何创建通知 chrome 扩展?

】如何创建通知chrome扩展?【英文标题】:Howtocreateanotificationchromeextension?【发布时间】:2013-09-1819:25:51【问题描述】:我想创建一个googlechrome扩展程序,在mysql数据库中添加新记录时通知用户!有人可以帮助我吗?谢谢。【问题... 查看详情

Chrome 扩展:本地存储,如何导出

】Chrome扩展:本地存储,如何导出【英文标题】:ChromeExtension:LocalStorage,howtoexport【发布时间】:2014-06-0308:17:48【问题描述】:我有一个chrome扩展,可以将一堆数据保存到chrome.storage.local。我试图找到简单的方法来导出这些数据并... 查看详情

如何使用 WebStorm 进行 Chrome 扩展开发?

】如何使用WebStorm进行Chrome扩展开发?【英文标题】:HowdoIuseWebStormforChromeExtensionDevelopment?【发布时间】:2012-12-0911:11:35【问题描述】:我刚刚购买了WebStorm5,到目前为止,我一直非常喜欢它的检查功能。我在开发Chrome扩展程序... 查看详情

如何与电子中的chrome扩展背景页面通信?

】如何与电子中的chrome扩展背景页面通信?【英文标题】:Howtocommunicatewithchromeextensionbackgroundpageinelectron?【发布时间】:2022-01-2101:31:49【问题描述】:由于电子没有实现chrome.runtime.onMessageExternal。我们如何在main或renderer进程中与c... 查看详情

如何在 Chrome 扩展中使用 fontawesome?

】如何在Chrome扩展中使用fontawesome?【英文标题】:HowtousefontawesomeinChromeExtension?【发布时间】:2017-05-0509:18:23【问题描述】:我正在开发一个显示在特定网站上的GoogleChrome扩展程序。我想在我的chrome扩展中使用Fontawesome。当我尝... 查看详情

如何链接到 chrome 扩展中的选项页面?

】如何链接到chrome扩展中的选项页面?【英文标题】:Howdoyoulinktotheoptionspageinachromeextension?【发布时间】:2013-01-2914:03:49【问题描述】:我有一个带有optionspage的chrome扩展程序。选项页面可以正常工作,我可以从扩展页面访问它... 查看详情

Chrome 扩展:如何禁用页面可见性 API

】Chrome扩展:如何禁用页面可见性API【英文标题】:ChromeExtension:HowtoDisablePageVisibilityAPI【发布时间】:2018-05-1912:42:18【问题描述】:我正在编写一个Chrome扩展程序,它需要防止网页触发documentvisibilitychange事件。至少我需要能够覆... 查看详情