feat(report): accomplishment report dialog + entry points
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>
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user