flutter_wright 0.9.2
flutter_wright: ^0.9.2 copied to clipboard
Playwright-style control of a running Flutter app — snapshot, tap, type, assert — for AI-driven and automated end-to-end testing. Debug-only in-app HTTP server.
更新日志 #
0.9.2 #
- docs: 新增
example/(最小可运行 app:FlutterWright.start(enabled: kDebugMode)+ 计数器页),补齐 pub.dev「Package has an example」评分项。 - docs:
wait_for_handlerdartdoc 的ref=<sN>等查询参数加反引号 —— 消除 dartdoc「尖括号被当 HTML」告警,pub.dev 静态分析满分。 - fix: 对齐代码内
FlutterWright.version常量到包版本(此前滞留0.9.0,致/health在 0.9.1 包仍上报 0.9.0)。
0.9.1 #
- docs: README 重写为英文、精简为快速上手。修正
FlutterWrightRoot被误列入基本集成 —— 它仅为/screenshot的 Flutter 原生截图所需、属可选;最小集成只需FlutterWright.start()+runApp(MyApp())。Navigation 一节改用 GetX/GoRouter adapter 示例。
0.9.0 #
- feat(webview): 选填
FlutterWright.registerWebView(evalJs, {label, context})—— 一行闭包让内嵌 WebView 的 H5 透明进snapshot,并可被同一套tap/type/scroll/longPress/waitFor(wXeYref)驱动。核心零 webview 插件依赖;不调则行为与 0.8.0 完全一致。
0.8.0 - 2026-05-28 #
破坏性变更 #
- 启用改为宿主显式控制:
FlutterWright.start({bool enabled = false})。默认 false → 不绑定控制面(fail-safe,正式包零运行时攻击面)。移除FlutterWrightConfig.enableInDebugOnly。- 迁移:旧
enableInDebugOnly: true(仅 debug 启用)≈FlutterWright.start(enabled: kDebugMode);提测的 release 包按自有「测试包?」判断接线,如FlutterWright.start(enabled: AppEnv.isTestBuild)。
- 迁移:旧
新增 #
- 可选 token 鉴权:
start({String? token})。非空时除GET /health外所有请求须带匹配X-FW-Token,否则 401(常量时间比对)。为空 = 不鉴权(仅 loopback)。token 由集成方自定,只从 env/本地配置读,绝不进仓库。 /health应用身份:start({String? appName, String? package}),/health(免 token)回{ok, service, version, name, package},供发现/探活确认目标 app。name/package未设时为 JSONnull(键始终存在,便于强类型反序列化)。
0.7.0 - 2026-05-27 #
新增 #
- snapshot-first 交互层(对齐 Playwright MCP):
GET /snapshot(带[ref=sN]的 YAML 语义树,SemanticsSnapshot.serialize)。POST /tap/long_press/scroll/type(经SemanticsOwner.performAction/EditableTextState.userUpdateTextEditingValue,请求体element+ref, 成功响应自动回吐snapshot)。GET /wait_for?text=|ref=|gone= [&timeout=ms](轮询条件,408 超时)。start()持有SemanticsBinding.instance.ensureSemantics()句柄, 强制常开语义树(无障碍服务未开时也能读到节点);stop()释放。
- skill 侧脚本:
snapshot.sh/tap.sh/long_press.sh/type.sh(含submit=发 ENTER) /scroll.sh/wait_for.sh(SDK);press_key.sh/back.sh(adb keyevent,免 SDK);logs.sh(读 daemonapp.log,免 SDK)。
变更 #
- navigatorKey 降级为可选:
FlutterWright.start()仅当传了navigatorKey或navigationAdapter才注册/navigate/reset/routes;否则这三个端点回 501 「navigation not configured」。交互闭环只需start()即可。 /navigate/reset的成功响应也附snapshot字段(与 /tap 等动作一致)。- 示例
dev/main_dev.dart显式传navigatorKey: FlutterWright.navigatorKey。
测试 / 兼容 #
- 单元测试:
semantics_snapshot_test、semantics_action_test、start_navigation_test(SDK)。 - E2E:
e2e_interaction_test(snapshot/type→tap/wait_for/navigate 回吐)。既有e2e_control_plane_test与各 example 测试改造withApp在测试体内 stop() 以释放 SDK 持有的SemanticsHandle(flutter_test 的 invariant 检查早于 tearDown)。 - API 全部兼容 Flutter 3.24(已下限)~3.44。
0.6.0 - 2026-05-25 #
破坏性变更。
移除 #
FlutterWright.start(testRoutes:)参数;FlutterWright.routes(RouteRegistry) 静态字段;src/route_registry.dart整个文件及其 barrel export。路由发现改由NavigationAdapter.discoverableRoutes提供。POST /reload端点与ReloadHandler;vm_service依赖。热重载改由 flutter-wright skill 经run持有的flutter run --machinedaemon(app.restart)驱动,不再经 SDK。SDK 自此 只负责goto/reset(导航)与/screenshot(FlutterWrightRoot)、/health。
新增 #
NavigationAdapter.discoverableRoutes(可选,默认null):GET /routes的唯一来源。NavigatorKeyAdapter(.., {routes})与CallbackNavigationAdapter(.., {routesProvider})用于喂路由发现。FlutterWright.start({navigatorKey, routes}):可传宿主自有 navigatorKey;routes路由名列表喂GET /routes(取代testRoutes)。- (skill 侧)
run/stop方法:AI 持有一个后台flutter run --machinedaemon;reload重写为驱动该 daemon。env-check 从全局/health闸门拆为逐方法前提。
修复 #
- 统一版本号:
pubspec.yaml与代码version常量对齐为 0.6.0。
迁移 #
start(testRoutes: [...])→ Navigator 1.0(map)用start(routes: map.keys); Navigator 1.0(onGenerateRoute)暴露一次路由名常量start(routes: AppRouter.names); 其他栈把路由放进 adapter 的routesProvider。- 自定义
implements NavigationAdapter的 adapter 需补一行Iterable<String>? get discoverableRoutes => null;(不可枚举时)。 - 用过
POST /reload或 skillreload(走 SDK)的:改用 flutter-wright skill 的run起 app,reload即驱动该 daemon;或在自己的 flutter run 控制台按r。
0.4.0 - 2026-05-25 #
破坏性变更。 不保证低版本兼容。
移除 #
- 整个 mock 能力:
MockDataProvider、InMemoryMockDataProvider、POST /mock端点、FlutterWright.start(mockProvider:)参数、FlutterWright.mockProvidergetter 全部删除。理由:让/mock真正改 UI 需要宿主把 provider 接进 repository/数据层, 对大部分真实项目改动量太大、几乎没人会接入 —— 属伪需求。SDK 聚焦真正低成本、 架构无关的能力(navigate / screenshot / routes / reset / reload / health)。- 配套移除 skill 的
mock方法(scripts/mock.sh)与reset的clearMock参数;POST /reset现在只接受空 body、只把 navigator pop 回根。
- 配套移除 skill 的
变更 #
ResetHandler不再持有 mock,只驱动NavigationAdapter.reset()。- 示例 app 去掉 mock 桥接(
DataStore/DevDataStore),dev/main_dev.dart复用lib/app.dart的createApp()工厂,不再重复 app 启动逻辑(改善 dev 入口可维护性)。
0.3.0 - 2026-05-25 #
新增 #
- 可插拔导航(
NavigationAdapter):/navigate与/reset不再硬编码 Navigator 1.0 的pushNamed/popUntil,改为经NavigationAdapter适配, 从而路由架构无关(Navigator 1.0 / GoRouter / GetX / auto_route 等)。NavigatorKeyAdapter—— 默认实现(命名路由,行为同旧版)。CallbackNavigationAdapter—— 逃生舱:宿主提供onNavigate/onReset两个闭包,适配 GoRouterrouter.go、GetXGet.toNamed等任意栈。FlutterWright.start新增可选参数navigationAdapter;不传时默认NavigatorKeyAdapter(navigatorKey),完全向后兼容。
变更 #
- 推荐集成方式改为
dev_dependencies+ 独立 debug 入口(dev/main_dev.dart), 使生产lib/对 SDK 零引用、release 构建零残留。packages/example已按此范式重构 (mock 经 app 本地DataStore接口解耦,DevDataStore在dev/桥接 SDK 的MockDataProvider)。详见docs/integration-guide.md。
修复 #
GET /screenshot(flutter 渲染模式)恒返回 500 的真实 bug:captureFlutterScreen原先读取binding.rootElement.renderObject(恒为RenderView,永远不是RenderRepaintBoundary),导致FlutterWrightRoot包装器形同虚设。现改为给FlutterWrightRoot的RepaintBoundary挂GlobalKey(fwRepaintBoundaryKey)并经其定位 捕获,回退到旧的根检查。Android 模拟器实测返回 200 PNG。
0.2.0 - 2026-05-22 #
新增 #
POST /reload接口:通过vm_service.reloadSources触发 Flutter 热重载(VM service 进程内 RPC)。- 新增
vm_service: >=14.0.0 <16.0.0依赖。
变更 #
- SDK 环境约束收紧:
flutter: >=3.24.0,sdk: >=3.5.0(原3.10.0/3.0.0)。 - 文档标注"作为 flutter-wright monorepo 的一部分发布"。
0.1.0 (首次发布) #
- 仅 debug 启用的 HTTP server,默认绑
127.0.0.1:9123(可配置)。 - 接口:
/health、/routes、/navigate、/reset、/mock、/screenshot。 MockDataProvider接口 +InMemoryMockDataProvider默认实现。FlutterWrightRootWidget 包装,让 app 内截图更可靠。- Release 构建是 no-op(由
kDebugMode守门)。