mirror of
https://github.com/kuhyx/diet-guard.git
synced 2026-11-10 19:27:14 +01:00
Glyph and count for catering cues
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ff12f4e171
commit
c9c30b1ee5
@ -15,6 +15,20 @@ import 'package:diet_guard_app/services/kuchnia_spread.dart';
|
|||||||
import 'package:diet_guard_app/ui/cues.dart';
|
import 'package:diet_guard_app/ui/cues.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// One fill tap's status (see [CountCue]).
|
||||||
|
typedef FillCue = CountCue;
|
||||||
|
|
||||||
|
/// The cue for a tap's [outcome]: dishes logged (ok + N), a proposal of
|
||||||
|
/// [armed] dishes (info + N), or nothing done (warn + 0: no delivery, every
|
||||||
|
/// slot taken, or the fetch failed).
|
||||||
|
FillCue fillCue(FillOutcome outcome, {required int armed}) {
|
||||||
|
final written = outcome.written.length;
|
||||||
|
final label = outcome.message;
|
||||||
|
if (written > 0) return (label: label, kind: CueKind.ok, count: written);
|
||||||
|
if (armed > 0) return (label: label, kind: CueKind.info, count: armed);
|
||||||
|
return (label: label, kind: CueKind.warn, count: 0);
|
||||||
|
}
|
||||||
|
|
||||||
/// Drives the screen's [FillAllFlow] and tidies the screen after a fill.
|
/// Drives the screen's [FillAllFlow] and tidies the screen after a fill.
|
||||||
mixin LogMealFillMixin<T extends StatefulWidget>
|
mixin LogMealFillMixin<T extends StatefulWidget>
|
||||||
on LogMealSyncMixin<T>, LogMealKuchniaMixin<T>, LogMealFutureMixin<T> {
|
on LogMealSyncMixin<T>, LogMealKuchniaMixin<T>, LogMealFutureMixin<T> {
|
||||||
@ -22,9 +36,9 @@ mixin LogMealFillMixin<T extends StatefulWidget>
|
|||||||
/// armed proposal along with it.
|
/// armed proposal along with it.
|
||||||
FillAllFlow fillFlow = FillAllFlow();
|
FillAllFlow fillFlow = FillAllFlow();
|
||||||
|
|
||||||
/// Shows [message] as a status cue of [kind] (its words are only spoken).
|
/// Shows [cue] as a status cue (its label is only spoken). Supplied by the
|
||||||
/// Supplied by the screen.
|
/// screen.
|
||||||
void showFillStatus(String message, {CueKind kind = CueKind.info});
|
void showFillStatus(FillCue cue);
|
||||||
|
|
||||||
/// A proposal belongs to the date it was fetched for; picking another (or
|
/// A proposal belongs to the date it was fetched for; picking another (or
|
||||||
/// going back to today) must not leave "Confirm (N)" offering it.
|
/// going back to today) must not leave "Confirm (N)" offering it.
|
||||||
@ -52,7 +66,11 @@ mixin LogMealFillMixin<T extends StatefulWidget>
|
|||||||
await publishAfterLog();
|
await publishAfterLog();
|
||||||
await refreshSlots();
|
await refreshSlots();
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
showFillStatus('Fill all failed: $error', kind: CueKind.error);
|
showFillStatus((
|
||||||
|
label: 'Fill all failed: $error',
|
||||||
|
kind: CueKind.error,
|
||||||
|
count: null,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -63,16 +81,17 @@ mixin LogMealFillMixin<T extends StatefulWidget>
|
|||||||
await _afterFill(outcome.written, later: day != null);
|
await _afterFill(outcome.written, later: day != null);
|
||||||
}
|
}
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
showFillStatus(
|
showFillStatus(fillCue(outcome, armed: fillFlow.armedCount));
|
||||||
outcome.message,
|
|
||||||
kind: outcome.written.isNotEmpty ? CueKind.ok : CueKind.warn,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disarms a proposal without writing anything.
|
/// Disarms a proposal without writing anything.
|
||||||
void onFillCancel() {
|
void onFillCancel() {
|
||||||
fillFlow.cancel();
|
fillFlow.cancel();
|
||||||
showFillStatus('Fill all cancelled — nothing logged.');
|
showFillStatus((
|
||||||
|
label: 'Fill all cancelled — nothing logged.',
|
||||||
|
kind: CueKind.info,
|
||||||
|
count: null,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Publishes the batch once and drops the filled dishes from the delivery
|
/// Publishes the batch once and drops the filled dishes from the delivery
|
||||||
|
|||||||
@ -29,6 +29,8 @@ import 'package:diet_guard_app/ui/cues.dart';
|
|||||||
import 'package:diet_guard_app/widgets/macro_input_row.dart';
|
import 'package:diet_guard_app/widgets/macro_input_row.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
CountCue _cue(String l, CueKind k, [int? n]) => (label: l, kind: k, count: n);
|
||||||
|
|
||||||
/// Writes [dish]'s name and macros into the log form's controllers.
|
/// Writes [dish]'s name and macros into the log form's controllers.
|
||||||
///
|
///
|
||||||
/// Free function rather than a mixin method so the numeric formatting is
|
/// Free function rather than a mixin method so the numeric formatting is
|
||||||
@ -139,16 +141,20 @@ mixin LogMealKuchniaMixin<T extends StatefulWidget> on State<T> {
|
|||||||
/// not be re-offered) and still records the fetch, so a successful tap
|
/// not be re-offered) and still records the fetch, so a successful tap
|
||||||
/// also spares the automatic path a second walk.
|
/// also spares the automatic path a second walk.
|
||||||
///
|
///
|
||||||
/// Returns a line to show the user, or null when a dish was prefilled and
|
/// Returns the cue to show (a spoken line, a glyph kind and a dish count),
|
||||||
/// the form speaks for itself.
|
/// or null when a dish was prefilled and the form speaks for itself.
|
||||||
Future<String?> loadDeliveryOnTap() async {
|
Future<CountCue?> loadDeliveryOnTap() async {
|
||||||
if (!KuchniaQueueService.isInitialized) return 'Catering is not ready yet.';
|
if (!KuchniaQueueService.isInitialized) {
|
||||||
|
return _cue('Catering is not ready yet.', CueKind.warn);
|
||||||
|
}
|
||||||
final logged = await LogStorageService.instance.todayEntries();
|
final logged = await LogStorageService.instance.todayEntries();
|
||||||
if (!mounted) return null;
|
if (!mounted) return null;
|
||||||
final result = await refreshDelivery(DateTime.now());
|
final result = await refreshDelivery(DateTime.now());
|
||||||
if (!mounted) return null;
|
if (!mounted) return null;
|
||||||
if (!result.ok) return result.reason;
|
if (!result.ok) return _cue(result.reason!, CueKind.error);
|
||||||
if (result.dishes.isEmpty) return 'No delivery today.';
|
if (result.dishes.isEmpty) {
|
||||||
|
return _cue('No delivery today.', CueKind.warn, 0);
|
||||||
|
}
|
||||||
await KuchniaQueueService.instance.recordFetched(DateTime.now());
|
await KuchniaQueueService.instance.recordFetched(DateTime.now());
|
||||||
if (!mounted) return null;
|
if (!mounted) return null;
|
||||||
final ordered = dishesInSlotOrder(
|
final ordered = dishesInSlotOrder(
|
||||||
@ -162,7 +168,7 @@ mixin LogMealKuchniaMixin<T extends StatefulWidget> on State<T> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (KuchniaQueueService.next == null) {
|
if (KuchniaQueueService.next == null) {
|
||||||
return 'All delivered dishes are already logged.';
|
return _cue('All delivered dishes are already logged.', CueKind.ok, 0);
|
||||||
}
|
}
|
||||||
prefillNextDish();
|
prefillNextDish();
|
||||||
return null;
|
return null;
|
||||||
@ -180,20 +186,21 @@ mixin LogMealKuchniaMixin<T extends StatefulWidget> on State<T> {
|
|||||||
/// the 250-line cap, and this is the mixin's own behaviour anyway.
|
/// the 250-line cap, and this is the mixin's own behaviour anyway.
|
||||||
Future<void> loadDeliveryAndReport() async {
|
Future<void> loadDeliveryAndReport() async {
|
||||||
setState(() => deliveryBusy = true);
|
setState(() => deliveryBusy = true);
|
||||||
String? message;
|
CountCue? cue;
|
||||||
try {
|
try {
|
||||||
message = await loadDeliveryOnTap();
|
cue = await loadDeliveryOnTap();
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) setState(() => deliveryBusy = false);
|
if (mounted) setState(() => deliveryBusy = false);
|
||||||
}
|
}
|
||||||
if (!mounted || message == null) return;
|
if (!mounted || cue == null) return;
|
||||||
// The outcome sentence stays as the spoken label; the snackbar paints
|
// The outcome sentence stays as the spoken label; the snackbar paints
|
||||||
// only a warning glyph (no delivery / not ready / fetch failed).
|
// the dish glyph in the kind's tint plus the count (0 = none to log).
|
||||||
showCueSnack(
|
showCueSnack(
|
||||||
context,
|
context,
|
||||||
kind: CueKind.warn,
|
kind: cue.kind,
|
||||||
semanticLabel: message,
|
semanticLabel: cue.label,
|
||||||
icon: Icons.restaurant,
|
icon: Icons.restaurant,
|
||||||
|
count: cue.count,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -63,8 +63,8 @@ class _LogMealScreenState extends State<LogMealScreen>
|
|||||||
CueState? _cue; // painted as a tinted icon, never as text
|
CueState? _cue; // painted as a tinted icon, never as text
|
||||||
TodayProgress? _progress;
|
TodayProgress? _progress;
|
||||||
|
|
||||||
void _setCue(CueKind kind, String? label) {
|
void _setCue(CueKind kind, String? label, [int? count]) {
|
||||||
_cue = label == null ? null : CueState.next(_cue, kind, label);
|
_cue = label == null ? null : CueState.next(_cue, kind, label, count);
|
||||||
_progress = null;
|
_progress = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,8 +123,8 @@ class _LogMealScreenState extends State<LogMealScreen>
|
|||||||
@override
|
@override
|
||||||
void onDishPrefilled() => setState(() => _source = 'catering');
|
void onDishPrefilled() => setState(() => _source = 'catering');
|
||||||
@override
|
@override
|
||||||
void showFillStatus(String message, {CueKind kind = CueKind.info}) =>
|
void showFillStatus(FillCue cue) =>
|
||||||
setState(() => _setCue(kind, message));
|
setState(() => _setCue(cue.kind, cue.label, cue.count));
|
||||||
|
|
||||||
void _onSuggestionSelected(FoodSuggestion suggestion) {
|
void _onSuggestionSelected(FoodSuggestion suggestion) {
|
||||||
fillControllersFromSuggestion(suggestion, _descController, _macros);
|
fillControllersFromSuggestion(suggestion, _descController, _macros);
|
||||||
|
|||||||
@ -57,6 +57,7 @@ class StatusCue extends StatefulWidget {
|
|||||||
required this.kind,
|
required this.kind,
|
||||||
required this.semanticLabel,
|
required this.semanticLabel,
|
||||||
this.icon,
|
this.icon,
|
||||||
|
this.count,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -69,6 +70,9 @@ class StatusCue extends StatefulWidget {
|
|||||||
/// Optional glyph replacing [CueKind.icon].
|
/// Optional glyph replacing [CueKind.icon].
|
||||||
final IconData? icon;
|
final IconData? icon;
|
||||||
|
|
||||||
|
/// Optional numeral painted beside the glyph (e.g. dishes logged).
|
||||||
|
final int? count;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatusCue> createState() => _StatusCueState();
|
State<StatusCue> createState() => _StatusCueState();
|
||||||
}
|
}
|
||||||
@ -127,7 +131,11 @@ class _StatusCueState extends State<StatusCue>
|
|||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(AppSpacing.sm),
|
padding: const EdgeInsets.all(AppSpacing.sm),
|
||||||
child: Icon(widget.icon ?? widget.kind.icon, color: tint),
|
child: _GlyphCount(
|
||||||
|
widget.icon ?? widget.kind.icon,
|
||||||
|
tint,
|
||||||
|
widget.count,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -144,6 +152,7 @@ void showCueSnack(
|
|||||||
required CueKind kind,
|
required CueKind kind,
|
||||||
required String semanticLabel,
|
required String semanticLabel,
|
||||||
IconData? icon,
|
IconData? icon,
|
||||||
|
int? count,
|
||||||
VoidCallback? onUndo,
|
VoidCallback? onUndo,
|
||||||
}) {
|
}) {
|
||||||
final messenger = ScaffoldMessenger.of(context)..hideCurrentSnackBar();
|
final messenger = ScaffoldMessenger.of(context)..hideCurrentSnackBar();
|
||||||
@ -155,7 +164,9 @@ void showCueSnack(
|
|||||||
label: semanticLabel,
|
label: semanticLabel,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(icon ?? kind.icon, color: tint),
|
ExcludeSemantics(
|
||||||
|
child: _GlyphCount(icon ?? kind.icon, tint, count),
|
||||||
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (onUndo != null)
|
if (onUndo != null)
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -172,12 +183,16 @@ void showCueSnack(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A status to show: `label` is only spoken; the `kind` glyph and the
|
||||||
|
/// `count` numeral (null = glyph only) are what is painted.
|
||||||
|
typedef CountCue = ({String label, CueKind kind, int? count});
|
||||||
|
|
||||||
/// One screen's current status cue; [seq] re-keys the widget so an identical
|
/// One screen's current status cue; [seq] re-keys the widget so an identical
|
||||||
/// consecutive status still shakes/pulses again.
|
/// consecutive status still shakes/pulses again.
|
||||||
@immutable
|
@immutable
|
||||||
class CueState {
|
class CueState {
|
||||||
/// Creates the successor of [previous] carrying [kind] and [label].
|
/// Creates the successor of [previous] carrying [kind] and [label].
|
||||||
CueState.next(CueState? previous, this.kind, this.label)
|
CueState.next(CueState? previous, this.kind, this.label, [this.count])
|
||||||
: seq = (previous?.seq ?? 0) + 1;
|
: seq = (previous?.seq ?? 0) + 1;
|
||||||
|
|
||||||
/// Meaning.
|
/// Meaning.
|
||||||
@ -186,12 +201,46 @@ class CueState {
|
|||||||
/// Spoken description; never painted.
|
/// Spoken description; never painted.
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
|
/// Optional numeral painted beside the glyph.
|
||||||
|
final int? count;
|
||||||
|
|
||||||
/// Monotonic counter used as the widget key.
|
/// Monotonic counter used as the widget key.
|
||||||
final int seq;
|
final int seq;
|
||||||
|
|
||||||
/// The left-aligned cue widget for this state.
|
/// The left-aligned cue widget for this state.
|
||||||
Widget get widget => Align(
|
Widget get widget => Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: StatusCue(key: ValueKey(seq), kind: kind, semanticLabel: label),
|
child: StatusCue(
|
||||||
|
key: ValueKey(seq),
|
||||||
|
kind: kind,
|
||||||
|
semanticLabel: label,
|
||||||
|
count: count,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A tinted glyph, followed by [count] when there is one.
|
||||||
|
class _GlyphCount extends StatelessWidget {
|
||||||
|
const _GlyphCount(this.icon, this.tint, this.count);
|
||||||
|
|
||||||
|
final IconData icon;
|
||||||
|
final Color tint;
|
||||||
|
final int? count;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final n = count;
|
||||||
|
if (n == null) return Icon(icon, color: tint);
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(icon, color: tint),
|
||||||
|
const SizedBox(width: AppSpacing.xs),
|
||||||
|
Text(
|
||||||
|
'$n',
|
||||||
|
style: TextStyle(color: tint, fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
77
app/test/no_words_kuchnia_test.dart
Normal file
77
app/test/no_words_kuchnia_test.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Guard: a catering fetch / fill reports with a glyph and a dish count; its
|
||||||
|
// sentence is only the spoken label.
|
||||||
|
|
||||||
|
import 'package:diet_guard_app/screens/log_meal_fill_mixin.dart';
|
||||||
|
import 'package:diet_guard_app/services/kuchnia_spread.dart';
|
||||||
|
import 'package:diet_guard_app/ui/cues.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'label_finders.dart';
|
||||||
|
import 'no_words_support.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('fillCue', () {
|
||||||
|
test('nothing to fill paints a warning and 0', () {
|
||||||
|
final cue = fillCue((
|
||||||
|
message: 'No catering delivery today.',
|
||||||
|
written: const <SlottedDish>[],
|
||||||
|
), armed: 0);
|
||||||
|
expect(cue.kind, CueKind.warn);
|
||||||
|
expect(cue.count, 0);
|
||||||
|
expect(cue.label, 'No catering delivery today.');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a proposal paints its armed count', () {
|
||||||
|
final cue = fillCue((
|
||||||
|
message: 'Will log 3',
|
||||||
|
written: const <SlottedDish>[],
|
||||||
|
), armed: 3);
|
||||||
|
expect((cue.kind, cue.count), (CueKind.info, 3));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('a counted cue paints only the glyph and the number', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
final state = CueState.next(
|
||||||
|
null,
|
||||||
|
CueKind.ok,
|
||||||
|
'Logged 4 catering dishes.',
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
await tester.pumpWidget(MaterialApp(home: Scaffold(body: state.widget)));
|
||||||
|
expect(find.text('4'), findsOneWidget);
|
||||||
|
expect(cueLabelled('Logged 4 catering dishes.'), findsOneWidget);
|
||||||
|
expectNoWords(tester, minStrings: 2, where: 'fill cue');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('the delivery snackbar paints the dish glyph and 0', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Builder(
|
||||||
|
builder: (context) => TextButton(
|
||||||
|
onPressed: () => showCueSnack(
|
||||||
|
context,
|
||||||
|
kind: CueKind.warn,
|
||||||
|
semanticLabel: 'No delivery today.',
|
||||||
|
icon: Icons.restaurant,
|
||||||
|
count: 0,
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.local_shipping),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(find.byType(TextButton));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 500));
|
||||||
|
expect(find.byIcon(Icons.restaurant), findsOneWidget);
|
||||||
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
expectNoWords(tester, minStrings: 3, where: 'delivery snack');
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -75,12 +75,14 @@ class _HostState extends State<_Host>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int? statusCount;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void showFillStatus(String message, {CueKind kind = CueKind.info}) =>
|
void showFillStatus(FillCue cue) => setState(() {
|
||||||
setState(() {
|
status = cue.label;
|
||||||
status = message;
|
statusKind = cue.kind;
|
||||||
statusKind = kind;
|
statusCount = cue.count;
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Counted instead of run: the real one starts a network sync.
|
/// Counted instead of run: the real one starts a network sync.
|
||||||
@override
|
@override
|
||||||
@ -123,6 +125,8 @@ void main() {
|
|||||||
await t.runAsync(host.onFillAll);
|
await t.runAsync(host.onFillAll);
|
||||||
|
|
||||||
expect(host.status, startsWith('Will log 4'));
|
expect(host.status, startsWith('Will log 4'));
|
||||||
|
// Painted: a glyph + the number of dishes the confirm would log.
|
||||||
|
expect(host.statusCount, 4);
|
||||||
expect(await t.runAsync(storage.todayEntries), isEmpty);
|
expect(await t.runAsync(storage.todayEntries), isEmpty);
|
||||||
expect(host.publishes, 0);
|
expect(host.publishes, 0);
|
||||||
expect(KuchniaQueueService.remaining, 4);
|
expect(KuchniaQueueService.remaining, 4);
|
||||||
@ -141,6 +145,7 @@ void main() {
|
|||||||
|
|
||||||
expect(host.status, 'Logged 4 catering dishes.');
|
expect(host.status, 'Logged 4 catering dishes.');
|
||||||
expect(host.statusKind, CueKind.ok);
|
expect(host.statusKind, CueKind.ok);
|
||||||
|
expect(host.statusCount, 4);
|
||||||
expect(await t.runAsync(() => loggedToday(storage)), hasLength(4));
|
expect(await t.runAsync(() => loggedToday(storage)), hasLength(4));
|
||||||
expect(host.publishes, 1, reason: 'one publish per batch, not per dish');
|
expect(host.publishes, 1, reason: 'one publish per batch, not per dish');
|
||||||
expect(KuchniaQueueService.remaining, 0);
|
expect(KuchniaQueueService.remaining, 0);
|
||||||
@ -162,6 +167,7 @@ void main() {
|
|||||||
|
|
||||||
// D1's slot was taken, so only D2..D4 landed and D1 is still on offer.
|
// D1's slot was taken, so only D2..D4 landed and D1 is still on offer.
|
||||||
expect(host.status, 'Logged 3 catering dishes.');
|
expect(host.status, 'Logged 3 catering dishes.');
|
||||||
|
expect(host.statusCount, 3);
|
||||||
expect(KuchniaQueueService.remaining, 1);
|
expect(KuchniaQueueService.remaining, 1);
|
||||||
expect(host.desc.text, 'D1');
|
expect(host.desc.text, 'D1');
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user