Files
eatvio_app/test/features/consultations/utils/consultation_progress_mapper_test.dart
alex-chevski 16084ee94c fix(chat): guard diet duration and keep progress plank
- show diet duration hint and plan duration in suggestion flow
- disable diet CTA on duration mismatch with grey visual state
- keep progress plank visible for personal_diet_setted
- center step labels under their circles
2026-11-03 17:40:54 +03:00

280 lines
8.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:eatvio_app/features/consultations/models/consultation_progress.dart';
import 'package:eatvio_app/features/consultations/utils/consultation_progress_mapper.dart';
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
import 'package:flutter_test/flutter_test.dart';
typedef _Expected = ({
Set<ConsultationStep> steps,
bool plank,
PersonalDietStatus diet,
ConsultationPhase phase,
});
const _startDate = ConsultationStep.startDate;
const _paid = ConsultationStep.paid;
const _inProgress = ConsultationStep.inProgress;
const _finished = ConsultationStep.finished;
final Map<ChosenPlanStateEnum, _Expected> _expectations = {
ChosenPlanStateEnum.stateInited: (
steps: {},
plank: false,
diet: PersonalDietStatus.notProposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateStartDateHasBeenSet: (
steps: {_startDate},
plank: true,
diet: PersonalDietStatus.notProposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateInCoordination: (
steps: {},
plank: true,
diet: PersonalDietStatus.notProposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateStarted: (
steps: {_startDate, _paid, _inProgress},
plank: true,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateInProgress: (
steps: {_startDate, _paid, _inProgress},
plank: true,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.statePendingPayment: (
steps: {_startDate},
plank: true,
diet: PersonalDietStatus.notProposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateConfirmedByConsultant: (
steps: {},
plank: false,
diet: PersonalDietStatus.notProposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.statePaid: (
steps: {_startDate, _paid},
plank: true,
diet: PersonalDietStatus.notProposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateCanceledByTheInitiator: (
steps: {},
plank: false,
diet: PersonalDietStatus.notRequired,
phase: ConsultationPhase.canceled,
),
ChosenPlanStateEnum.stateLastDayStarted: (
steps: {_startDate, _paid, _inProgress},
plank: true,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateLastDayFinished: (
steps: {_startDate, _paid, _inProgress},
plank: true,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateComplained: (
steps: {_startDate, _paid, _inProgress},
plank: true,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateDone: (
steps: {_startDate, _paid, _inProgress, _finished},
plank: true,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.personalDietSet: (
steps: {_startDate, _paid},
plank: true,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.stateChargeWasCollected: (
steps: {_startDate, _paid, _inProgress, _finished},
plank: false,
diet: PersonalDietStatus.proposed,
phase: ConsultationPhase.active,
),
ChosenPlanStateEnum.statePaymentFailed: (
steps: {_startDate},
plank: false,
diet: PersonalDietStatus.notRequired,
phase: ConsultationPhase.paymentFailed,
),
};
void main() {
group('mapConsultationProgress — все состояния', () {
test('таблица покрывает ровно все 16 состояний', () {
expect(_expectations.length, 16);
expect(_expectations.keys.toSet(), ChosenPlanStateEnum.values.toSet());
});
for (final entry in _expectations.entries) {
test('${entry.key.name} маппится во все поля ConsultationProgress', () {
final progress = mapConsultationProgress(
state: entry.key,
hasPersonalDiet: true,
);
expect(progress.completedSteps, unorderedEquals(entry.value.steps));
expect(progress.showProgressPlank, entry.value.plank);
expect(progress.dietStatus, entry.value.diet);
expect(progress.phase, entry.value.phase);
});
}
});
group('mapConsultationProgress — ключевые сценарии', () {
test('in_coordination показывает плашку без завершённых шагов', () {
final progress = mapConsultationProgress(
state: ChosenPlanStateEnum.stateInCoordination,
hasPersonalDiet: true,
);
expect(progress.showProgressPlank, isTrue);
expect(progress.completedSteps, isEmpty);
});
test(
'personal_diet_setted показывает плашку и завершает startDate+paid',
() {
final progress = mapConsultationProgress(
state: ChosenPlanStateEnum.personalDietSet,
hasPersonalDiet: true,
);
expect(progress.showProgressPlank, isTrue);
expect(progress.completedSteps, unorderedEquals([_startDate, _paid]));
},
);
test(
'started/in_progress/last_day_started/last_day_finished/complained — 3 шага',
() {
const states = [
ChosenPlanStateEnum.stateStarted,
ChosenPlanStateEnum.stateInProgress,
ChosenPlanStateEnum.stateLastDayStarted,
ChosenPlanStateEnum.stateLastDayFinished,
ChosenPlanStateEnum.stateComplained,
];
for (final state in states) {
final progress = mapConsultationProgress(
state: state,
hasPersonalDiet: true,
);
expect(
progress.completedSteps,
unorderedEquals([_startDate, _paid, _inProgress]),
reason: 'state=${state.name}',
);
}
},
);
test('done/charge_was_collected — 4 шага', () {
const states = [
ChosenPlanStateEnum.stateDone,
ChosenPlanStateEnum.stateChargeWasCollected,
];
for (final state in states) {
final progress = mapConsultationProgress(
state: state,
hasPersonalDiet: true,
);
expect(
progress.completedSteps,
unorderedEquals([_startDate, _paid, _inProgress, _finished]),
reason: 'state=${state.name}',
);
}
});
test(
'canceled — фаза canceled и dietStatus notRequired даже при диете',
() {
final progress = mapConsultationProgress(
state: ChosenPlanStateEnum.stateCanceledByTheInitiator,
hasPersonalDiet: true,
);
expect(progress.phase, ConsultationPhase.canceled);
expect(progress.isCanceled, isTrue);
expect(progress.dietStatus, PersonalDietStatus.notRequired);
},
);
test('payment_failed — фаза paymentFailed и только startDate', () {
final progress = mapConsultationProgress(
state: ChosenPlanStateEnum.statePaymentFailed,
hasPersonalDiet: true,
);
expect(progress.phase, ConsultationPhase.paymentFailed);
expect(progress.isPaymentFailed, isTrue);
expect(progress.completedSteps, unorderedEquals([_startDate]));
});
test('hasPersonalDiet=false даёт notRequired для любого состояния', () {
for (final state in ChosenPlanStateEnum.values) {
final progress = mapConsultationProgress(
state: state,
hasPersonalDiet: false,
);
expect(
progress.dietStatus,
PersonalDietStatus.notRequired,
reason: 'state=${state.name}',
);
expect(progress.hasDietChip, isFalse, reason: 'state=${state.name}');
}
});
test('paid с диетой даёт notProposed', () {
final progress = mapConsultationProgress(
state: ChosenPlanStateEnum.statePaid,
hasPersonalDiet: true,
);
expect(progress.dietStatus, PersonalDietStatus.notProposed);
});
test('personal_diet_setted/started/proposed дают proposed', () {
const states = [
ChosenPlanStateEnum.personalDietSet,
ChosenPlanStateEnum.stateStarted,
];
for (final state in states) {
final progress = mapConsultationProgress(
state: state,
hasPersonalDiet: true,
);
expect(
progress.dietStatus,
PersonalDietStatus.proposed,
reason: 'state=${state.name}',
);
}
});
});
}