Karma 在 Semaphore CI 上的持续集成接入指南

原创2026-09-22 17:47:231,930 阅读
文章标签:测试开发工具

Karma 在 Semaphore CI 上的持续集成接入指南

本指南面向使用 Karma 作为 JavaScript 测试运行器的团队,讲解如何将 Karma 测试接入 Semaphore CI 云构建服务:从 package.json 中声明测试脚本,到在 Semaphore 上配置自定义构建命令,最终让每次代码推送都自动在 PhantomJS 或 Firefox 中完成单次测试运行。读完本文,你将掌握一套可直接复制到实际项目的 Semaphore + Karma 持续集成配置方案,并理解 Karma 单次运行模式与浏览器启动器在 CI 场景下的底层工作方式。

为什么选择 Semaphore 作为 Karma 的测试环境

Semaphore 是一个流行的持续集成(CI)服务,支持广泛的编程语言生态。对 JavaScript 项目而言,它最大的价值在于构建环境中预置了较新版本的 Firefox、PhantomJS 与 Node.js,这使得它非常适合作为 JavaScript 应用的测试场地——你不需要自己在容器里折腾浏览器安装,Semaphore 已经为 Karma 这类需要真实浏览器环境的测试运行器做好了准备。

本文假设你已经拥有一个 Semaphore 账户,并且项目中已经初始化了 Node.js 项目(存在 package.json)。下面的步骤将把 Karma 测试无缝接入 Semaphore 的构建流程。

第一步:在 package.json 中声明 Karma 与测试命令

Semaphore 的构建流程以 npm 为核心:它通过 npm install 安装依赖、通过 npm test 触发测试。因此,接入 Semaphore 的第一步是让项目根目录存在一个规范的 package.json,它同时承担"文档化配置"和"让测试易于运行"两个职责。

如果你还没有 package.json,请先在项目根目录创建它,并声明 Karma 依赖与测试脚本:

// ...snip...
"devDependencies": {
  "karma": "~0.10"
},
// ...snip...
"scripts": {
   "test": "./node_modules/.bin/karma start --single-run --browsers PhantomJS"
}
// ...snip...

这段配置包含两个关键部分:

  • devDependencies 中的 karma:把 Karma 作为开发依赖安装。npm install 时它会被正确解析,因为 Semaphore 的 Node.js 环境默认并不知晓 Karma 这类模块,显式声明才能保证 CI 上可用。
  • scripts.test:定义了 npm test 的实际行为。命令中的两个参数是 Karma 在 CI 场景下的核心开关:
    • --single-run:让 Karma 在浏览器被捕获并完成测试后自动退出进程——这正是 CI 需要的"跑完即返回"语义,进程会以测试结果作为退出码供 CI 判断构建成败;
    • --browsers PhantomJS:指定本次运行要启动的浏览器为 PhantomJS(无头浏览器,无需图形界面)。

关于 --single-run 与 --browsers 这两个参数,可以在仓库的 lib/cli.js 中找到它们的官方释义:--single-run 是 "Run the test when browsers captured and exit."(捕获浏览器后运行测试并退出),--browsers 则接受逗号分隔的浏览器列表(例如 --browsers Chrome,ChromeCanary,Firefox)。从 lib/cli.js 的解析逻辑可以看到,browsers 参数会按逗号切分成数组,最终注入到 Karma 配置中驱动浏览器启动。

配置完成后,在项目根目录运行 npm test,即可在本地验证 Karma 是否能在 PhantomJS 中完成测试。

第二步:改用 Firefox 作为测试浏览器(可选)

如果你更倾向使用真实浏览器而非无头浏览器,只需把测试脚本的浏览器参数替换为 Firefox:

"scripts": {
   "test": "./node_modules/.bin/karma start --single-run --browsers Firefox"
}

这里需要留意一个前置条件:Karma 的浏览器启动器(launcher)通常以插件形式存在。根据仓库 docs/config/03-browsers.md 的说明,大多数浏览器启动器需要作为插件加载,例如安装 Firefox 启动器:

npm install karma-firefox-launcher --save-dev

然后在 Karma 配置文件的 browsers 数组中声明浏览器。如果你在 CI 上直接指定 --browsers Firefox 却遇到启动失败,最常见的原因就是对应的 launcher 插件未被安装。这一点在仓库的 lib/launcher.js 中也有印证——当 Karma 无法在依赖注入容器中找到 launcher:Firefox 之类的提供者时,会输出日志 "Cannot load browser ... it is not registered! Perhaps you are missing some plugin?"(无法加载浏览器,可能缺少某个插件)。

另外,PhantomJS 和 Firefox 这类浏览器的可执行文件路径可以通过环境变量覆盖(例如 PHANTOMJS_BIN),当 CI 上的浏览器二进制不在默认路径时非常实用,详见 docs/config/03-browsers.md 中的 "Correct path to browser binary" 一节。

第三步:把项目添加到 Semaphore

登录 Semaphore 后,按照其官方文档中"添加 GitHub/Bitbucket 项目"的流程(screencast 演示)把仓库挂载到 Semaphore。关键操作点如下:

  1. 等待 Semaphore 完成项目分析。分析阶段 Semaphore 会自动探测项目类型,并可能为项目设置一个默认的语言/运行时版本;
  2. 忽略 Semaphore 自动设置的 Ruby 版本。这是 Semaphore 分析器的默认行为,对 JavaScript 项目没有意义;
  3. 选择自定义构建命令(Customize your build commands),填入以下两条:
npm install
npm test
  • npm install 负责安装 package.json 中声明的所有依赖(包括 Karma 与浏览器 launcher 插件);
  • npm test 触发我们在第一步中定义的测试脚本,Karma 将启动浏览器执行单次测试并退出。

配置完成后即可开始首次构建。若使用 Firefox 作为测试浏览器,Semaphore 会在构建期间自动通过虚拟屏幕(virtual screen)运行 Firefox,你无需额外编写 xvfb 之类的启动脚本——这是 Semaphore 内置的能力。

如果后续需要调整,Semaphore 允许在任意时刻进一步自定义构建命令,例如在 npm test 之前执行额外的构建步骤(如编译、打包),或在安装阶段做缓存处理。

深入理解:CI 场景下 Karma 的底层工作机制

要真正用好这套配置,理解 Karma 在 --single-run 模式下做了什么会很有帮助。结合当前仓库源码,可以梳理出以下关键事实:

1. 配置与 CLI 参数的合并

Karma 的配置可以通过 karma.conf.js 文件或命令行参数给出。lib/cli.js 会先寻找默认配置文件(依次尝试 ./karma.conf.js、./karma.conf.coffee、./karma.conf.ts 等),再与命令行参数合并,命令行参数优先级更高。仓库的配置模板 config.tpl.js 展示了完整可用的配置骨架,其中与 CI 直接相关的两个字段是:

// start these browsers
browsers: ['Chrome'],

// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,

注意模板中 singleRun 默认为 false(监听模式),而 CI 配置必须将其置为 true 或通过 --single-run 参数覆盖——这正是 Semaphore 集成时 npm test 命令的职责所在。

2. 浏览器是如何被"启动"的

当 Karma 服务启动时,lib/launcher.js 会根据配置中的 browsers 数组逐个创建启动器:launch() 方法接收浏览器名称列表,为每个名称通过依赖注入查找对应的 launcher:<Name> 提供者,并以默认并发度(config.concurrency,模板中为 Infinity)调度启动任务。每个启动器继承自 lib/launchers/base.js 中的 BaseLauncher,经历 BEING_CAPTURED → CAPTURED 的状态机转换——浏览器打开 Karma 服务器地址(默认端口 9876,定义于 lib/constants.js)后完成"捕获"。

--single-run 模式则意味着:所有配置的浏览器被捕获、测试运行完毕之后,Karma 进程自动结束,退出码反映测试成败,从而被 Semaphore 正确判定构建结果。

3. 当前仓库自身的 CI 实践

有趣的是,Karma 仓库自身的 package.json 就是这套模式的直接示范:它通过 scripts 把单元测试、端到端测试和客户端测试组合成一条 npm test 链:

"test:unit": "mocha \"test/unit/**/*.spec.js\"",
"test:e2e": "cucumber-js test/e2e/*.feature",
"test:client": "node bin/karma start test/client/karma.conf.js",
"test": "npm run test:unit && npm run test:e2e && npm run test:client"

其中 test:client 正是以 karma start <config> 的形式驱动 Karma 配置运行。这套"npm scripts 组合 + Karma 单次运行"的模式可以直接迁移到任何接入 Semaphore 的 JavaScript 项目。

版本与兼容性说明

文档示例中的 "karma": "~0.10" 属于早期历史版本。当前仓库中 Karma 的版本为 6.4.4(见 package.json),并声明 engines.node >= 10。接入 Semaphore 时建议直接声明 "karma": "^6" 或安装当前最新稳定版,并确保 Semaphore 构建环境中 Node.js 版本满足要求——虽然 Semaphore 默认预置了较新的 Node.js,但建议在项目分析阶段确认所选 Node 版本与本地开发环境一致,避免因版本差异导致的兼容性问题。

常见问题排查要点

  • "Cannot load browser" 错误:对应 launcher 插件未安装。检查是否执行过 npm install karma-firefox-launcher --save-dev(Firefox)或 karma-phantomjs-launcher(PhantomJS),并确认它们出现在 devDependencies 中,因为 CI 的 npm install 只会安装声明过的依赖。
  • 浏览器无法启动:检查 CI 环境中浏览器可执行文件路径,必要时通过 PHANTOMJS_BIN 等环境变量指定路径,参见 docs/config/03-browsers.md。
  • 测试跑完但进程不退出:确认测试命令包含 --single-run,或配置文件中 singleRun: true;否则 Karma 会进入监听模式导致 CI 构建挂起。
  • 构建命令被 Semaphore 分析器覆盖:记得在项目设置中切换到"自定义构建命令",使用 npm install 与 npm test,并忽略分析器自动生成的 Ruby 版本设置。

总结

将 Karma 接入 Semaphore CI 只需三步:在 package.json 中声明 Karma 依赖与 --single-run 测试脚本、按官方流程把项目挂载到 Semaphore、在构建命令中填入 npm install && npm test。整个过程充分利用了 Semaphore 预置的 PhantomJS/Firefox 环境,以及它对 Firefox 虚拟屏幕的自动支持,无需额外维护 CI 脚本。配合对 lib/cli.js 与 lib/launcher.js 源码的理解,你可以在遇到问题时快速定位是配置、插件还是环境变量的问题,让 JavaScript 项目的每一次代码推送都自动获得可靠的测试保障。

登录后查看全文
karma