// Doctor deep links — findings with a dedicated page must be one // tap away from it (usertest follow-up: "approvals waiting for // review" was a dead-end statement). The tiles and panel rows are // public callback-driven widgets so these tests pump each variant // without a live hub. import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:chain_studio/data/hub.dart'; import 'package:chain_studio/l10n/app_localizations.dart'; import 'package:chain_studio/pages/doctor.dart'; const _snapshot = DoctorSnapshot( moduleCount: 2, capabilityCount: 3, pendingApprovals: 1, eventChainTotal: 5, eventChainVerified: 5, eventChainTamperedAt: null, services: [], update: UpdateStatus( channel: 'stable', localVersion: '0.22.0', latestVersion: '0.22.0', updateAvailable: false, manifestReachable: true, ), paths: DaemonPathsSnapshot( logPath: '', dbPath: '', modulesDir: '', flowsDir: '', configPath: '', pidPath: '', ), ); Widget _host(Widget child) => MaterialApp( localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, locale: const Locale('de'), home: Scaffold(body: child), ); void main() { testWidgets('a linked stat tile is a labelled button that fires its target', ( tester, ) async { var opened = false; await tester.pumpWidget( _host( Row( children: [ DoctorStatTile( label: 'Freigaben', value: '1', subtitle: 'warten auf Prüfung', icon: Icons.inbox_outlined, onTap: () => opened = true, linkLabel: 'Freigaben öffnen', ), ], ), ), ); await tester.pumpAndSettle(); // Affordance: chevron + semantics button with the link label. expect(find.byIcon(Icons.chevron_right), findsOneWidget); expect( find.bySemanticsLabel(RegExp('Freigaben öffnen')), findsOneWidget, ); await tester.tap(find.text('1')); expect(opened, isTrue); }); testWidgets('an unlinked stat tile stays a plain card', (tester) async { await tester.pumpWidget( _host( const Row( children: [ DoctorStatTile( label: 'Dienste', value: '0', subtitle: 'deklariert', icon: Icons.dns_outlined, ), ], ), ), ); await tester.pumpAndSettle(); expect(find.byIcon(Icons.chevron_right), findsNothing); expect(find.byType(InkWell), findsNothing); }); testWidgets( 'the approvals row links to approvals, the modules row to the store', (tester) async { var storeOpened = false; var approvalsOpened = false; await tester.pumpWidget( _host( DoctorModulesPanel( snapshot: _snapshot, onOpenStore: () => storeOpened = true, onOpenApprovals: () => approvalsOpened = true, ), ), ); await tester.pumpAndSettle(); // The pending-approvals finding must be tappable ("1 Freigabe // wartet auf Prüfung" -> approvals inbox). await tester.tap(find.textContaining('wartet auf Prüfung')); expect(approvalsOpened, isTrue); expect(storeOpened, isFalse); await tester.tap(find.textContaining('2 Module')); expect(storeOpened, isTrue); }, ); }