import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:iop_client/main.dart'; import 'package:iop_client/client_config.dart'; import 'package:iop_client/iop_wire/client_wire_client.dart'; import 'package:iop_client/gen/proto/iop/control.pb.dart'; import 'package:protobuf/protobuf.dart'; import 'package:fixnum/fixnum.dart'; class FakeWebSocket implements WebSocket { final _controller = StreamController(); @override StreamSubscription listen( void Function(dynamic event)? onData, { Function? onError, void Function()? onDone, bool? cancelOnError, }) { return _controller.stream.listen( onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError, ); } @override dynamic noSuchMethod(Invocation invocation) { return null; } } class FakeClientWireClient extends ClientWireClient { final bool shouldSuccess; final String mockMessage; FakeClientWireClient({ this.shouldSuccess = true, this.mockMessage = 'Welcome to Toki CP!', }) : super(FakeWebSocket()); @override bool get isAlive => true; @override Future sendRequest< Req extends GeneratedMessage, Res extends GeneratedMessage >(Req data, {Duration timeout = const Duration(seconds: 30)}) async { if (data is ClientHelloRequest) { final response = ClientHelloResponse() ..ready = shouldSuccess ..protocol = 'iop-wire-v1' ..serverTimeUnixNano = Int64(1716584400) ..message = mockMessage; return response as Res; } throw UnimplementedError(); } } void main() { testWidgets('Client App basic rendering and success handshake test', ( WidgetTester tester, ) async { final fakeClient = FakeClientWireClient(shouldSuccess: true); await tester.pumpWidget(IopClientApp(testClient: fakeClient)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); expect(find.text('IOP CONTROL PLANE'), findsOneWidget); expect(find.text('Operations Overview'), findsOneWidget); expect( find.text(ClientConfig.controlPlaneHttpUrl, findRichText: true), findsOneWidget, ); expect( find.text(ClientConfig.controlPlaneWireUrl, findRichText: true), findsOneWidget, ); expect(find.text('CONNECTED'), findsOneWidget); }); testWidgets('Client App connection error state test', ( WidgetTester tester, ) async { final fakeClient = FakeClientWireClient( shouldSuccess: false, mockMessage: 'Invalid Version', ); await tester.pumpWidget(IopClientApp(testClient: fakeClient)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); expect(find.text('ERROR'), findsOneWidget); }); testWidgets('Client App opens IOP agent panel from the left rail', ( WidgetTester tester, ) async { final fakeClient = FakeClientWireClient(shouldSuccess: true); await tester.pumpWidget(IopClientApp(testClient: fakeClient)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.tap(find.byIcon(Icons.smart_toy_outlined)); await tester.pump(); expect(find.text('Ask about IOP operations'), findsOneWidget); expect(find.textContaining('IOP agent surface is ready'), findsOneWidget); expect(find.textContaining('Edge Control'), findsOneWidget); expect(find.textContaining('Node Management'), findsOneWidget); }); testWidgets('Client App opens Execution/Logs panel from the left rail', ( WidgetTester tester, ) async { final fakeClient = FakeClientWireClient(shouldSuccess: true); await tester.pumpWidget(IopClientApp(testClient: fakeClient)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.tap(find.byIcon(Icons.list_alt_outlined)); await tester.pump(); expect(find.text('Execution & Logs'), findsOneWidget); expect(find.textContaining('Live session logs'), findsOneWidget); }); }