231 lines
7.4 KiB
Dart
231 lines
7.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:iop_console/iop_console.dart';
|
|
|
|
void main() {
|
|
Future<void> pumpConsole(
|
|
WidgetTester tester, {
|
|
required Size viewport,
|
|
Widget? executionLogs,
|
|
IopConsoleConfig? config,
|
|
IopConsoleThemeAdapter? themeAdapter,
|
|
IopConsoleNavigationCallback? onNavigate,
|
|
IopCapabilityPack? capabilities,
|
|
}) async {
|
|
tester.view.physicalSize = viewport;
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: IopConsoleShell(
|
|
overview: const Center(child: Text('Overview content')),
|
|
executionLogs: executionLogs,
|
|
config: config,
|
|
themeAdapter: themeAdapter,
|
|
onNavigate: onNavigate,
|
|
capabilities: capabilities,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
testWidgets('public shell renders without an app-owned console wrapper', (
|
|
tester,
|
|
) async {
|
|
await pumpConsole(tester, viewport: const Size(1024, 768));
|
|
|
|
expect(find.text('Overview content'), findsOneWidget);
|
|
expect(find.byIcon(Icons.dashboard_outlined), findsOneWidget);
|
|
|
|
await tester.tap(find.byIcon(Icons.smart_toy_outlined));
|
|
await tester.pump();
|
|
|
|
expect(find.byType(IopAgentPanel), findsOneWidget);
|
|
expect(find.text('Ask about IOP operations'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets('rail and content remain stable on narrow and wide viewports', (
|
|
tester,
|
|
) async {
|
|
for (final viewport in const [Size(320, 640), Size(1200, 800)]) {
|
|
await pumpConsole(tester, viewport: viewport);
|
|
|
|
expect(find.text('Overview content'), findsOneWidget);
|
|
expect(find.byIcon(Icons.tune), findsOneWidget);
|
|
expect(tester.getSize(find.byIcon(Icons.dashboard_outlined)).height, 24);
|
|
expect(tester.takeException(), isNull);
|
|
}
|
|
});
|
|
|
|
testWidgets(
|
|
'supports navigation to executionLogs and displays injected widget',
|
|
(tester) async {
|
|
var navigatedSection = IopConsoleSection.overview;
|
|
|
|
await pumpConsole(
|
|
tester,
|
|
viewport: const Size(1024, 768),
|
|
executionLogs: const Center(child: Text('Custom Logs Content')),
|
|
onNavigate: (section) => navigatedSection = section,
|
|
);
|
|
|
|
// Tap on Execution & Logs rail item
|
|
await tester.tap(find.byIcon(Icons.list_alt_outlined));
|
|
await tester.pump();
|
|
|
|
expect(navigatedSection, IopConsoleSection.executionLogs);
|
|
expect(find.text('Custom Logs Content'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
},
|
|
);
|
|
|
|
testWidgets('injects capabilities and displays them in IopAgentPanel', (
|
|
tester,
|
|
) async {
|
|
const pack = IopCapabilityPack(
|
|
capabilities: [
|
|
IopCapability(
|
|
name: 'Target Command Execution',
|
|
description: 'Run targeted terminal automation commands.',
|
|
),
|
|
IopCapability(
|
|
name: 'Session Maintenance',
|
|
description: 'Establish and clean up persistent CLI sessions.',
|
|
),
|
|
],
|
|
);
|
|
|
|
await pumpConsole(
|
|
tester,
|
|
viewport: const Size(1024, 768),
|
|
capabilities: pack,
|
|
);
|
|
|
|
// Go to Agent Tab
|
|
await tester.tap(find.byIcon(Icons.smart_toy_outlined));
|
|
await tester.pump();
|
|
|
|
// Verify capability details are visible in the introductory message text
|
|
expect(find.textContaining('Target Command Execution'), findsOneWidget);
|
|
expect(find.textContaining('Session Maintenance'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets(
|
|
'IopConsoleOverview renders endpoints, status badge, and triggers refresh',
|
|
(tester) async {
|
|
tester.view.physicalSize = const Size(1024, 768);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
const config = IopConsoleConfig(
|
|
controlPlaneHttpUrl: 'https://api.iop.test',
|
|
controlPlaneWireUrl: 'wss://wire.iop.test',
|
|
authTokenReference: 'cp-auth-ref-main',
|
|
);
|
|
var refreshCount = 0;
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: IopConsoleOverview(
|
|
config: config,
|
|
statusText: 'Connected to Control Plane',
|
|
onRefresh: () => refreshCount++,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Check header and status badge
|
|
expect(find.text('Operations Overview'), findsOneWidget);
|
|
expect(find.text('CONNECTED TO CONTROL PLANE'), findsOneWidget);
|
|
|
|
// Check config values
|
|
expect(find.text('https://api.iop.test'), findsOneWidget);
|
|
expect(find.text('wss://wire.iop.test'), findsOneWidget);
|
|
// Check auth token reference key value
|
|
expect(find.text('cp-auth-ref-main'), findsOneWidget);
|
|
|
|
// Check refresh button functionality
|
|
final refreshBtn = find.text('Refresh Connection');
|
|
expect(refreshBtn, findsOneWidget);
|
|
|
|
await tester.tap(refreshBtn);
|
|
await tester.pump();
|
|
|
|
expect(refreshCount, 1);
|
|
expect(tester.takeException(), isNull);
|
|
},
|
|
);
|
|
|
|
testWidgets('IopConsoleOverview handles disconnected status correctly', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(1024, 768);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
const config = IopConsoleConfig(
|
|
controlPlaneHttpUrl: 'https://api.iop.test',
|
|
controlPlaneWireUrl: 'wss://wire.iop.test',
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: IopConsoleOverview(config: config, statusText: 'Disconnected'),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Verify it displays OFFLINE status text and DISCONNECTED status badge
|
|
expect(find.text('DISCONNECTED'), findsOneWidget);
|
|
expect(find.text('OFFLINE'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
|
|
testWidgets(
|
|
'IopConsoleOverview preserves narrow and wide responsive sections',
|
|
(tester) async {
|
|
const config = IopConsoleConfig(
|
|
controlPlaneHttpUrl: 'https://api.iop.test',
|
|
controlPlaneWireUrl: 'wss://wire.iop.test',
|
|
authTokenReference: 'cp-auth-ref-main',
|
|
);
|
|
|
|
// 400px width drives the narrow (< 600) layout; 1024px drives the wide one.
|
|
for (final viewport in const [Size(400, 1200), Size(1024, 1200)]) {
|
|
tester.view.physicalSize = viewport;
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: IopConsoleOverview(
|
|
config: config,
|
|
statusText: 'Connected to Control Plane',
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
|
|
// Header, status badge, and endpoint sections render on both viewports.
|
|
expect(find.text('Operations Overview'), findsOneWidget);
|
|
expect(find.text('CONNECTED TO CONTROL PLANE'), findsOneWidget);
|
|
expect(find.text('SYSTEM ENDPOINTS'), findsOneWidget);
|
|
expect(find.text('https://api.iop.test'), findsOneWidget);
|
|
expect(find.text('wss://wire.iop.test'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
}
|
|
},
|
|
);
|
|
}
|