forked from baron/baron-sso
121 lines
3.8 KiB
Dart
121 lines
3.8 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();
|
|
|
|
// Verify the mock received the update
|
|
expect(mockNotifier.updateCalled, isTrue);
|
|
expect(mockNotifier.updatedName, 'Saved Name');
|
|
});
|
|
}
|