// The shell's sustained-failure banner must name the actual // problem: a hub that rejects the token (UNAUTHENTICATED / // PERMISSION_DENIED) is UP — telling the operator "can't reach // the hub" sends them to fix the endpoint when the token is what // needs attention. The probe result is faked through // StudioShellState.debugProbeOverride; the banner appears after // three consecutive failed polls (5 s apart), so each test pumps // the poll timer forward instead of waiting. import 'package:chain_client_sdk/chain_client_sdk.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:chain_studio/data/hub.dart'; import 'package:chain_studio/main.dart'; Future _pumpShell(WidgetTester tester) async { await tester.pumpWidget( const StudioApp( initialThemeMode: ThemeModeValue.system, initialLocale: Locale('en'), ), ); // pump (not pumpAndSettle): the app has long-lived timers that // never settle. One frame lays the shell out, then three poll // ticks cross the banner threshold. await tester.pump(const Duration(milliseconds: 100)); for (var i = 0; i < 3; i++) { await tester.pump(const Duration(seconds: 5)); await tester.pump(); } } void main() { tearDown(() { StudioShellState.debugProbeOverride = null; }); testWidgets('sustained auth rejection points at the token, not the wire', (tester) async { StudioShellState.debugProbeOverride = () async => HubProbeResult.authRejected; await _pumpShell(tester); expect(find.textContaining('rejected the sign-in'), findsOneWidget); expect(find.textContaining("Can't reach"), findsNothing); // Token fixed (probe turns serving): the banner must clear. StudioShellState.debugProbeOverride = () async => HubProbeResult.serving; await tester.pump(const Duration(seconds: 5)); await tester.pump(); expect(find.textContaining('rejected the sign-in'), findsNothing); }); testWidgets('sustained connection failure keeps the unreachable wording', (tester) async { StudioShellState.debugProbeOverride = () async => HubProbeResult.unreachable; await _pumpShell(tester); expect(find.textContaining("Can't reach"), findsOneWidget); expect(find.textContaining('rejected the sign-in'), findsNothing); }); }