導航路徑 test 驗證的是使用者在畫面之間的移動是否符合設計 — 每個畫面的 back 按鈕是否導向正確的上層畫面、每個 router 定義的路由是否從 UI 可達、gopush 的語意是否產生正確的返回堆疊。

Back 按鈕 test

每個有 back 按鈕的畫面需要一個 test 驗證「按下 back 後導航到哪裡」。Back 按鈕的目標畫面依導航方式而定:

  • context.push('/terminal') 進入 → back 回到推入前的畫面(首頁)
  • context.go('/terminal') 進入 → back 行為依 router 設定,可能沒有上一頁
 1testWidgets('back from terminal returns to home (pushed)', (tester) async {
 2  await tester.pumpWidget(app());
 3  // 從首頁 push 到 terminal
 4  await tester.tap(find.text('Connect Terminal'));
 5  await tester.pumpAndSettle();
 6  expect(find.byType(TerminalScreen), findsOneWidget);
 7  // 按 back
 8  await tester.tap(find.byKey(Key('back_button')));
 9  await tester.pumpAndSettle();
10  expect(find.byType(HomeScreen), findsOneWidget);
11});

Route 可達性 test

Router 定義的每個路由都應該有從 UI 可達的路徑(ux-design 模組一 路由可達性)。Route 可達性 test 驗證「從首頁出發,透過 UI 操作能到達每個路由」。

 1testWidgets('enrollment route is reachable from home', (tester) async {
 2  await tester.pumpWidget(app());
 3  // 找到配對入口按鈕
 4  final enrollButton = find.text('Enroll Device');
 5  expect(enrollButton, findsOneWidget);
 6  // 點擊後到達 enrollment 畫面
 7  await tester.tap(enrollButton);
 8  await tester.pumpAndSettle();
 9  expect(find.byType(EnrollmentScreen), findsOneWidget);
10});

不可達的路由在 test 中表現為「找不到導航到該路由的 UI 元素」。如果 router 定義了 /enrollment 但首頁沒有對應按鈕,find.text('Enroll Device') 會找不到元素 — test 失敗暴露入口缺失。

go vs push 語意的 test

gopush 對返回堆疊的影響不同(ux-design 模組五 導航模式)。Test 需要驗證正確的導航方式被使用:

Push 語意:保留返回堆疊

Push 後按系統 back 鍵應該回到推入前的畫面。

 1testWidgets('push preserves back stack', (tester) async {
 2  await tester.pumpWidget(app());
 3  // push to enrollment
 4  await tester.tap(find.text('Enroll Device'));
 5  await tester.pumpAndSettle();
 6  // 系統 back 鍵
 7  final backButton = find.byTooltip('Back');
 8  await tester.tap(backButton);
 9  await tester.pumpAndSettle();
10  // 應該回到首頁
11  expect(find.byType(HomeScreen), findsOneWidget);
12});

Go 語意:替換路由堆疊

Go 後按系統 back 鍵的行為依 router 設定。如果 go 到的路由是根層級,系統 back 鍵可能退出 app 而非回到前一個畫面。

Test 策略:驗證 go 後的路由堆疊狀態。如果設計意圖是「切換工作區,不保留前一個畫面」,斷言系統 back 鍵不回到前一個畫面。

深層連結 test

深層連結(deep link)讓使用者從 app 外部直接進入特定畫面。Deep link test 驗證「直接導航到內部路由時,畫面和導航堆疊是否正確」。

1testWidgets('deep link to /terminal shows terminal', (tester) async {
2  await tester.pumpWidget(app(initialRoute: '/terminal'));
3  expect(find.byType(TerminalScreen), findsOneWidget);
4});

深層連結的特殊性在於使用者跳過了正常的導航流程。從首頁到 terminal 的正常流程可能經過認證 gate,但深層連結直接到 terminal — 認證 gate 是否仍然生效需要額外的 test。

下一步路由