拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Langflow 前端 E2E 测试实践:Playwright 配置、自定义 Fixtures 与 data-testid 选择器体系

Langflow 前端 E2E 测试实践Playwright 配置、自定义 Fixtures 与 contenteditable="false">【免费下载链接】langflowLangflow is a powerful tool for building and deploying AI-powered agents and workflows.项目地址: https://gitcode.com/GitHub_Trending/la/langflowLangflow 的前端 E2E 测试体系基于 Playwright 构建核心是一套自动错误感知的自定义 fixture、以data-testid为主的选择器目录以及覆盖画布操作、Playground 会话、模板流程等完整用户路径的 spec 组织方式。本文以仓库中的 E2E 测试技能文档 SKILL.md 为骨架结合 playwright.config.ts、fixtures.ts 等源码逐一展开读完你可以掌握如何运行、过滤和调试 Langflow 的 E2E 测试如何编写符合规范的 spec标签、fixture 导入、选择器策略以及底层响应监控、错误契约、teardown 清理的实现原理。一、适用范围与技术栈这套技能文档明确划定了 E2E 测试的适用边界引自 SKILL.md 的 When to Apply 一节为功能或流程编写 E2E 测试时适用修复失败的 E2E 测试时适用评审 E2E 测试覆盖度时适用修改组件中的data-testid属性时适用可能破坏既有测试修改src/frontend/tests/utils/下的测试工具时适用。不适用的场景单元测试Jest前端*.test.tsx文件和后端测试pytest。技能文档给出的技术栈如下表。需要说明的是版本号以当前仓库实际依赖为准工具技能文档记录当前仓库实际用途Playwright1.59.11.60.0E2E 测试运行器 浏览器自动化Chromium内置内置默认浏览器Firefox/Safari 被禁用自定义 fixturestests/fixtures.ts同左自动检测 API 错误与 flow 执行失败当前 package.json 中playwright/test: 1.60.0且devDependencies中的playwright同为1.60.0。配置文件中 Firefox/Safari 项目均被注释掉只启用 Chromium 项目。二、运行命令与 WebServer 自启动机制2.1 常用命令# 运行全部 E2E 测试 npx playwright test # 按标签过滤运行 npx playwright test --grep release npx playwright test --grep workspace npx playwright test --grep starter-projects # 运行单个测试文件 npx playwright test tests/core/features/run-flow.spec.ts # 调试模式headed 浏览器 单步 npx playwright test --debug # 查看 HTML 报告 npx playwright show-report # 更新快照如有使用 npx playwright test --update-snapshots仓库还提供了一键脚本 run-tests.sh它负责安装 Playwright 浏览器、通过make frontend启动前端、用poetry run langflow run --backend-only --port 7860启动后端设置LANGFLOW_DATABASE_URLsqlite:///./temp与LANGFLOW_AUTO_LOGINTrue最后执行npx playwright test tests/core --projectchromium并在退出时通过 trap 清理 7860/3000 端口与临时数据库。tests/README.md 则建议日常开发用make tests_frontend入口运行。2.2 Playwright 自动拉起的服务栈从 playwright.config.ts 的webServer数组看Playwright 会按顺序自动启动三个服务OpenAI 兼容 mock 服务node tests/fixtures/openai-compatible-server.mjs健康检查地址http://127.0.0.1:8787/health。这使得 E2E 测试中的 LLM 调用不依赖真实 OpenAI 凭证。后端 APIuvicorn7860 端口uv run uvicorn --factory langflow.main:create_app \ --host localhost --port 7860 --loop asyncio \ --log-level error --no-access-log注入的关键环境变量见配置文件 L124-L137环境变量值作用LANGFLOW_DATABASE_URLsqlite:///./temp使用临时 SQLite 数据库测试后清理LANGFLOW_AUTO_LOGINtrue跳过登录页配合awaitBootstrapTestLANGFLOW_SUPERUSER/LANGFLOW_SUPERUSER_PASSWORDlangflow/ 测试口令提供固定超级用户LANGFLOW_DEACTIVATE_TRACINGtrue关闭追踪减少噪声LANGFLOW_LOG_LEVELERROR降低日志量OPENAI_API_KEY/OPENAI_BASE_URL本地回环 key /http://127.0.0.1:8787/v1把模型调用指向上面的 mock 服务LANGFLOW_A2A_ENABLEDtrue暴露 A2A 发现 JSON-RPC 端点供 Agent 标签页测试发布并调用真实 agent后端启动超时设为120 * 750毫秒量级的宽裕值timeout: 120 * 750并允许复用已存在的服务器reuseExistingServer: true避免重复冷启动。前端npm start即 Vite3000 端口通过VITE_PROXY_TARGEThttp://localhost:7860把/api请求代理到后端。2.3 关键配置项来自 playwright.config.ts 的实际取值配置值说明fullyParalleltrue测试文件并行执行timeout5 * 60 * 10005 分钟Flow 构建可能较慢防止误报超时retries1当前配置固定 1 次重试技能文档曾记录为本地 3 次/CI 2 次以当前配置为准workers2平衡速度与资源占用actionTimeout2000020 秒单个 actionclick、fill 等的超时traceon-first-retry首次重试时采集 trace便于事后调试baseURLhttp://localhost:${PORT \|\| 3000}/指向 Vite dev serverforbidOnlyCI 时强制开启防止test.only被意外提交testIgnore**/live/**排除 live 目录连接真实外部服务的测试reporterCI 用blob本地用listhtml本地报告输出到playwright-report/Chromium 项目额外授予了clipboard-read/clipboard-write权限用于覆盖剪贴板相关交互。三、目录结构与文件命名src/frontend/tests/ ├── fixtures.ts # 自定义 fixture错误检测 a11y 扫描钩子 ├── globalTeardown.ts # 收尾删除临时数据库 ├── a11y/ # 可访问性扫描辅助 ├── assets/ # 测试用文件资源uploadFile 的来源目录 ├── live/ # 连接真实外部服务的测试默认被忽略 ├── core/ │ ├── features/ # 主功能测试run-flow、playground 等 │ ├── integrations/ # Starter project / 模板测试 │ ├── regression/ # Bug 回归测试 │ └── unit/ # 组件级 Playwright 测试 └── utils/ # 37 个共享辅助函数extended/目录下平行组织features/、integrations/、regression/三类扩展测试MCP、auto-save 等较新特性。文件命名约定kebab-case.spec.ts后缀run-flow.spec.ts、playground.spec.ts、flow-lock.spec.ts模板测试允许带空格的文件名Document QA.spec.ts、Social Media Agent.spec.ts分片并行测试chatInputOutputUser-shard-0.spec.tsE2E 用.spec.tsPlaywright 约定单元测试用.test.tsxJest 约定两者不可混用。四、测试编写范式Test Anatomy以下四种范式直接继承自 SKILL.md并标注了当前源码状态。4.1 基础测试import { expect, test } from ../../fixtures; import { awaitBootstrapTest } from ../../utils/await-bootstrap-test; test( user should be able to run a flow successfully, { tag: [release, workspace] }, async ({ page }) { await awaitBootstrapTest(page); // Arrange: 创建 flow await page.getByTestId(blank-flow).click(); // Act: 添加组件并运行 await page.getByTestId(sidebar-search-input).fill(Chat Output); // ... setup ... // Assert: 验证构建成功 await expect(page.getByTestId(build-status-success)).toBeVisible({ timeout: 30000 }); }, );awaitBootstrapTest是当前每个测试的强制入口。从 await-bootstrap-test.ts 的源码看它做了三件事page.goto(/)打开应用等待[data-testidmainpage_title]出现30 秒超时seedFlowIfEmpty默认开启为空工作区播种 flow然后打开模板选择弹窗可用skipModal: true跳过。它存在的原因是没有这一步测试会与前端初始化竞争——组件可能未渲染、store 可能未水合、API 调用可能未完成。技能文档中几乎每条元素找不到的偶发失败都归因于缺少这一步。4.2 使用 test.describe 组织test.describe(Flow Lock Feature, () { test( should lock and unlock a flow, { tag: [release, api] }, async ({ page }) { /* ... */ }, ); test( should prevent editing when locked, { tag: [release] }, async ({ page }) { /* ... */ }, ); });4.3 串行模式依赖顺序的测试test.describe.configure({ mode: serial }); test(step 1: create flow, async ({ page }) { /* ... */ }); test(step 2: edit flow, async ({ page }) { /* ... */ }); test(step 3: delete flow, async ({ page }) { /* ... */ });4.4 事件投递模式包装器注意当前实现已简化技能文档描述withEventDeliveryModes会把测试在 streaming / polling / direct 三种事件投递模式下各跑一遍通过拦截/api/v1/config路由自动配置。但阅读当前源码 withEventDeliveryModes.ts 可以看到该包装器现在是一个兼容性 no-op shim其注释明确说明 v2 workflows endpoint replaced the three modes with a single AG-UI SSE path即 v2 workflows 端点已把三种投递模式统一为单一的 AG-UI SSE 通道包装器目前只注册一次测试保留签名以兼容所有既有调用点export function withEventDeliveryModes( title: string, config: TestConfig, testFn: TestFunction, ) { test(title, config, async ({ page }) { await testFn({ page }); }); }因此从源码结构看新测试继续按原有签名调用它不会出错但不要再依赖它产生 3 倍用例三种模式的差异覆盖逻辑已由后端统一的 SSE 通道取代。五、标签Tag体系tests/README.md 与技能文档一致地规定每个测试必须携带release标签——release 运行按该标签 grep 过滤未打标签或标签拼错的 spec 会静默地从发布覆盖中消失文档特别提醒是starter-projects不是starter-projectss。除此之外只允许以下六个标签不得自创标签用途适用场景release属于发布运行每个 spec 必需所有测试workspace工作区/flow 管理创建、编辑、删除 flowapi依赖 API 的功能调用后端端点的测试database数据库操作涉及持久化的测试components组件级测试单个组件的行为starter-projects模板/起步项目测试预置 flow 模板// 正确打标签 test(my feature test, { tag: [release, workspace] }, async ({ page }) { ... }); // 错误无标签无法被过滤 test(my feature test, async ({ page }) { ... });六、自定义 Fixture自动错误感知这是 Langflow E2E 体系最有价值的部分。所有 spec 必须从../../fixtures导入test与expect而不是从playwright/test导入——后者会绕过全部错误检测// 正确 import { expect, test } from ../../fixtures; // 错误——绕过错误检测可能产生静默通过 import { expect, test } from playwright/test;6.1 为什么需要它没有自定义 fixture 时测试可能在以下情况下依然通过后端返回 500但测试只检查了 UI 文案flow 构建因 Python 异常静默失败但测试只检查了按钮状态资源被删除后 API 返回 404测试根本没检查响应。6.2 检测行为对照 fixtures.ts 源码fixtures.ts 通过base.extend重写了pagefixtureL86-L525在每个测试的 page 生命周期内挂接request/response/requestfinished/requestfailed监听器核心逻辑inspectResponseL186-L335分两条线工作1HTTP 状态码监控凡是 URL 包含/api/且状态码 ≥ 400 的响应都会被记录。4xx 进入clientErrors列表附 method/path/status/脱敏后的响应体并在测试结束后作为api-4xx-responses附件写入报告5xx 则进入服务端错误契约server error contract实现见 server-error-contract.mjs状态码含义失败原因400Bad Request客户端发送了非法数据——通常是前端 bug404Not Found资源不存在——通常是过期 ID 或缺少前置步骤422Validation ErrorPydantic 校验失败——通常是 schema 不匹配500Internal Server Error后端崩溃——永远是 bug未声明的 5xx、以及已声明但未观察到的 5xx例如用page.expectServerError({ method, path, status, count })注册了预期却未发生都会让 fixture 在 teardown 阶段抛出Server-error contract failed错误并列出每一笔未匹配项。2流式/执行类响应的错误解析对状态为 200 且路径包含/events?event_delivery、/build/或/run/的响应fixture 先排除text/event-stream、application/grpc、application/octet-stream、application/x-ndjson等真流式内容这些由别的机制跟踪然后对有限响应体逐行尝试 JSON 解析命中以下任一情况即记为 flow 执行错误json.data.build_data.params以Error开头构建错误json.data.error true或json.error true记录error_message原始文本匹配 Python 异常模式NameError:、TypeError:、ValueError:、AttributeError:、ImportError:、KeyError:、An error occured ...。响应体读取有2 秒超时RESPONSE_BODY_READ_TIMEOUT_MS 2000见 L42-L44流式响应仍在写入时读取会超时此时跳过 body 解析并打警告避免 fixture 被长流卡死。teardown 阶段还有 2 秒的在途请求排空窗口API_REQUEST_DRAIN_TIMEOUT_MS确保跟随请求如 404 后的重试的响应仍可被观察到。6.3 允许预期错误测试 error handling 本身时需要显式放行。fixture 在 page 上注入allowFlowErrors方法L128-L130test(should show error message on invalid component config, { tag: [release] }, async ({ page }) { page.allowFlowErrors(); // 仅为本测试放行 flow 错误 await awaitBootstrapTest(page); // ... 触发错误的操作 ... await expect(page.getByText(/error/i)).toBeVisible(); });注意边界allowFlowErrors()只抑制 flow 执行错误HTTP 5xx 仍然会失败——服务端崩溃不属于预期行为。错误报告是聚合式的测试函数结束后fixture 把收集到的错误拼成描述性消息抛出形如Test failed due to 2 flow execution error(s): - /api/v1/build/abc123/flow Traceback (most recent call last)... If this error is expected, call page.allowFlowErrors() at the start of your test.这样开发者不必在每个测试里手写响应断言就能定位根因。6.4 附带能力a11y 扫描与 CPU 节流同一 fixture 还提供两个源码级能力可访问性扫描钩子page.runA11yScan(label, options?)由RUN_A11Ytrue开启使用accessibility-checker包RUN_A11Y_ASSERTtrue时进一步断言新增违规数为 0扫描摘要会作为附件写入报告L139-L183。配套聚合脚本见npm run a11y:report/a11y:html-report/a11y:job-summary。CPU 节流LF_CPU_THROTTLErate环境变量可让 Chromium 通过 CDPEmulation.setCPUThrottlingRate降速用于复现慢机器如 Windows CI上的竞态条件L76-L108。七、选择器策略与>await initialGPTsetup(page); // 执行全部步骤 await initialGPTsetup(page, { skipAdjustScreenView: true, skipUpdateOldComponents: true, skipSelectGptModel: true, });其六步顺序有讲究先更新过期组件再选模型可避免模型下拉框停留在旧组件定义的陈旧列表选gpt-4o-mini则是兼顾低成本与快速响应。8.2 检查面板模式关键约束// 必须先启用检查面板 await enableInspectPanel(page); // 点击节点选中 await page.getByTestId(title-OpenAI).click(); // 打开字段编辑器 await page.getByTestId(edit-fields-button).click(); // 切换字段可见性 await page.getByTestId(showmodel_name).click(); // 关闭字段编辑器 await page.getByTestId(edit-fields-button).click();若跳过enableInspectPanel(page)edit-fields-button根本不会出现在 DOM 中——检查面板未开启时该按钮不存在这是新写测试最常见的失败点之一。九、跳过测试与清理// 环境变量缺失时跳过 test.skip(!process?.env?.OPENAI_API_KEY, OPENAI_API_KEY required to run this test); // 无条件跳过必须给出原因 test.skip(true, Feature not yet implemented with new designs);收尾清理由 globalTeardown.ts 完成所有测试结束后删除src/frontend/temp临时数据库目录。源码显示它针对 Windows 做了专门处理——uvicorn 进程可能仍持有 SQLite 文件句柄POSIX 允许删除打开中的文件而 Win32 不允许表现为 EBUSY/EPERM因此 teardown 采用指数退避重试 5 次 → 逐文件兜底删除 → 永不抛错的策略最坏情况下留下目录交由运行器工作区清理。十、编写高质量 E2E 测试的规范应做Do每个测试都打release标签外加适用的领域标签从../../fixtures导入不从playwright/test导入以awaitBootstrapTest(page)开头——永远如此用getByTestId获取稳定选择器为异步操作设置显式超时waitForSelector与expect(...).toBeVisible()都要带timeout测试完整用户路径setup → action → verification涉及 flow 执行chat、build的测试沿用withEventDeliveryModes调用约定当前为单次执行见 4.4 节。不应做Dont不要用page.waitForTimeout()除非绝对必要——优先waitForSelector或expect().toBeVisible()不要硬编码 API key——从process.env.OPENAI_API_KEY读取webServer 配置已注入本地回环 key不要无理由跳过测试——test.skip()的第二个参数永远必填不要从playwright/test导入——使用自定义 fixtures不要忘enableInspectPanel(page)访问edit-fields-button前不要假设输入框存在——全局变量选中时渲染的是 badge。对抗性场景Challenge TestsE2E 测试同样应覆盖对抗性输入技能文档列出的五类非法输入粘贴 1 万字符、特殊字符scriptalert(1)/script、空提交网络中断构建中途断连时的表现权限边界用户能否通过直接 URL 访问他人 flow并发操作双击删除、快速连发消息错误恢复500 错误后 UI 是否能优雅恢复注意自定义 fixture 会自动把未声明的 500 判为失败这类测试需配合expectServerError声明预期。十一、延伸阅读仓库内参考文件文件内容SKILL.md本文的技能文档骨架适用场景、命令、标签、规范selectors.md完整 contenteditable="false">【免费下载链接】langflowLangflow is a powerful tool for building and deploying AI-powered agents and workflows.项目地址: https://gitcode.com/GitHub_Trending/la/langflow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门