forked from baron/baron-sso
132 lines
4.0 KiB
Dart
132 lines
4.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:userfront/features/profile/data/models/user_profile_model.dart';
|
|
import 'package:userfront/features/profile/domain/notifiers/profile_notifier.dart';
|
|
import 'package:userfront/features/profile/presentation/pages/profile_page.dart';
|
|
|
|
// Mocking the profile notifier
|
|
class MockProfileNotifier extends ProfileNotifier {
|
|
UserProfile? _profile;
|
|
bool updateCalled = false;
|
|
String? updatedName;
|
|
|
|
@override
|
|
Future<UserProfile?> build() async {
|
|
_profile = UserProfile(
|
|
id: 'test-id',
|
|
email: 'test@example.com',
|
|
name: 'Original Name',
|
|
phone: '01012345678',
|
|
department: 'Dev',
|
|
affiliationType: 'employee',
|
|
companyCode: 'C100',
|
|
);
|
|
return _profile;
|
|
}
|
|
|
|
@override
|
|
Future<UserProfile?> loadProfile() async {
|
|
state = const AsyncValue.loading();
|
|
state = AsyncValue.data(_profile);
|
|
return _profile;
|
|
}
|
|
|
|
@override
|
|
Future<void> updateProfile({
|
|
String? name,
|
|
String? phone,
|
|
String? department,
|
|
}) async {
|
|
updateCalled = true;
|
|
updatedName = name;
|
|
_profile = _profile!.copyWith(
|
|
name: name ?? _profile!.name,
|
|
phone: phone ?? _profile!.phone,
|
|
department: department ?? _profile!.department,
|
|
);
|
|
state = AsyncValue.data(_profile);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
testWidgets(
|
|
'ProfilePage explicit save button UX flow (Edit -> Cancel -> Edit -> Save)',
|
|
(tester) async {
|
|
final recordedErrors = <FlutterErrorDetails>[];
|
|
final previousOnError = FlutterError.onError;
|
|
FlutterError.onError = (details) {
|
|
final text = details.exceptionAsString();
|
|
if (text.contains('A RenderFlex overflowed')) {
|
|
return;
|
|
}
|
|
recordedErrors.add(details);
|
|
};
|
|
addTearDown(() {
|
|
FlutterError.onError = previousOnError;
|
|
});
|
|
|
|
tester.view.physicalSize = const Size(1920, 1080);
|
|
tester.view.devicePixelRatio = 1.0;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
final mockNotifier = MockProfileNotifier();
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [profileProvider.overrideWith(() => mockNotifier)],
|
|
child: const MaterialApp(home: Scaffold(body: ProfilePage())),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
// 1. Entering edit mode
|
|
final editButton = find.byKey(const Key('profile-name-edit-button'));
|
|
expect(editButton, findsOneWidget);
|
|
await tester.tap(editButton);
|
|
await tester.pumpAndSettle();
|
|
|
|
final inputField = find.byKey(const Key('profile-name-input'));
|
|
expect(inputField, findsOneWidget);
|
|
|
|
// 2. Testing cancel flow
|
|
await tester.enterText(inputField, 'Changed Name');
|
|
await tester.pumpAndSettle();
|
|
|
|
final cancelButton = find.byKey(const Key('profile-name-cancel-button'));
|
|
await tester.tap(cancelButton);
|
|
await tester.pumpAndSettle();
|
|
|
|
// After cancellation, the field should be read-only again.
|
|
expect(find.byKey(const Key('profile-name-input')), findsNothing);
|
|
// Find text could be part of ListTile
|
|
expect(find.text('Original Name'), findsWidgets);
|
|
|
|
// 3. Re-enter edit mode and explicitly save
|
|
await tester.tap(find.byKey(const Key('profile-name-edit-button')));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.enterText(
|
|
find.byKey(const Key('profile-name-input')),
|
|
'Saved Name',
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
final saveButton = find.byKey(const Key('profile-name-save-button'));
|
|
await tester.tap(saveButton);
|
|
await tester.pumpAndSettle();
|
|
await tester.pump(const Duration(seconds: 4));
|
|
await tester.pumpAndSettle();
|
|
|
|
FlutterError.onError = previousOnError;
|
|
|
|
// Verify the mock received the update
|
|
expect(mockNotifier.updateCalled, isTrue);
|
|
expect(mockNotifier.updatedName, 'Saved Name');
|
|
expect(recordedErrors, isEmpty);
|
|
},
|
|
);
|
|
}
|