tane/apps/app_seeds/test/ui/quantity_picker_test.dart
vjrj 5b487ba1ec feat(ux): usable amounts, colour-coded category/form chips, currency quick-picks
Four usability passes across the everyday flows:

- Quantity picker: a countable unit (cob/pod/ear…) now defaults to 1 and
  the stepper clamps at a minimum of 1 — you can never store 'a cob' with
  a blank/zero figure. Vibe units (a few) still carry no number.
- Category & form chips are colour-coded (new category_palette.dart): a
  small muted earthy palette maps each botanical family to a STABLE
  tonality (fill + readable ink), and each lot form gets its own tone.
  Applied to the inventory filter bar (now grouped attributes | forms |
  families, separated by a hairline), the list's category headers (a
  matching colour dot), and the lot-form selector.
- Sale currency: quick-pick chips (€ · Ğ1 · hours) fill the field in one
  tap — Ğ1 offered quietly among familiar options, never imposed — while
  free text still takes anything else. New i18n key sale.hours (en/es/pt/ast).

Tests: quantity_picker_test (default-1, clamp, vibe, clear-still-1),
category_palette_test (stable/distinct swatches); overflow guard + the
inventory widget tests stay green.
2026-07-11 06:06:04 +02:00

83 lines
2.5 KiB
Dart

import 'package:commons_core/commons_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tane/db/enums.dart';
import 'package:tane/ui/quantity_picker.dart';
import '../support/test_support.dart';
/// A countable amount must never be blank: picking cob/pod/… defaults to 1 and
/// the stepper can't drop below 1 — you can't save "a cob" with no figure.
void main() {
Quantity? emitted;
Future<void> pumpPicker(WidgetTester tester,
{LotType type = LotType.seed}) async {
emitted = null;
final db = newTestDatabase();
addTearDown(db.close);
await tester.pumpWidget(wrapScreen(
repository: newTestRepository(db),
child: Scaffold(
body: QuantityPicker(
type: type,
onChanged: (q) => emitted = q,
),
),
));
await tester.pump();
}
testWidgets('selecting a countable unit defaults the count to 1',
(tester) async {
await pumpPicker(tester);
await tester.tap(find.byKey(const Key('quantity.kind.cob')));
await tester.pump();
expect(emitted, isNotNull);
expect(emitted!.kind, QuantityKind.cob);
expect(emitted!.count, 1);
expect(
find.widgetWithText(TextField, '1'),
findsOneWidget,
reason: 'the count field shows 1, not an empty box',
);
});
testWidgets('the minus button never takes a countable amount below 1',
(tester) async {
await pumpPicker(tester);
await tester.tap(find.byKey(const Key('quantity.kind.cob')));
await tester.pump();
// Two decrements from 1 must clamp at 1, never 0 or blank.
await tester.tap(find.byIcon(Icons.remove));
await tester.pump();
await tester.tap(find.byIcon(Icons.remove));
await tester.pump();
expect(emitted!.count, 1);
});
testWidgets('a vibe unit (a few) carries no number and shows no stepper',
(tester) async {
await pumpPicker(tester);
await tester.tap(find.byKey(const Key('quantity.kind.aFew')));
await tester.pump();
expect(emitted!.kind, QuantityKind.aFew);
expect(emitted!.count, isNull);
expect(find.byKey(const Key('quantity.count')), findsNothing);
});
testWidgets('typing then clearing the box still stores 1, never empty',
(tester) async {
await pumpPicker(tester);
await tester.tap(find.byKey(const Key('quantity.kind.pod')));
await tester.pump();
await tester.enterText(find.byKey(const Key('quantity.count')), '');
await tester.pump();
expect(emitted!.kind, QuantityKind.pod);
expect(emitted!.count, 1);
});
}