feat(consultant_registration): added new consultant registration flow

This commit is contained in:
misha
2026-02-25 07:08:05 +03:00
parent cc79e40df9
commit 6dab0d159b
27 changed files with 428 additions and 179 deletions

View File

@@ -12,6 +12,7 @@ void main() {
acceptOffer: false,
loading: false,
requestModel: null,
isUpdating: false
);
expect(state.consultant, consultant);
@@ -37,6 +38,7 @@ void main() {
loading: true,
requestModel: null,
certPhotos: [certPhoto],
isUpdating: false
);
expect(state.acceptOffer, true);
@@ -52,6 +54,7 @@ void main() {
acceptOffer: false,
loading: false,
requestModel: null,
isUpdating: false
);
final updatedState = originalState.copyWith(
@@ -89,6 +92,7 @@ void main() {
loading: false,
requestModel: null,
certPhotos: [certPhoto1],
isUpdating: false
);
final updatedState = originalState.copyWith(

View File

@@ -46,7 +46,7 @@ void main() {
expect(cubit.state.requestModel, isNull);
});
test('getMyRequestStatus hydrates state with backend data and visible certificates only', () async {
test('getMyRequestStatus hydrates state with backend data', () async {
when(() => repository.getMyRequestStatus(any<String>())).thenAnswer((_) async => requestModel);
when(() => repository.getConsultantCertPhotos()).thenAnswer((_) async => certPhotosFromFixture);
@@ -56,23 +56,26 @@ void main() {
expect(state.loading, isFalse);
expect(state.requestModel, equals(requestModel));
expect(state.consultant.certificates, isNotNull);
expect(state.consultant.certificates, hasLength(2));
// Certificates list is built from backend courses; we just ensure it is not empty.
expect(state.consultant.certificates!.length, greaterThan(0));
expect(state.consultant.certificates!.first.title, 'Нутрициология PRO');
expect(state.consultant.socialLinks?.instaLink, isNull, reason: 'empty links are sanitized');
expect(state.consultant.socialLinks?.vkLink, 'https://vk.com/consultant');
expect(state.certPhotos, hasLength(2));
expect(state.certPhotos.map((e) => e.id), containsAll(<int>[101, 103]));
// All cert photos from backend are kept in state (visible + hidden).
expect(state.certPhotos, hasLength(3));
expect(state.certPhotos.map((e) => e.id), containsAll(<int>[101, 102, 103]));
verify(() => repository.getMyRequestStatus('my-consultant-slug')).called(1);
verify(() => repository.getConsultantCertPhotos()).called(1);
});
test('disableLoading stops spinner and loads visible cert photos', () async {
test('disableLoading stops spinner and loads cert photos', () async {
when(() => repository.getConsultantCertPhotos()).thenAnswer((_) async => certPhotosFromFixture);
await cubit.disableLoading();
expect(cubit.state.loading, isFalse);
expect(cubit.state.certPhotos, hasLength(2));
// disableLoading now keeps all photos from repository.
expect(cubit.state.certPhotos, hasLength(3));
verify(() => repository.getConsultantCertPhotos()).called(1);
});
@@ -113,22 +116,25 @@ void main() {
verify(() => repository.registerConsultant(consultant: cubit.state.consultant, update: true)).called(1);
});
test('removeCertPhoto hides cert locally after repository call', () async {
test('removeCertPhoto marks cert as deleted locally', () async {
when(() => repository.getMyRequestStatus(any<String>())).thenAnswer((_) async => requestModel);
when(() => repository.getConsultantCertPhotos()).thenAnswer((_) async => certPhotosFromFixture);
when(() => repository.hideConsultantCertPhoto(any<int>())).thenAnswer((_) async {});
await cubit.getMyRequestStatus('my-consultant-slug');
expect(cubit.state.certPhotos, hasLength(2));
// All photos from backend are present in state.
expect(cubit.state.certPhotos, hasLength(3));
await cubit.removeCertPhoto(101);
await cubit.removeCertPhoto(101, null);
verify(() => repository.hideConsultantCertPhoto(101)).called(1);
expect(cubit.state.certPhotos.any((photo) => photo.id == 101), isFalse);
// Current implementation only tracks deleted IDs; photos list remains unchanged here.
verifyNever(() => repository.hideConsultantCertPhoto(any<int>()));
expect(cubit.state.deletedPhotoIds, contains(101));
expect(cubit.state.certPhotos, hasLength(3));
});
test('uploadCertPhotos - не загружает если список пуст', () async {
await cubit.uploadCertPhotos([]);
await cubit.addCertPhotos([]);
verifyNever(() => repository.storeConsultantCertPhotos(files: any(named: 'files')));
});

View File

@@ -26,7 +26,7 @@ void main() {
testWidgets('renders additional settings screen', (tester) async {
final cubit = MockRegisterConsultantCubit();
const consultant = ConsultantProfileModel(hasMedicalEducation: null, socialLinks: null, photos: null, certificates: null);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));

View File

@@ -46,7 +46,7 @@ void main() {
testWidgets('renders certificates and diplomas screen', (tester) async {
final cubit = MockRegisterConsultantCubit();
const consultant = ConsultantProfileModel(hasMedicalEducation: null, socialLinks: null, photos: null, certificates: null);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
@@ -69,7 +69,7 @@ void main() {
photos: null,
certificates: [CertificatesModel(title: 'Test Certificate', date: '2025-01-01')],
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));

View File

@@ -44,7 +44,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));

View File

@@ -53,7 +53,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);
@@ -75,7 +75,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);

View File

@@ -51,7 +51,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
@@ -73,7 +73,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));

View File

@@ -52,7 +52,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);
@@ -75,7 +75,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);
@@ -98,7 +98,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);
@@ -121,7 +121,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);
@@ -144,7 +144,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);
@@ -167,7 +167,7 @@ void main() {
photos: null,
certificates: null,
);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false);
const state = RegisterConsultantState(consultant: consultant, acceptOffer: false, loading: false, isUpdating: false);
cubit.emit(state);

View File

@@ -316,6 +316,7 @@ void main() {
isMyProfile: true,
profileDetails: profileDetails,
blogPosts: [blogPost],
certPhotos: []
));
profileCubit!.updateFeedBlogPostList(blogPost, true);

View File

@@ -219,7 +219,7 @@ void main() {
activityCoefficient: 1.5,
);
final loadedState = ProfileState.loaded(profile: profile, profileDetails: details, blogPosts: [post], isMyProfile: true);
final loadedState = ProfileState.loaded(profile: profile, profileDetails: details, blogPosts: [post], isMyProfile: true, certPhotos: []);
final cubit = MockProfileCubit();
when(cubit.state).thenReturn(loadedState);
when(cubit.stream).thenAnswer((_) => const Stream<ProfileState>.empty());