149 lines
4.4 KiB
Dart
149 lines
4.4 KiB
Dart
import 'package:cyberhybridhub/admin/models/backfill_sync_item.dart';
|
|
import 'package:cyberhybridhub/admin/models/sync_run_event.dart';
|
|
import 'package:cyberhybridhub/admin/repositories/sync_run_log_repository.dart';
|
|
import 'package:cyberhybridhub/admin/widgets/sync_run_expansion_tile.dart';
|
|
import 'package:cyberhybridhub/theme/app_theme.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
SyncRunEvent _event({
|
|
required int id,
|
|
required String kind,
|
|
required DateTime startedAt,
|
|
String? error,
|
|
SyncRunSeverity severity = SyncRunSeverity.ok,
|
|
SyncRunStatus status = SyncRunStatus.success,
|
|
}) {
|
|
return SyncRunEvent(
|
|
id: id,
|
|
kind: kind,
|
|
startedAt: startedAt,
|
|
finishedAt: startedAt.add(const Duration(minutes: 1)),
|
|
rowsWritten: kind == 'cleanup' ? 0 : 100,
|
|
rowsRemoved: kind == 'cleanup' ? 4200 : 0,
|
|
error: error,
|
|
severity: severity,
|
|
status: status,
|
|
durationMs: 60000,
|
|
summary: error ?? '100 bar rows written',
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('shows severity chip and full error text when expanded', (
|
|
WidgetTester tester,
|
|
) async {
|
|
const String errorText =
|
|
'AlpacaMarketDataException: getBarsRange rate limited: 429';
|
|
final SyncRunEvent event = _event(
|
|
id: 7,
|
|
kind: 'backfill',
|
|
startedAt: DateTime.utc(2026, 5, 27, 10),
|
|
error: errorText,
|
|
severity: SyncRunSeverity.rateLimit,
|
|
status: SyncRunStatus.failed,
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: buildAppTheme(),
|
|
home: Scaffold(
|
|
body: SyncRunExpansionTile(
|
|
event: event,
|
|
now: DateTime.utc(2026, 5, 27, 12),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(find.text('Partial success'), findsNothing);
|
|
expect(find.textContaining('Failed'), findsWidgets);
|
|
expect(find.textContaining('Rate limited'), findsNothing);
|
|
|
|
await tester.tap(find.byType(ExpansionTile));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byKey(const Key('sync-run-error-7')), findsOneWidget);
|
|
expect(find.text(errorText), findsWidgets);
|
|
expect(find.textContaining('raw'), findsNothing);
|
|
expect(find.text('HTTP status'), findsOneWidget);
|
|
expect(find.text('429'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('renders very long error text without raw field labels', (
|
|
WidgetTester tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(800, 1600);
|
|
tester.view.devicePixelRatio = 1.0;
|
|
addTearDown(tester.view.reset);
|
|
|
|
final String longError = 'E' * 500;
|
|
final SyncRunEvent event = _event(
|
|
id: 8,
|
|
kind: 'backfill',
|
|
startedAt: DateTime.utc(2026, 5, 27, 10),
|
|
error: longError,
|
|
severity: SyncRunSeverity.error,
|
|
status: SyncRunStatus.failed,
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: buildAppTheme(),
|
|
home: Scaffold(
|
|
body: SyncRunExpansionTile(event: event),
|
|
),
|
|
),
|
|
);
|
|
await tester.tap(find.byType(ExpansionTile));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text(longError), findsWidgets);
|
|
expect(find.textContaining('"raw"'), findsNothing);
|
|
});
|
|
|
|
testWidgets('backfill items show Alpaca start wire string for DB spot checks', (
|
|
WidgetTester tester,
|
|
) async {
|
|
const String slotWire = '2026-05-26T08:00:00Z';
|
|
final SyncRunEvent event = SyncRunEvent(
|
|
id: 9,
|
|
kind: 'backfill',
|
|
startedAt: DateTime.utc(2026, 5, 27, 10),
|
|
finishedAt: DateTime.utc(2026, 5, 27, 10, 1),
|
|
rowsWritten: 0,
|
|
rowsRemoved: 0,
|
|
severity: SyncRunSeverity.warning,
|
|
status: SyncRunStatus.partial,
|
|
durationMs: 60000,
|
|
summary: '0 bar rows written',
|
|
error: 'partial sync saved (0 rows)',
|
|
backfillItems: <BackfillSyncItem>[
|
|
BackfillSyncItem(
|
|
slotStart: DateTime.utc(2026, 5, 26, 8),
|
|
slotStartWire: slotWire,
|
|
symbols: <String>['A', 'AA'],
|
|
),
|
|
],
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: buildAppTheme(),
|
|
home: Scaffold(
|
|
body: SyncRunExpansionTile(event: event),
|
|
),
|
|
),
|
|
);
|
|
await tester.tap(find.byType(ExpansionTile));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text(slotWire), findsOneWidget);
|
|
expect(find.textContaining('2 assets: A, AA'), findsOneWidget);
|
|
expect(
|
|
find.textContaining('Backfill fetches (Alpaca start / raw.slot_start)'),
|
|
findsOneWidget,
|
|
);
|
|
});
|
|
}
|