以下为作者观点:
多年来,自动化端到端测试是很多现代公司的标准做法,这样做可以让开发人员从后端到前端持续部署复杂的应用程序。
但是测试浏览器扩展程序又如何呢?通常用于测试的无头(headless)浏览器中对扩展程序的支持通常是实验性的,这在很大程度上阻碍了大多数测试运行器支持开箱即用的扩展程序测试。实际上,启动扩展并在页面视口之外与之交互通常需要新的应用程序编程接口(API)。
本文将特别关注 Chrome,并解释我们为主要浏览器扩展程序CS Live设置可靠的端到端 (E2E) 测试的过程。
CS Live:https://chromewebstore.google.com/detail/contentsquare-cs-live/bfkjochdalcdahjnliojhpldoogkbglc
CS Live 简要概述
Contentsquare 最显著的功能之一是基于区域的热图,它允许客户以覆盖其网站区域的叠加层形式查看指标。此功能作为我们主要 Web 应用程序中的一个模块实现,但由于它使用网站作为背景,我们认为它会成为一个完美的浏览器扩展。它使客户无需登录 Contentsquare 的 Web 应用程序即可查看其区域指标,从而更快地获得见解并简化团队协作。
在客户自己的网站上运行的 CS Live 扩展
端到端测试的重要性
端到端 (E2E) 测试是一种软件测试技术,通过模拟真实用户场景和复制实时数据来验证整个应用程序从头到尾的功能和性能。与单元测试不同,其目标是识别集成所有组件时出现的错误,确保应用程序作为统一实体提供预期的输出。
它们通常更难设置,但对于像 CS Live 这样与具有许多边缘情况的第三方网页的DOM进行广泛交互的扩展来说,它们仍然至关重要。
通过强大的 E2E 测试,团队可以更频繁、更自信地发布产品。
自动化扩展测试
让我们逐步了解为 Chrome 扩展程序设置端到端测试所需的所有步骤。
步骤1:生成CRX包
CRX包本质上是一个档案,包含在 Chrome 和其他基于 Chromium 的浏览器中安装和运行扩展所需的文件和元数据。
理想情况下,应该已经有一种自动构建 CRX 文件的方法作为发布过程的一部分。有多种方法可以做到这一点。以下是使用crxnpm 包的示例:
const fs = require("fs");
const path = require("path");
const ChromeExtension = require("crx");
const crx = new ChromeExtension({
privateKey: fs.readFileSync(path.resolve(__dirname, "./key.pem")),
});
const crxFile = path.resolve(__dirname, "cslive.crx");
crx
.load(path.resolve(__dirname, "../dist")) // The source of your extension
.then((crx) => crx.pack())
.then((crxBuffer) => fs.promises.writeFile(crxFile, crxBuffer, {}))
.then(() => console.log("CRX File generated"))
.catch((err) => {
console.error("Cannot generate CRX file", err);
});
步骤2:使用扩展程序启动无头 Chrome 实例
Contentsquare 广泛使用WebdriverIO框架来测试 Web 应用。虽然还有其他方法可以运行 Chrome 无头实例(例如Puppeteer),但我们选择扩展现有的 WebdriverIO 基础架构和配置文件,如下所示:
const fs = require("fs");
const path = require("path");
const csDefaultConfig = require("wdio-contentsquare-defaults.conf.js");
const crxFile = path.resolve(__dirname, "cslive.crx");
function getBrowserCapabilities() {
const { capabilities } = csDefaultConfig.config;
const options = capabilities[0]["goog:chromeOptions"];
options.extensions = [Buffer.from(fs.readFileSync(crxFile)).toString("base64")];
options.args = options.args.filter((arg) => arg !== "--disable-extensions" && arg !== "--headless");
options.args.push("--headless=new");
capabilities[0]["goog:chromeOptions"] = options;
}
csDefaultConfig.config.capabilities = getBrowserCapabilities();
module.exports = csDefaultConfig;
在上面的代码中,我们将 CRX 文件作为 base64 blob 传递,并调整命令行参数以启用扩展支持。
最重要的是,我们通过启用了Chrome 112+ 的新无头模式--headless=new。此模式依赖于更接近窗口化 Chrome 实例的新实现,从而可以进行扩展测试。
步骤 3:确保测试域已列入白名单
如果使用单独的域进行测试,可能需要在扩展程序的manifest.json文件中将其列入白名单,以使用诸如runtime.sendMessage()之类的API,这些API允许网页上下文连接到您的扩展程序。
"externally_connectable": {
"matches": [
"*://*.contentsquare.com/*",
"*://*.qa-website.local/*"
]
},
步骤4:导航到网站并激活扩展程序
作为测试的设置,我们打开目标网页并向扩展程序发送一条消息,通知它我们要启动测试会话。
为了无需交互登录即可连接到我们的服务,我们将JSON Web Token传递给扩展。
await browser.url("http://demo.qa-website.local/testpage.html");
const token = await getJwtTokenForTestUser();
const extension_id = "<hardcoded value>";
await browser.execute((token, extension_id) => {
// This code is executed in the browser context
return new Promise((resolve, reject) => {
window["chrome"].runtime.sendMessage(
extension_id,
{
command: "launch-e2e-test",
data: token,
},
() => {
const lastError = window["chrome"].runtime.lastError;
lastError ? reject(lastError) : resolve("Injected");
}
);
});
}, token, extension_id);
步骤5:在扩展中监听命令
Chrome 扩展程序的消息传递 API允许我们监听类似上一步中发送的消息。以下是我们在扩展程序中使用它来触发测试的方法:
function csListenForExternalMessages() {
chrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
if (message.command == 'launch-e2e-test') {
csSaveTokenToSessionStorage(message.data)
.then(() => chrome.tabs.query({ active: true, currentWindow: true }))
.then(async ([tab]) => {
await csEnableExtension(tab);
// Testing code is invoked here in the extension context
return csRunTest(tab);
})
.then((res) => sendResponse(res));
}
});
}
完成!你现在可以从测试代码中访问网页上下文和扩展上下文。你现在可以触发测试并验证其在页面上的结果是否正确。
最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】
软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。