Initial commit: Krow Worker App
This commit is contained in:
128
test/shift_logic_test.dart
Normal file
128
test/shift_logic_test.dart
Normal file
@@ -0,0 +1,128 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:krow_worker_app/core/formatters.dart';
|
||||
import 'package:krow_worker_app/models/shift.dart';
|
||||
import 'package:krow_worker_app/models/timecard.dart';
|
||||
|
||||
Shift buildShift({
|
||||
ShiftStatus status = ShiftStatus.booked,
|
||||
DateTime? clockIn,
|
||||
DateTime? clockOut,
|
||||
int breakMinutes = 30,
|
||||
}) {
|
||||
final start = DateTime(2026, 8, 10, 17, 50);
|
||||
return Shift(
|
||||
id: 's1',
|
||||
role: 'Barista',
|
||||
business: 'Zoox',
|
||||
venue: 'Zoox - San Jose Hub',
|
||||
address: '848 E Gish Rd',
|
||||
start: start,
|
||||
end: start.add(const Duration(hours: 6)),
|
||||
rate: 21.00,
|
||||
status: status,
|
||||
breakMinutes: breakMinutes,
|
||||
clockIn: clockIn,
|
||||
clockOut: clockOut,
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('Shift pay', () {
|
||||
test('scheduled pay deducts the unpaid break', () {
|
||||
final shift = buildShift();
|
||||
expect(shift.scheduledDuration, const Duration(hours: 5, minutes: 30));
|
||||
expect(shift.scheduledPay, closeTo(115.50, 0.001));
|
||||
});
|
||||
|
||||
test('worked hours replace the schedule once clocked out', () {
|
||||
final shift = buildShift(
|
||||
status: ShiftStatus.completed,
|
||||
clockIn: DateTime(2026, 8, 10, 18, 1),
|
||||
clockOut: DateTime(2026, 8, 10, 23, 50),
|
||||
);
|
||||
// 5h49m on the clock, less the 30 minute break.
|
||||
expect(shift.workedDuration, const Duration(hours: 5, minutes: 19));
|
||||
expect(shift.pay, closeTo(111.65, 0.01));
|
||||
});
|
||||
|
||||
test('a clocked window shorter than the break never goes negative', () {
|
||||
final shift = buildShift(
|
||||
status: ShiftStatus.completed,
|
||||
clockIn: DateTime(2026, 8, 10, 18, 0),
|
||||
clockOut: DateTime(2026, 8, 10, 18, 5),
|
||||
);
|
||||
expect(shift.workedDuration, Duration.zero);
|
||||
expect(shift.pay, 0);
|
||||
});
|
||||
|
||||
test('cancelled and no-show shifts generate no pay', () {
|
||||
expect(buildShift(status: ShiftStatus.cancelled).pay, 0);
|
||||
expect(buildShift(status: ShiftStatus.noShow).pay, 0);
|
||||
});
|
||||
});
|
||||
|
||||
group('Timecard', () {
|
||||
Timecard card({required DateTime clockIn}) {
|
||||
final start = DateTime(2026, 8, 10, 17, 50);
|
||||
return Timecard(
|
||||
id: 'tc1',
|
||||
shiftId: 's1',
|
||||
role: 'Barista',
|
||||
business: 'Zoox',
|
||||
scheduledStart: start,
|
||||
scheduledEnd: start.add(const Duration(hours: 6)),
|
||||
clockIn: clockIn,
|
||||
clockOut: DateTime(2026, 8, 10, 23, 50),
|
||||
breakMinutes: 30,
|
||||
rate: 21.00,
|
||||
status: TimecardStatus.needsReview,
|
||||
submittedAt: DateTime(2026, 8, 11, 0, 2),
|
||||
);
|
||||
}
|
||||
|
||||
test('variance is positive when you clock in late', () {
|
||||
expect(card(clockIn: DateTime(2026, 8, 10, 18, 1)).varianceMinutes, 11);
|
||||
});
|
||||
|
||||
test('variance is negative when you clock in early', () {
|
||||
expect(card(clockIn: DateTime(2026, 8, 10, 17, 45)).varianceMinutes, -5);
|
||||
});
|
||||
|
||||
test('amount follows the clocked hours', () {
|
||||
expect(
|
||||
card(clockIn: DateTime(2026, 8, 10, 18, 1)).amount,
|
||||
closeTo(111.65, 0.01),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('Formatters', () {
|
||||
test('duration reads as hours and minutes', () {
|
||||
expect(Fmt.duration(const Duration(hours: 5, minutes: 19)), '5h 19m');
|
||||
expect(Fmt.duration(const Duration(minutes: 45)), '45m');
|
||||
});
|
||||
|
||||
test('stopwatch pads every field', () {
|
||||
expect(
|
||||
Fmt.stopwatch(const Duration(hours: 1, minutes: 2, seconds: 3)),
|
||||
'01:02:03',
|
||||
);
|
||||
});
|
||||
|
||||
test('countdown switches unit as the shift approaches', () {
|
||||
final now = DateTime(2026, 8, 10, 12, 0);
|
||||
expect(
|
||||
Fmt.untilStart(now.add(const Duration(minutes: 41)), now: now),
|
||||
'In 41 min',
|
||||
);
|
||||
expect(
|
||||
Fmt.untilStart(now.add(const Duration(hours: 3)), now: now),
|
||||
'In 3 hr',
|
||||
);
|
||||
expect(
|
||||
Fmt.untilStart(now.subtract(const Duration(minutes: 5)), now: now),
|
||||
'Started',
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user