1fe9653bdf
Co-Authored-By: claude-flow <ruv@ruv.net>
208 lines
6.2 KiB
Dart
208 lines
6.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:tasq/models/programmer_day_sheet.model.dart';
|
|
import 'package:tasq/screens/programmer_tasks/day_sheets/day_sheet_dialogs.dart';
|
|
import 'package:tasq/utils/programmer_day_rows.dart';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Widget _wrap(Widget child) {
|
|
return MaterialApp(home: Scaffold(body: child));
|
|
}
|
|
|
|
// Minimal tappable button that opens the dialog under test.
|
|
class _DisapproveOpener extends StatelessWidget {
|
|
const _DisapproveOpener({required this.rows, this.result});
|
|
|
|
final List<DaySheetRow> rows;
|
|
final ValueNotifier<String?>? result;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ElevatedButton(
|
|
onPressed: () async {
|
|
final r = await showDisapproveDialog(context, flaggedRows: rows);
|
|
result?.value = r;
|
|
},
|
|
child: const Text('Open'),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _JustifyOpener extends StatelessWidget {
|
|
const _JustifyOpener({this.result});
|
|
|
|
final ValueNotifier<String?>? result;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ElevatedButton(
|
|
onPressed: () async {
|
|
final r = await showJustifyDialog(context);
|
|
result?.value = r;
|
|
},
|
|
child: const Text('Open'),
|
|
);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// DaySheetRow fixture
|
|
// ---------------------------------------------------------------------------
|
|
|
|
DaySheetRow _row(String taskId) => DaySheetRow(
|
|
taskId: taskId,
|
|
title: 'Task $taskId',
|
|
category: 'Software Development',
|
|
kind: 'assignee',
|
|
seconds: 3600,
|
|
notes: const [],
|
|
);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tests
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void main() {
|
|
group('showDisapproveDialog', () {
|
|
testWidgets('stays open and shows error when remarks are empty',
|
|
(tester) async {
|
|
final result = ValueNotifier<String?>(null);
|
|
await tester.pumpWidget(_wrap(_DisapproveOpener(
|
|
rows: [_row('t1')],
|
|
result: result,
|
|
)));
|
|
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Dialog should be visible.
|
|
expect(find.text('Disapprove'), findsWidgets);
|
|
|
|
// Tap the Disapprove action button with empty remarks.
|
|
final disapproveButtons = find.text('Disapprove');
|
|
await tester.tap(disapproveButtons.last);
|
|
await tester.pumpAndSettle();
|
|
|
|
// Error message should appear and dialog should still be open.
|
|
expect(find.text('Remarks are required'), findsOneWidget);
|
|
expect(find.text('Disapprove'), findsWidgets);
|
|
expect(result.value, isNull);
|
|
});
|
|
|
|
testWidgets('returns the entered remarks when non-empty', (tester) async {
|
|
final result = ValueNotifier<String?>(null);
|
|
await tester.pumpWidget(_wrap(_DisapproveOpener(
|
|
rows: [_row('t1')],
|
|
result: result,
|
|
)));
|
|
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.enterText(
|
|
find.byType(TextField).first, 'Missing notes');
|
|
await tester.pumpAndSettle();
|
|
|
|
final disapproveButtons = find.text('Disapprove');
|
|
await tester.tap(disapproveButtons.last);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(result.value, 'Missing notes');
|
|
});
|
|
});
|
|
|
|
group('showJustifyDialog', () {
|
|
testWidgets('stays open and shows error when justification is empty',
|
|
(tester) async {
|
|
final result = ValueNotifier<String?>(null);
|
|
await tester.pumpWidget(_wrap(_JustifyOpener(result: result)));
|
|
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Tap submit with no text.
|
|
await tester.tap(find.text('Submit'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Please write a justification'), findsOneWidget);
|
|
expect(result.value, isNull);
|
|
});
|
|
|
|
testWidgets('returns body when non-empty', (tester) async {
|
|
final result = ValueNotifier<String?>(null);
|
|
await tester.pumpWidget(_wrap(_JustifyOpener(result: result)));
|
|
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.enterText(find.byType(TextField).first, 'My justification');
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.text('Submit'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(result.value, 'My justification');
|
|
});
|
|
});
|
|
|
|
group('rowsForSheet', () {
|
|
test('returns snapshot rows when approved and snapshot exists', () {
|
|
final snapshotRow = _row('snap-1');
|
|
final snapshot = DaySheetSnapshot(
|
|
totalSeconds: 3600,
|
|
rows: [snapshotRow],
|
|
);
|
|
final sheet = ProgrammerDaySheet(
|
|
id: 'sheet-1',
|
|
programmerId: 'user-1',
|
|
status: DaySheetStatus.approved,
|
|
workDate: DateTime.utc(2026, 9, 27),
|
|
approvedSnapshot: snapshot,
|
|
createdAt: DateTime.utc(2026, 9, 27),
|
|
updatedAt: DateTime.utc(2026, 9, 27),
|
|
);
|
|
final liveRow = _row('live-1');
|
|
|
|
final result = rowsForSheet(sheet, [liveRow]);
|
|
|
|
expect(result, [snapshotRow]);
|
|
});
|
|
|
|
test('returns live rows when not approved', () {
|
|
final sheet = ProgrammerDaySheet(
|
|
id: 'sheet-2',
|
|
programmerId: 'user-1',
|
|
status: DaySheetStatus.pending,
|
|
workDate: DateTime.utc(2026, 9, 27),
|
|
createdAt: DateTime.utc(2026, 9, 27),
|
|
updatedAt: DateTime.utc(2026, 9, 27),
|
|
);
|
|
final liveRow = _row('live-1');
|
|
|
|
final result = rowsForSheet(sheet, [liveRow]);
|
|
|
|
expect(result, [liveRow]);
|
|
});
|
|
|
|
test('returns live rows when approved but snapshot is null', () {
|
|
final sheet = ProgrammerDaySheet(
|
|
id: 'sheet-3',
|
|
programmerId: 'user-1',
|
|
status: DaySheetStatus.approved,
|
|
workDate: DateTime.utc(2026, 9, 27),
|
|
approvedSnapshot: null,
|
|
createdAt: DateTime.utc(2026, 9, 27),
|
|
updatedAt: DateTime.utc(2026, 9, 27),
|
|
);
|
|
final liveRow = _row('live-1');
|
|
|
|
final result = rowsForSheet(sheet, [liveRow]);
|
|
|
|
expect(result, [liveRow]);
|
|
});
|
|
});
|
|
}
|