PostHog Desktop 实战:基于本地 Django 技术栈驱动 Electron 应用的后端到桌面 E2E 测试
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
本文围绕 PostHog 仓库中桌面端(products/desktop)的测试技能参考文档 local-django-stack.md 展开,讲解如何以最精简的本地服务组合(Docker 数据服务 + Django + 根 Vite + Electron 开发进程)跑通一次真实的"后端到桌面"端到端测试。读完后你将掌握:最小技术栈的规划与启动顺序、通过真实 OAuth 流程完成桌面端登录、用Project.objects.create_with_team等方式正确播种测试数据,以及用 CDP 网络请求与可访问性快照逐层验证接口契约与 UI 的完整方法论。
一、工作流定位:什么场景下使用本流程
这份参考文档是 test-electron-app 技能 的配套参考资料。父技能负责"如何用 agent-browser 通过 CDP 协议(默认:9222)驱动真实运行的 PostHog Electron 应用",而本文聚焦其中一个子场景:当被测功能依赖真实后端数据时,如何搭建并驱动一套本地 Django 技术栈来做聚焦式(focused)的后端到桌面 E2E 测试。
文档给出的核心原则是两条:
- 范围要窄("Keep it scoped to the API and desktop surface under test")——只启动被测接口和桌面界面真正依赖的服务;
- 尊重已有进程——启动任何东西之前先检查现有进程,复用不属于你的服务,永远不要停止开发者自己启动的 Electron 实例。
1.1 最小栈规划
文档明确建议"选择能覆盖被测契约的最小技术栈",其组成与取舍如下:
| 组件 | 何时需要 |
|---|---|
| 被测端点所需的 Docker 数据服务 | 总是(按端点实际依赖选择) |
| 运行在本地 PostHog URL 上的 Django | 总是 |
| 根 Vite 前端 | 当被测页面是登录页、OAuth 页面等由 Django 托管的页面时需要 |
| 桌面端 Electron 开发进程 | 总是(本 E2E 的被测对象) |
文档特别警告:不要为了一个不触碰摄入(ingestion)、Celery、Temporal 或插件服务器的测试就去启动全部 worker——"全量技术栈 + 一次原生桌面端重建"叠加在一起,足以把一台小规格虚拟机压垮。这是本工作流区别于"把整个开发环境拉起来再测"的关键纪律。
二、环境准备:从 monorepo 根目录开始
在仓库根目录下准备依赖(文档原文步骤完整保留):
bootstrap-dev-stack uv sync pnpm install --frozen-lockfile --prefer-offlinebootstrap-dev-stack:按需准备 cloud-task 环境;uv sync:同步 Python 依赖(Django 后端);pnpm install --frozen-lockfile --prefer-offline:以锁定文件为准安装前端/桌面端依赖,优先走离线缓存。
紧接着是一条容易被忽略但决定测试成败的约定:在运行 Django 之前,先加载仓库提交的服务环境(service environment),让 Postgres、ClickHouse、Redis 解析到与迁移(migrations)所用完全相同的服务实例;同时加载仓库中已提交的开发用 OAuth 签名密钥(committed development OAuth signing key),且不要 source 任何无关的示例配置——混入错误的环境变量是本地 OAuth 联调最常见的隐性故障源。
三、启动 Django 与 Vite:用健康检查代替"进程活着"
文档要求Django 和根 Vite 作为两个独立的长生命周期进程运行,并给出一条明确的就绪判定准则:
轮询
http://localhost:8010/_health,不要相信启动器(launcher)的退出码作为就绪信号。
也就是说,进程启动成功 ≠ 服务可用。PostHog 后端自带健康检查端点(见 health 模块),测试脚本应以 HTTP 轮询通过作为唯一进入下一步的依据。这一准则同样适用于 Electron 侧:父技能中给出的做法是轮询curl -s localhost:9222/json/version,而不是盲目sleep。
前端页面层由根 Vite 提供。登录页、OAuth 页面这类由 Django 模板渲染但需要前端资源的页面,依赖该 Vite 进程;如果本次测试不经过这些页面,就可以跳过它——这正是"最小栈"原则的体现。
四、启动桌面端 Electron 开发进程
从products/desktop目录启动,复用已安装依赖,并按父技能描述拉起 Electron。针对无头(headless)场景,文档补充了关键细节:在 root 权限运行的 Linux 虚拟机上,需要为这个一次性的开发进程使用虚拟显示(virtual display)并设置 Electron 的禁用沙箱(sandbox-disable)环境变量。
父技能 SKILL.md 给出了无 TTY 环境下的完整启动配方,值得与本文档配合使用:
pnpm build:deps # turbo 构建 @posthog/code 依赖(TTY 安全) tail -f /dev/null | pnpm dev:code # 后台运行并保持存活其中pnpm dev:code即pnpm --filter code start,等价于electron-vite dev --watch——只启动应用本身、不拉起phrocsTUI 进程复用器(后者在没有控制终端的后台 shell 中会直接中止)。而 CDP 调试端口并非 CLI 参数传入,而是应用在开发模式下自行开启的:Electron 主进程启动逻辑 中,仅当isDev时追加remote-debugging-port开关,端口默认9222、可通过POSTHOG_CODE_CDP_PORT覆盖:
if (isDev) { app.commandLine.appendSwitch( "remote-debugging-port", process.env.POSTHOG_CODE_CDP_PORT ?? "9222", ); }两个脚本入口分别定义在 products/desktop/package.json 中:dev:code与app:cdp(后者负责检查 agent-browser 是否安装、应用是否在:9222上可达,然后建立连接)。
五、通过真实 OAuth 流程完成认证
这是文档中"契约即证据"思想的集中体现,规则如下:
- 使用应用内的真实登录路径。开发版 Electron 有独立的认证状态(dev 实例使用独立的
posthog-code-dev配置文件/数据目录),在应用内选择Local development,然后在浏览器会话中完成 Electron 生成的 OAuth URL——目标就是localhost:8010上你刚拉起的 Django 栈。 - 让 Cookie 与 CSRF 状态留在浏览器里:使用常规登录表单,或发起页面内的
/api/login/请求,而不是手工拼请求。随后授权应用,让它的 localhost 回调把登录态交还给 Electron。 - 禁止作弊式通过:不要改写 scope、也不要手工把 token 塞进桌面端存储来"让登录通过"。文档的措辞很直接——如果授权成功了但 Desktop 里没有项目,去检查 OAuth token 的 scope 以及
/api/users/@me/和组织/项目请求;那是契约证据(contract evidence),不是需要绕过的环境噪音(setup noise)。
后端侧的登录链路可以对照 Django 视图入口 理解:login_required包装器在 cloud-OAuth 模式下允许客户端侧会话而不要求本地登录,这正是桌面端走真实 OAuth 流程时后端需要配合的行为。
六、打开被测界面前先播种前置数据
文档把"播种"单列一节,核心方法论是:在创建 fixture 之前,先追踪该端点的每一个服务端依赖。凡是配置指向内部项目、对象存储或分析数据库的字段,都需要真实存在且相互匹配的数据行。
6.1 项目与团队:必须成对创建
通过
Project.objects.create_with_team(...)或既有的 bootstrap 助手创建项目与团队。不要直接创建Team行——一个 team 必须依赖它配对的Project。
这一点在源码中得到印证:Project 管理器 的create_with_team在单个原子事务内完成两件事——用Team.objects.increment_id_sequence()生成共享主键,先创建Project,再用同一id调用Team.objects.create_with_data(...)创建配对的Team,保证两者 id 一致、关系完整。仓库中的测试 test_project.py 也全部以Project.objects.create_with_team(...)作为标准建数据姿势:
project, team = Project.objects.create_with_team( organization=organization, name="Project name", )6.2 ClickHouse 侧 fixture 的四条规则
对依赖 ClickHouse 的 fixture,文档给出四条可操作规则:
- 确认活动数据库是
posthog而不是default——连错库是最隐蔽的数据缺失原因; - 如果相关 worker 正在运行,优先走摄入(ingestion)路径写入数据,与生产行为保持一致;
- 否则,可以有意识地使用既有的测试 fixture 助手,并用生产环境同款查询验证插入的行(不要假设写入成功);
- 时间戳要晚于任务的创建时间,且必须匹配查询用到的每一个归因属性——分析类查询普遍带时间窗与属性过滤,差一个字段数据就"不存在"。
6.3 UI 挂载条件也要播种
文档举了一个典型例子:如果界面只在某个运行时状态存在时才挂载,那么该状态本身也要播种。以"任务成本指示器"为例,它除了任务记录外,还需要一次任务运行和会话日志中一条有效的用量更新(usage update),查询 hook 才会渲染。"API 通了但 UI 空着"往往不是前端 bug,而是运行时状态缺失。
七、逐层验证契约与 UI
在应用内打开被测界面后,用 agent-browser 检查网络层:
agent-browser network requests然后按文档给出的五层清单逐项验证:
- 端点返回预期的状态码;
- 其 JSON 响应包含桌面端读取的每一个字段;
- 可访问性快照(accessibility snapshot)中能看到该值出现在指示器里;
- 打开弹出层(popover)时显示预期的明细拆分;
- 刷新并重放交互,结果保持一致(幂等性与稳定性验证)。
这一清单体现了"状态码 200 不等于通过"的严格标准:响应字段完整性(第 2 层)与渲染结果(第 3、4 层)分别对应契约的两端,而第 5 层则排除了偶发成功。
文档还规定了两条执行纪律:
- 失败时读 Django 日志拿准确异常,不要靠猜;
- 修掉范围内的 PR bug 后继续同一次 E2E 运行,而不是在第一个可操作的失败处就收工——一次运行应尽可能走完全部验证层。
八、收尾:进程治理约定
与开头"尊重已有进程"呼应,文档的收尾约定是:测试结束后保持 Electron 运行(按父技能说明处理);只停止本次运行自己启动的进程。这保证了开发者自己的实例不受影响,后续交互无需重新拉起整条链路。
九、小结:这套工作流可迁移的方法论
把 local-django-stack.md 抽象开,它沉淀了五条可复用的 E2E 测试纪律:
- 最小栈原则:按被测契约反推依赖,拒绝"全量拉起";
- 轮询就绪信号:以
/_health、CDP/json/version等可探测端点代替进程退出码; - 走真实认证链路:OAuth 全流程在浏览器中完成,把认证异常当作契约证据而非环境噪音;
- 数据播种与查询对齐:成对创建领域对象(
Project/Team)、用生产查询回验、时间戳与归因属性全匹配; - 分层验证 + 失败不提前收工:状态码 → 响应字段 → 可访问性快照 → 交互展开 → 刷新重放,五层全过才算通过,中途修复后继续同一次运行。
配套延伸阅读:test-electron-app 技能主文档(CDP 连接、快照循环、截图策略与无头启动配方)、桌面端 package.json 脚本、Electron 主进程启动逻辑、Project/Team 模型。
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考