1101fb0a97
Add AccomplishmentReportDialog with programmer/admin modes, date-range filter (default this month), and include-unapproved toggle. Wire into DaySheetsTab app-bar action, ApprovalsTab app-bar action, and ProgrammerDrillDownScreen app-bar button. Co-Authored-By: claude-flow <ruv@ruv.net>
171 lines
5.5 KiB
Dart
171 lines
5.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:tasq/models/profile.model.dart';
|
|
import 'package:tasq/providers/profile_provider.dart';
|
|
import 'package:tasq/screens/programmer_tasks/report/accomplishment_report_dialog.dart';
|
|
import 'package:tasq/theme/app_theme.dart';
|
|
import 'package:tasq/utils/app_time.dart';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Widget _buildApp(Widget child, {List<Override> overrides = const []}) {
|
|
return ProviderScope(
|
|
overrides: overrides,
|
|
child: MaterialApp(
|
|
theme: AppTheme.light(),
|
|
home: Scaffold(body: child),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Opener widget that shows the dialog on tap.
|
|
class _DialogOpener extends ConsumerWidget {
|
|
const _DialogOpener({this.programmerId});
|
|
|
|
final String? programmerId;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
return ElevatedButton(
|
|
onPressed: () => showAccomplishmentReportDialog(
|
|
context,
|
|
ref,
|
|
programmerId: programmerId,
|
|
),
|
|
child: const Text('Open'),
|
|
);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tests
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void main() {
|
|
setUpAll(AppTime.initialize);
|
|
|
|
// ── Programmer mode (not admin, no programmerId) ─────────────────────────
|
|
|
|
group('as programmer (not admin)', () {
|
|
late List<Override> overrides;
|
|
|
|
setUp(() {
|
|
overrides = [
|
|
isStrictAdminProvider.overrideWithValue(false),
|
|
profilesProvider.overrideWith(
|
|
(ref) => Stream.value([
|
|
Profile(id: 'prog-1', role: 'programmer', fullName: 'Alice'),
|
|
]),
|
|
),
|
|
currentUserIdProvider.overrideWithValue('prog-1'),
|
|
];
|
|
});
|
|
|
|
testWidgets('shows Accomplishment Report title', (tester) async {
|
|
await tester
|
|
.pumpWidget(_buildApp(const _DialogOpener(), overrides: overrides));
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Accomplishment Report'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('does not show programmer picker', (tester) async {
|
|
await tester
|
|
.pumpWidget(_buildApp(const _DialogOpener(), overrides: overrides));
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byType(DropdownButton<Profile>), findsNothing);
|
|
});
|
|
|
|
testWidgets('toggle Include unapproved days is present and off by default',
|
|
(tester) async {
|
|
await tester
|
|
.pumpWidget(_buildApp(const _DialogOpener(), overrides: overrides));
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Include unapproved days (marked)'), findsOneWidget);
|
|
final sw = tester.widget<Switch>(find.byType(Switch).first);
|
|
expect(sw.value, isFalse);
|
|
});
|
|
|
|
testWidgets('date filter defaults to This Month', (tester) async {
|
|
await tester
|
|
.pumpWidget(_buildApp(const _DialogOpener(), overrides: overrides));
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('This Month'), findsOneWidget);
|
|
});
|
|
});
|
|
|
|
// ── Admin picker mode (isStrictAdmin, no programmerId passed) ────────────
|
|
|
|
group('as admin (no programmerId, strict admin)', () {
|
|
final prog1 = Profile(id: 'prog-1', role: 'programmer', fullName: 'Alice');
|
|
final prog2 = Profile(id: 'prog-2', role: 'programmer', fullName: 'Bob');
|
|
final admin1 =
|
|
Profile(id: 'admin-1', role: 'admin', fullName: 'Admin User');
|
|
|
|
late List<Override> overrides;
|
|
|
|
setUp(() {
|
|
overrides = [
|
|
isStrictAdminProvider.overrideWithValue(true),
|
|
profilesProvider.overrideWith(
|
|
(ref) => Stream.value([prog1, prog2, admin1]),
|
|
),
|
|
currentUserIdProvider.overrideWithValue('admin-1'),
|
|
];
|
|
});
|
|
|
|
testWidgets('shows programmer picker', (tester) async {
|
|
await tester
|
|
.pumpWidget(_buildApp(const _DialogOpener(), overrides: overrides));
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.byType(DropdownButton<Profile>), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Generate is disabled until a programmer is chosen',
|
|
(tester) async {
|
|
await tester
|
|
.pumpWidget(_buildApp(const _DialogOpener(), overrides: overrides));
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
final button = tester.widget<FilledButton>(
|
|
find.ancestor(
|
|
of: find.text('Generate'),
|
|
matching: find.byType(FilledButton),
|
|
),
|
|
);
|
|
expect(button.onPressed, isNull);
|
|
});
|
|
|
|
testWidgets('picker shows only programmer-role profiles', (tester) async {
|
|
await tester
|
|
.pumpWidget(_buildApp(const _DialogOpener(), overrides: overrides));
|
|
await tester.tap(find.text('Open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Open the dropdown to expose its items.
|
|
await tester.tap(find.byType(DropdownButton<Profile>));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Programmer names should appear in the dropdown overlay.
|
|
expect(find.text('Alice'), findsWidgets);
|
|
expect(find.text('Bob'), findsWidgets);
|
|
// Admin-role profile must not appear.
|
|
expect(find.text('Admin User'), findsNothing);
|
|
});
|
|
});
|
|
}
|