
Teleport E2E 测试指南基于 Playwright 的真实实例端到端测试框架【免费下载链接】teleportThe easiest, and most secure way to access and protect all of your infrastructure.项目地址: https://gitcode.com/gh_mirrors/tel/teleportTeleport 的e2e/目录内置了一套完整的端到端E2E测试体系它基于 Playwright测试目标是一个真实启动的 Teleport 实例而非 mock 或 stub覆盖 Web UI、SSH 节点、Kubernetes 与 Teleport Connect 桌面应用的完整用户链路。本文以仓库中的 e2e/README.md 为骨架结合 runner 源码e2e/runner/main.go、e2e/runner/flags.go与配置模板e2e/config/teleport.yaml.tmpl展开帮助你掌握这套框架的启动方式、运行模式、flag 用法、fixture 机制、多用户/多角色建模、自定义 Teleport 配置以及会话录制Session Recordings的注入原理从而能够独立编写和调试面向真实 Teleport 集群的 E2E 测试。目录概览E2E 测试套件如何组织e2e/目录的顶层结构如下仓库根目录相对路径e2e/run.sh统一入口脚本负责编译 Go runner 并执行e2e/runner/Go 编写的测试运行器构建二进制、生成证书、启动 Teleport、编排 fixture、扫描测试文件中的声明e2e/tests/Playwright 测试用例分为web/Web UI与connect/Teleport Connect 桌面应用两大类e2e/helpers/测试辅助库登录、认证状态、WebAuthn mock、页面对象等e2e/config/Teleport 配置与状态模板teleport.yaml.tmpl、state.yaml.tmple2e/testdata/测试数据包括roles/自定义角色 YAML与recordings/会话录制e2e/playwright.config.tsPlaywright 项目配置定义了chromium/firefox/webkit各自的:authenticated与:unauthenticated项目以及connect项目。从 e2e/package.json 可以看到依赖只有playwright/test、tsx、undici、cbor-x等少量 devDependencies测试本身是纯 TypeScript Playwright。环境准备Setup运行器每次执行都会自动安装 E2E 依赖并下载 Playwright 浏览器但也可以手动准备环境pnpm install pnpm exec playwright install chromium仓库根目录的pnpm-workspace.yaml表明项目使用 pnpm 管理 JS 工作区因此直接使用pnpm即可。如果只想跑 Chromiumplaywright install chromium只下载这一个浏览器内核需要 Firefox/WebKit 时用playwright install全部安装CI 中默认会在三种浏览器上运行详见下文。运行测试run.sh 与 Go runner测试统一通过 e2e/run.sh 启动./e2e/run.sh [flags] [test files...]可以在e2e/目录、仓库根目录或任意其他目录调用它——runner 会把test-result/下的路径重写为相对于当前工作目录的路径因此 Playwright 生成的截图、trace 等产物仍可直接点击跳转。run.sh 内部做了两件事如果参数指向企业版测试e/e2e/*则转交给e/e2e/run.sh否则进入e2e/runner目录以GOWORKoff go build -o e2e .编译 Go runner 并执行。从源码结构看Go runner 是这套体系的“总调度”在 e2e/runner/main.go 的run()中依次完成端口分配allocatePorts、二进制构建build、自签名证书生成generateSelfSignedCert、扫描测试声明、生成 Teleport 配置、创建并惰性启动 Teleport 实例与 Docker 节点最后把控制权交给playwrightRunner.run(ctx, mode)。多个浏览器实例各自持有独立的 proxy/auth 端口与数据目录端口在启动时一次性分配以减小竞争窗口。运行模式Modes默认是测试模式。通过以下互斥 flag 切换其他模式Flag说明--ui打开 Playwright UI 模式可交互式挑选并运行测试--debug以 Playwright inspector 运行测试等价于PWDEBUG1--codegen针对正在运行的 Teleport 打开 Playwright codegen仅 Web 测试可用--browse打开一个已登录的浏览器用于手工 Web 测试--browse-connect打开已登录的 Teleport Connect 应用用于手工测试这些模式在 e2e/runner/flags.go 中通过modeSet注册并有额外校验例如--browse/--codegen只支持单个浏览器多个浏览器会直接报错--ui不支持 Connect 测试Connect 运行在 Electron 而非浏览器中。Flags 一览Flag默认值说明-vfalse开启 debug 日志--no-buildfalse跳过make构建二进制开发期非常有用--no-resource-setupfalse跳过测试前的资源准备--quietfalse将 Teleport 日志重定向到文件而非 stdout--replace-certsfalse重新生成自签名证书--update-snapshotsfalse更新 Playwright 快照基线--teleport-log-levelINFOTeleport 日志级别DEBUG/INFO/WARN/ERROR--license-file空Teleport 许可证文件路径Enterprise 功能必需--teleport-binbuild/teleport覆盖 teleport 二进制路径环境变量TELEPORT_BIN--tctl-binbuild/tctl覆盖 tctl 二进制路径环境变量TCTL_BIN--teleport-url空覆盖 Teleport URL环境变量TELEPORT_URL。设置后 runner 跳过启动 Teleport与 README 表格相比源码中还暴露了以下额外能力--browsers逗号分隔的浏览器列表chromium,firefox,webkit。默认在本地只跑chromiumCI 中三种都跑见 e2e/runner/main.go 中flags.browsers nil的分支--report PR/--test-results PR下载并打开指定 PR 的 Playwright 报告或 trace二者互斥--github-report仅 CI 使用将测试结果发布为 GitHub annotations、job summary 与 PR 评论--with-name手动启用 fixture见下节。参数校验逻辑同样在 flags.go 中--teleport-log-level与--browsers都有白名单校验非法值会直接拒绝运行--teleport-bin/--tctl-bin/--teleport-url支持环境变量覆盖stringFlagWithEnv。注意 main.go 中--teleport-bin只有指向仓库内build/teleport或e/build/teleport时才会触发对应目录的构建逻辑指向自定义路径则不会重建。Fixtures按需启动的测试基础设施Fixture 是可选的基础设施组件如 SSH 节点或 Teleport Connect从测试文件自动探测。当测试声明test.use({ fixtures: [ssh-node] })时runner 自动启动所需基础设施Fixture说明ssh-node启动并接入一个 Teleport SSH 节点运行在 Docker 中ssh-node-bpf第二个节点docker-node-bpf启用 Enhanced Session Recording增强会话录制kube启动一个 kind 支撑的 Kubernetes 集群并在主进程中启用 Teleportkubernetes_serviceconnect构建 Teleport Connect。由 Connect 测试辅助代码自动探测Fixture 也可以手动启用--with-name如--with-ssh-node、--with-connect在--codegen、--browse这类不做自动探测的模式下很有用。从源码看fixture 的注册中心在 e2e/runner/fixtures/fixtures.go四个 fixture 通过register()注册BindFlags为每个 fixture 生成--with-nameflag测试侧的类型定义在生成的 e2e/helpers/fixtures.ts 中。实际使用示例见 e2e/tests/web/authenticated/ssh.spec.ts它通过test.use({ fixtures: [ssh-node] })声明节点随后在测试中连接docker-node并执行命令。runner 只会启动本次运行真正需要的节点只声明ssh-node就只起docker-node只声明ssh-node-bpf就只起docker-node-bpf两者都声明则两个容器都起——这让一个 spec 可以直接对比“启用增强录制”与“未启用增强录制”的节点行为。ssh-node-bpf 需要 Linux Docker 主机该 fixture 在 macOS 上的 Docker 几乎必然无法工作。原因是容器没有自己的内核BPF 程序加载到 Docker 宿主机的内核中而 macOS 上OrbStack 和 Docker Desktop 的宿主是一个精简的 VM 内核构建时未启用CONFIG_AUDIT导致task_struct没有sessionid字段可供命令钩子读取。该字段缺失于内核 BTFCO-RE 重定位无法解析程序加载失败。没有任何容器设置能给一个没有该字段的内核补上结构体字段。解决办法把DOCKER_HOST指向运行 Docker 的 Linux 机器。内核需要 BTF 和CONFIG_AUDIT标准 Ubuntu 或 Debian 内核两者都具备。runner 自己的探针会在特权容器中检查这两项你也可以手动复现同样的检查docker run --rm --privileged debian:bookworm-slim \ sh -c test -e /sys/kernel/btf/vmlinux test -e /proc/self/sessionidssh://协议可用包括~/.ssh/config里的Host别名因此浏览器仍可保持本地运行DOCKER_HOSTssh://userlinux-box ./e2e/run.sh --with-ssh-node-bpf e2e/tests/web/authenticated/ssh.spec.ts节点按 daemon 的架构构建而非固定 amd64bpf()系统调用不会经过架构模拟代理。在 macOS 上这意味着需要一个与 daemon 架构匹配的交叉编译器runner 会为检测到的架构自动选择amd64 主机用x86_64-unknown-linux-gnu-gccarm64 用aarch64-unknown-linux-gnu-gcc可用CC覆盖。在启动节点之前runner 会探测 daemon 内核见 e2e/runner/main.go 中的daemonSupportsBPF。CI 之外不支持的内核会降级为普通节点并导出E2E_SKIP_ENHANCED_RECORDING1让本地跑整个套件仍然全绿需要 BPF 的 spec 主动选择跳过import { skipEnhancedRecording } from gravitational/e2e/helpers/env; test.skip(skipEnhancedRecording, docker daemons kernel cannot run enhanced session recording);skipEnhancedRecording来自 e2e/helpers/env.ts其值正是读取E2E_SKIP_ENHANCED_RECORDING 1。在 CI 中不支持的内核会变成硬错误而非降级从而保证覆盖率不会悄然消失。如果节点因其他原因失败也会直接退出而非降级此时请检查e2e/docker-node-browser.log。用户与角色建模Users and Roles默认情况下runner 创建一个拥有access与editor角色的用户。需要自定义角色或 traits 的测试通过test.use()声明。用户名是自动生成的、人类可读的 ID如brave-falcon测试不需要指定名字。单用户最常见test.use({ user: { roles: [access, editor] }, });单数user形式会创建一个用户并自动以该用户登录。多用户需要多于一个用户的测试如 RBAC 测试使用users数组。至少一个用户必须带有loginAs: true用于指明测试以哪个用户身份认证test.use({ users: [ { roles: [access, editor], loginAs: true }, { roles: [{ file: gravitational/e2e/roles/viewer.yaml }] }, ], });Traits用户可以指定 Teleport traits。内建 trait 键logins、kubernetes_groups、db_names等在UserTraits接口中有类型定义见 e2e/helpers/test.ts 中的UserTraits也支持自定义键test.use({ user: { roles: [access], traits: { logins: [root, alice], kubernetes_groups: [dev] }, }, });省略 traits 时默认为{ logins: [root] }。从 YAML 文件加载自定义角色对于 Teleport 内建角色之外的角色引用 e2e/testdata/roles/ 下的 YAML 文件仓库现包含rbac-no-allow.yaml、rbac-read-access.yaml、rbac-session-list.yaml、rbac-session-read.yaml、web-terminal-no-copy.yamltest.use({ user: { roles: [{ file: gravitational/e2e/roles/rbac-read-access.yaml }], }, });gravitational/e2e/roles/前缀会被剥离文件从e2e/testdata/roles/加载角色名取自 YAML 中的metadata.name。自定义角色文件会去重因此多个用户可引用同一个文件。usernamefixture已登录用户的生成用户名以usernamefixture 值暴露用于测试断言。测试中途切换用户RBAC 风格测试需要中途换人时使用loginAsfixture。它接收users数组的下标直接交换页面缓存的会话状态无需走 UI 登录流程因此切换近乎瞬时test.use({ users: [ { roles: [access], loginAs: true }, { roles: [editor] }, ], }); test(switch users, async ({ page, loginAs }) { // 测试开始时以 users[0] 登录 // ... const { name: editorName, recordingIds } await loginAs(1); // 现在以 users[1] 登录editorName 是生成的用户名 // recordingIds 是 users[1] 的录制映射 });从 e2e/helpers/test.ts 的实现看loginAs会读取 runner 写出的user-mapping.json找到该用户的生成名通过authStateFor(name)拿到其 cookies/localStorage 状态清空并注入当前 context 的 cookies同时把页面绑定的 WebAuthn mock 重绑定到新用户最后重新导航注入 localStorage 并 reload。作用域test.use()遵循 Playwright 常规作用域规则——放在test.describe()内则仅对该组生效放在文件顶层则作用于文件内所有测试。账户隔离runner 为每个 spec 提供各自独立的引导账户即使两个 spec 声明了相同的user/users。具体规则未声明test.use({ user/users })、且处于需要认证的项目web 的:authenticated项目与connect项目中的测试回退到共享的默认access/editor用户显式声明test.use({ user: { roles: [...] } })的测试总是获得全新账户即使角色与默认用户相同也彼此独立两个 spec 声明完全相同的test.use({ user: ... })时会按 spec 路径获得不同账户同一 spec 内当test.use()解析结果完全一致时共享一个账户要强制隔离可通过改变 traits 或使用users数组条目按下标区分。工作原理简述runner 在服务端生成凭据在 setup 阶段通过 HTTP/v1/webapi/mfa/login/*为每个用户登录并把生成的 cookies localStorage 写入e2e/.auth/browser-username.json。测试通过 Playwright 的storageState拾取该状态因此在测试开始时已处于认证状态无需执行 UI 登录流程。runner 侧对应的实现见 e2e/runner/usercredentials.go 与 e2e/runner/bootstrap.go后者负责构建 bootstrap 状态并写出user-mapping.json、user-credentials.json、recording-mapping.json等映射文件。自定义 Teleport 配置如果测试需要与 e2e 默认基础配置不同的 Teleport 配置可在test.describe()块内用test.use({ teleport: { config: {...} } })声明。值按 JS 对象字面量求值因此必须是静态的不能有 import 或函数调用test.describe(custom license, () { test.use({ teleport: { config: { auth_service: { license_file: ${E2E_DIR}/testdata/licenses/custom-license.pem, }, }, }, }); });注意e2e runner 只会用不同配置重启 Teleport而不会从零重新初始化因此数据目录保持不变——集群身份cluster name、CA、已引导的用户与角色会原样延续到所有测试。声明式配置还可以通过test.use({ teleport: { env: {...} } })设置仅对该配置的 Teleport 重启生效的进程环境变量。这些变量不会被默认配置或其他声明式配置继承避免某个配置专用的变量泄漏到无关测试中test.describe(cloud license, () { test.use({ teleport: { config: { auth_service: { license_file: ${E2E_DIR}/testdata/licenses/cloud-license.pem, }, }, env: { TELEPORT_CLOUD_HOSTPORT: api.cloud.gravitational.io, }, }, }); });默认配置模板见 e2e/config/teleport.yaml.tmpl它给出了 e2e 测试的基础形态auth_service启用本地认证 WebAuthnrp_id: localhost、proxy_service启用多路复用监听proxy_listener_mode: multiplex、ssh_service默认关闭、kubernetes_service仅在提供 kubeconfig 时启用。模板注释还解释了为什么启用trust_x_forwarded_forWeb API 的限流器按客户端 IP 分桶否则整个运行共享一个桶以及proxy_protocol_allow_downgrade测试声明 IPv6 地址而连接目的地的 localhost 在某些机器上解析为::1、在 CI 容器中是127.0.0.1降级可覆盖 IPv4 情况。runner 侧的配置扫描与去重逻辑见 e2e/runner/scan.go 与 e2e/runner/teleport_config.go。将 spec 限制到特定浏览器默认情况下Web spec 会在每个浏览器上运行。主题与浏览器无关的测试可以退出test.use({ browsers: [chromium] });如果测试同时声明了 Teleport 配置这一点尤其值得做——否则 runner 会为每个浏览器重复一次该配置的 Teleport 重启。该限制作用于整个文件而非某个 describe 块runner 在选择每个浏览器要运行的 spec 时会强制执行对应 e2e/runner/scan.go 中的scanBrowserRestrictions。会话录制Session Recordingsrunner 在启动时会自动把会话录制种子数据写入 Teleport 的数据目录让 Web UI 的会话录制页面立即可用。录制文件按会话类型组织在 e2e/testdata/recordings/ 下e2e/testdata/recordings/ ├── events.jsonl # 自动生成 - 不要编辑 ├── ssh/ │ ├── session-id.tar │ ├── session-id.metadata │ └── session-id.thumbnail ├── k8s/ │ └── ... └── desktop/ └── ...每条录制由一个.tar文件必需和可选的.metadata、.thumbnail边车文件组成。events.jsonl包含会话结束审计事件由.tar文件自动生成。添加新录制把.tar以及任何.metadata/.thumbnail放到合适的子目录ssh/、k8s/或desktop/即可。当前仓库的示例数据位于e2e/testdata/recordings/ssh/ssh-recording-1.tar及其 metadata/thumbnail。录制是选择加入的——只有被test.use()中的recordings或UserDefinition.recordings引用的录制才会被注入。每条录制与声明它的用户关联每个(recording, owner)对都会获得一个新生成的会话 ID因此不同用户间的重复不会冲突。recordingIdsfixture由于 runner 会重写会话 ID需要导航到特定录制的测试应通过recordingIdsfixture 查找生成后的 ID。它把逻辑 ID.tar文件名映射为当前活动用户的已注入会话 IDtest.use({ user: { roles: [access], recordings: [ssh-session-1] }, }); test(open recording, async ({ page, recordingIds }) { await page.goto(/web/recordings/${recordingIds[ssh-session-1]}); });运行时runner 会把录制文件复制到 Teleport 的记录目录并将审计事件追加到审计日志时间戳已调整让会话在 UI 中看起来是最近发生的。相关实现见 e2e/runner/recordings.go映射文件recording-mapping.json的读写分别在 runner 启动与 e2e/helpers/test.ts 的recordingIdsfixture 中完成。常用命令Common Commands开发测试时通常用--no-build跳过每次重建 Teleport 二进制用--quiet减少 Teleport 日志噪音日志会写入teleport.log供调试。运行tests/connect路径或使用--browse-connect时会自动构建 Connect。# 运行单个测试跳过重建最快的迭代回路 ./e2e/run.sh --no-build e2e/tests/web/authenticated/roles.spec.ts # 跳过重建与测试前资源准备 ./e2e/run.sh --no-build --no-resource-setup e2e/tests/web/authenticated/roles.spec.ts # 只跑 Connect 测试跳过 Teleport 与 Connect 的重建 ./e2e/run.sh --no-build e2e/tests/connect # 打开已认证的浏览器做手工测试 ./e2e/run.sh --browse # 打开已认证的 Connect 做手工测试 ./e2e/run.sh --browse-connect # 用 Playwright inspector 调试失败的测试 ./e2e/run.sh --debug e2e/tests/web/authenticated/roles.spec.ts # 打开 Playwright UI 模式交互式挑选并运行测试 ./e2e/run.sh --ui # 通过浏览器交互录制新测试 ./e2e/run.sh --codegen # 视觉变更后更新快照基线 ./e2e/run.sh --update-snapshots e2e/tests/web/authenticated/ssh.spec.ts更多示例More Examples# 运行全部测试 ./e2e/run.sh # 运行 SSH 节点测试fixture 自动探测 ./e2e/run.sh e2e/tests/web/authenticated/ssh.spec.ts # 运行全部测试跳过 Teleport 构建 ./e2e/run.sh --no-build # 针对已有 Teleport 实例运行目前尚不可用认证逻辑硬编码为 e2e setup远程实例的认证方案待解决 ./e2e/run.sh --teleport-url https://localhost:3080 # 将 Teleport 日志级别设为 DEBUG 以获取更详细的输出 ./e2e/run.sh --teleport-log-level DEBUG注意 README 明确标注--teleport-url指向远程实例“目前还不能工作”因为认证逻辑硬编码为 e2e 自己的 setup远程实例的认证方案仍在规划中——因此该 flag 当前更适合作为覆盖 runner 默认 URL 的机制来理解。小结这套框架的关键设计真实实例优先测试跑在真实启动的 Teleport 集群上配合真实 Docker SSH 节点与 kind Kubernetes 集群覆盖 Web UI 与 Connect 桌面端声明驱动用户、角色、traits、fixture、自定义配置、浏览器限制全部通过 Playwright 标准的test.use()声明runner 在 Go 侧扫描并自动编排见 e2e/runner/scan.go 与 e2e/runner/main.go认证免 UI 流程runner 启动时通过 HTTP 登录接口预先生成认证状态cookies localStorage测试通过storageState直接以已登录状态开始并支持loginAs近乎瞬时的用户切换优雅降级与 CI 硬约束Enhanced Session Recording 在本地遇到不支持的 Docker 内核时降级跳过并导出E2E_SKIP_ENHANCED_RECORDING1在 CI 中则升级为硬错误防止覆盖率静默丢失面向开发体验--no-build、--quiet、--browse、--codegen、--ui、--debug等模式让测试开发、手工验证与调试形成闭环。实际测试用例可继续阅读 e2e/tests/web/authenticated/如ssh.spec.ts、rbac.spec.ts、roles-crud.spec.ts与 e2e/tests/connect/如auth.spec.ts、kube.spec.ts结合 e2e/playwright.config.ts 中:authenticated、:unauthenticated、connect三类项目划分即可快速理解并上手编写面向真实 Teleport 的端到端测试。【免费下载链接】teleportThe easiest, and most secure way to access and protect all of your infrastructure.项目地址: https://gitcode.com/gh_mirrors/tel/teleport创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考