changes
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel Forgot Password', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
late BuildContext mockContext;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
mockContext = const TestWidget().createElement();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
test('should send forgot password successfully', () async {
|
||||
mockRepository.setForgotPasswordResult(
|
||||
const Result.ok(TestFixtures.forgotPasswordResponse),
|
||||
);
|
||||
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
|
||||
await authViewModel.forgotPassword(mockContext);
|
||||
|
||||
expect(authViewModel.isLoadingForgot, false);
|
||||
expect(authViewModel.successMessage, 'OTP sent to email');
|
||||
expect(authViewModel.errorMessageForget, null);
|
||||
});
|
||||
|
||||
test('should handle forgot password error', () async {
|
||||
const errorMessage = 'Email not found';
|
||||
mockRepository.setForgotPasswordResult(
|
||||
Result.error(Exception(errorMessage)),
|
||||
);
|
||||
|
||||
authViewModel.emailController.text = 'nonexistent@example.com';
|
||||
|
||||
await authViewModel.forgotPassword(mockContext);
|
||||
|
||||
// Wait for the microtask to clear the error message
|
||||
await Future.microtask(() {});
|
||||
|
||||
expect(authViewModel.isLoadingForgot, false);
|
||||
expect(authViewModel.errorMessageForget, null); // Cleared after notify
|
||||
expect(authViewModel.successMessage, null);
|
||||
});
|
||||
|
||||
test('should set loading state during forgot password', () async {
|
||||
mockRepository.setForgotPasswordResult(
|
||||
const Result.ok(TestFixtures.forgotPasswordResponse),
|
||||
);
|
||||
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
|
||||
final forgotPasswordFuture = authViewModel.forgotPassword(mockContext);
|
||||
|
||||
// Check loading state is set
|
||||
expect(authViewModel.isLoadingForgot, true);
|
||||
expect(authViewModel.errorMessageForget, null);
|
||||
expect(authViewModel.successMessage, null);
|
||||
|
||||
await forgotPasswordFuture;
|
||||
|
||||
expect(authViewModel.isLoadingForgot, false);
|
||||
});
|
||||
|
||||
test('should clear previous messages before forgot password', () async {
|
||||
mockRepository.setForgotPasswordResult(
|
||||
const Result.ok(TestFixtures.forgotPasswordResponse),
|
||||
);
|
||||
|
||||
// Set previous error and success messages
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
mockRepository.setForgotPasswordResult(
|
||||
Result.error(Exception('Previous error')),
|
||||
);
|
||||
await authViewModel.forgotPassword(mockContext);
|
||||
|
||||
// Now test successful case
|
||||
mockRepository.setForgotPasswordResult(
|
||||
const Result.ok(TestFixtures.forgotPasswordResponse),
|
||||
);
|
||||
await authViewModel.forgotPassword(mockContext);
|
||||
|
||||
expect(authViewModel.errorMessageForget, null);
|
||||
expect(authViewModel.successMessage, 'OTP sent to email');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class TestWidget extends StatelessWidget {
|
||||
const TestWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel Initialization', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
test('should initialize with default values', () {
|
||||
expect(authViewModel.isLoading, false);
|
||||
expect(authViewModel.isLoggedIn, false);
|
||||
expect(authViewModel.isLoadingForgot, false);
|
||||
expect(authViewModel.isLoadingOtp, false);
|
||||
expect(authViewModel.isResetPasswordLoading, false);
|
||||
expect(authViewModel.errorMessage, null);
|
||||
expect(authViewModel.errorMessageForget, null);
|
||||
expect(authViewModel.resetPasswordErrorMessage, null);
|
||||
expect(authViewModel.errorMessageOtp, null);
|
||||
expect(authViewModel.successMessageOtp, null);
|
||||
expect(authViewModel.verifyOtpSuccess, false);
|
||||
expect(authViewModel.loggedInUser, null);
|
||||
expect(authViewModel.forgotPasswordMessage, null);
|
||||
expect(authViewModel.resetToken, null);
|
||||
expect(authViewModel.resetPasswordSuccess, false);
|
||||
});
|
||||
|
||||
test('should initialize controllers with empty text', () {
|
||||
expect(authViewModel.usernameController.text, isEmpty);
|
||||
expect(authViewModel.passwordController.text, isEmpty);
|
||||
expect(authViewModel.emailController.text, isEmpty);
|
||||
expect(authViewModel.newPasswordController.text, isEmpty);
|
||||
expect(authViewModel.otpController.text, isEmpty);
|
||||
});
|
||||
|
||||
test('should initialize with password visibility obscured', () {
|
||||
expect(authViewModel.obscurePassword, true);
|
||||
expect(authViewModel.obscureForgotPassword, true);
|
||||
});
|
||||
|
||||
test('should not be login enabled with empty fields', () {
|
||||
expect(authViewModel.isLoginEnabled, false);
|
||||
});
|
||||
|
||||
test('should be login enabled with filled fields', () {
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'testpass';
|
||||
|
||||
expect(authViewModel.isLoginEnabled, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel Login', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
test('should login successfully', () async {
|
||||
mockRepository.setLoginResult(
|
||||
const Result.ok(TestFixtures.loginResponse),
|
||||
);
|
||||
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'testpass';
|
||||
|
||||
await authViewModel.login();
|
||||
|
||||
expect(authViewModel.isLoading, false);
|
||||
expect(authViewModel.loggedInUser, TestFixtures.customer);
|
||||
expect(authViewModel.usernameController.text, isEmpty);
|
||||
expect(authViewModel.passwordController.text, isEmpty);
|
||||
expect(authViewModel.errorMessage, null);
|
||||
});
|
||||
|
||||
test('should handle login error', () async {
|
||||
const errorMessage = 'Invalid credentials';
|
||||
mockRepository.setLoginResult(Result.error(Exception(errorMessage)));
|
||||
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'wrongpass';
|
||||
|
||||
await authViewModel.login();
|
||||
|
||||
expect(authViewModel.isLoading, false);
|
||||
expect(authViewModel.loggedInUser, null);
|
||||
expect(authViewModel.errorMessage, null); // Cleared after notify
|
||||
});
|
||||
|
||||
test('should set loading state during login', () async {
|
||||
mockRepository.setLoginResult(
|
||||
const Result.ok(TestFixtures.loginResponse),
|
||||
);
|
||||
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'testpass';
|
||||
|
||||
final loginFuture = authViewModel.login();
|
||||
|
||||
// Check loading state is set
|
||||
expect(authViewModel.isLoading, true);
|
||||
expect(authViewModel.errorMessage, null);
|
||||
|
||||
await loginFuture;
|
||||
|
||||
expect(authViewModel.isLoading, false);
|
||||
});
|
||||
|
||||
test('should call localLogout before login', () async {
|
||||
mockRepository.setLoginResult(
|
||||
const Result.ok(TestFixtures.loginResponse),
|
||||
);
|
||||
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'testpass';
|
||||
|
||||
await authViewModel.login();
|
||||
|
||||
// Verify that localLogout was called (user is null initially)
|
||||
expect(authViewModel.loggedInUser, TestFixtures.customer);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel Logout', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
test('should logout successfully', () async {
|
||||
mockRepository.setLogoutResult(
|
||||
const Result.ok(TestFixtures.logoutResponse),
|
||||
);
|
||||
|
||||
// Set a logged in user first
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'testpass';
|
||||
mockRepository.setLoginResult(
|
||||
const Result.ok(TestFixtures.loginResponse),
|
||||
);
|
||||
await authViewModel.login();
|
||||
|
||||
await authViewModel.logout();
|
||||
|
||||
expect(authViewModel.loggedInUser, null);
|
||||
expect(authViewModel.errorMessage, null); // Cleared after notify
|
||||
});
|
||||
|
||||
test('should handle logout error', () async {
|
||||
const errorMessage = 'Logout failed';
|
||||
mockRepository.setLogoutResult(Result.error(Exception(errorMessage)));
|
||||
|
||||
await authViewModel.logout();
|
||||
|
||||
expect(authViewModel.errorMessage, null); // Cleared after notify
|
||||
});
|
||||
|
||||
test('should perform local logout', () async {
|
||||
mockRepository.setLogoutResult(
|
||||
const Result.ok(TestFixtures.logoutResponse),
|
||||
);
|
||||
|
||||
// Set a logged in user first
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'testpass';
|
||||
mockRepository.setLoginResult(
|
||||
const Result.ok(TestFixtures.loginResponse),
|
||||
);
|
||||
await authViewModel.login();
|
||||
|
||||
await authViewModel.logout();
|
||||
|
||||
expect(authViewModel.loggedInUser, null);
|
||||
});
|
||||
|
||||
test('should clear error message before logout', () async {
|
||||
mockRepository.setLogoutResult(
|
||||
const Result.ok(TestFixtures.logoutResponse),
|
||||
);
|
||||
|
||||
// Set an error first
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'wrongpass';
|
||||
mockRepository.setLoginResult(Result.error(Exception('Login failed')));
|
||||
await authViewModel.login();
|
||||
|
||||
await authViewModel.logout();
|
||||
|
||||
expect(authViewModel.errorMessage, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel OTP Verification', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
late BuildContext mockContext;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
mockContext = const TestWidget().createElement();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
test('should verify OTP successfully', () async {
|
||||
mockRepository.setVerifyOtpResult(
|
||||
const Result.ok(TestFixtures.verifyOtpResponse),
|
||||
);
|
||||
|
||||
authViewModel.otpController.text = '123456';
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
|
||||
await authViewModel.verifyOtp(mockContext);
|
||||
|
||||
expect(authViewModel.isLoadingOtp, false);
|
||||
expect(authViewModel.verifyOtpSuccess, true);
|
||||
expect(authViewModel.resetToken, 'reset_token_123');
|
||||
expect(
|
||||
authViewModel.successMessageOtp,
|
||||
null,
|
||||
); // Cleared after notify for toast
|
||||
expect(authViewModel.errorMessageOtp, null); // Cleared after notify
|
||||
});
|
||||
|
||||
test('should handle OTP verification error', () async {
|
||||
const errorMessage = 'Invalid OTP';
|
||||
mockRepository.setVerifyOtpResult(Result.error(Exception(errorMessage)));
|
||||
|
||||
authViewModel.otpController.text = '000000';
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
|
||||
await authViewModel.verifyOtp(mockContext);
|
||||
|
||||
expect(authViewModel.isLoadingOtp, false);
|
||||
expect(authViewModel.verifyOtpSuccess, false);
|
||||
expect(authViewModel.errorMessageOtp, null); // Cleared after notify
|
||||
expect(authViewModel.successMessageOtp, null); // Cleared after notify
|
||||
});
|
||||
|
||||
test('should set loading state during OTP verification', () async {
|
||||
mockRepository.setVerifyOtpResult(
|
||||
const Result.ok(TestFixtures.verifyOtpResponse),
|
||||
);
|
||||
|
||||
authViewModel.otpController.text = '123456';
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
|
||||
final verifyOtpFuture = authViewModel.verifyOtp(mockContext);
|
||||
|
||||
// Check loading state is set
|
||||
expect(authViewModel.isLoadingOtp, true);
|
||||
expect(authViewModel.errorMessageOtp, null);
|
||||
expect(authViewModel.verifyOtpSuccess, false);
|
||||
|
||||
await verifyOtpFuture;
|
||||
|
||||
expect(authViewModel.isLoadingOtp, false);
|
||||
});
|
||||
|
||||
test('should clear OTP flow', () {
|
||||
// Set some state first
|
||||
authViewModel.otpController.text = '123456';
|
||||
authViewModel.resetToken = 'some_token';
|
||||
|
||||
authViewModel.clearOtpFlow();
|
||||
|
||||
expect(authViewModel.errorMessageOtp, null);
|
||||
expect(authViewModel.successMessageOtp, null);
|
||||
expect(authViewModel.isLoadingOtp, false);
|
||||
expect(authViewModel.verifyOtpSuccess, false);
|
||||
expect(authViewModel.otpController.text, isEmpty);
|
||||
expect(authViewModel.resetToken, 'some_token'); // Should not be cleared
|
||||
});
|
||||
|
||||
test('should reset verifyOtpSuccess before verification', () async {
|
||||
mockRepository.setVerifyOtpResult(
|
||||
const Result.ok(TestFixtures.verifyOtpResponse),
|
||||
);
|
||||
|
||||
// Set verifyOtpSuccess to true first
|
||||
authViewModel.otpController.text = '123456';
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
await authViewModel.verifyOtp(mockContext);
|
||||
expect(authViewModel.verifyOtpSuccess, true);
|
||||
|
||||
// Now test with error
|
||||
mockRepository.setVerifyOtpResult(Result.error(Exception('Invalid OTP')));
|
||||
await authViewModel.verifyOtp(mockContext);
|
||||
|
||||
expect(authViewModel.verifyOtpSuccess, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class TestWidget extends StatelessWidget {
|
||||
const TestWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel Reset Password', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
test('should reset password successfully', () async {
|
||||
mockRepository.setResetPasswordResult(
|
||||
const Result.ok(TestFixtures.resetPasswordResponse),
|
||||
);
|
||||
|
||||
authViewModel.resetToken = 'reset_token_123';
|
||||
authViewModel.newPasswordController.text = 'NewPass123!';
|
||||
|
||||
await authViewModel.resetPassword();
|
||||
|
||||
expect(authViewModel.isResetPasswordLoading, false);
|
||||
expect(authViewModel.resetPasswordSuccess, true);
|
||||
expect(
|
||||
authViewModel.resetPasswordErrorMessage,
|
||||
null,
|
||||
); // Cleared after notify
|
||||
});
|
||||
|
||||
test('should handle reset password error', () async {
|
||||
const errorMessage = 'Invalid token';
|
||||
mockRepository.setResetPasswordResult(
|
||||
Result.error(Exception(errorMessage)),
|
||||
);
|
||||
|
||||
authViewModel.resetToken = 'invalid_token';
|
||||
authViewModel.newPasswordController.text = 'NewPass123!';
|
||||
|
||||
await authViewModel.resetPassword();
|
||||
|
||||
expect(authViewModel.isResetPasswordLoading, false);
|
||||
expect(authViewModel.resetPasswordSuccess, false);
|
||||
expect(
|
||||
authViewModel.resetPasswordErrorMessage,
|
||||
null,
|
||||
); // Cleared after notify
|
||||
});
|
||||
|
||||
test('should handle missing reset token', () async {
|
||||
authViewModel.resetToken = null;
|
||||
authViewModel.newPasswordController.text = 'NewPass123!';
|
||||
|
||||
await authViewModel.resetPassword();
|
||||
|
||||
expect(authViewModel.isResetPasswordLoading, false);
|
||||
expect(authViewModel.resetPasswordSuccess, false);
|
||||
expect(
|
||||
authViewModel.resetPasswordErrorMessage,
|
||||
'Reset token is required',
|
||||
);
|
||||
});
|
||||
|
||||
test('should set loading state during reset password', () async {
|
||||
mockRepository.setResetPasswordResult(
|
||||
const Result.ok(TestFixtures.resetPasswordResponse),
|
||||
);
|
||||
|
||||
authViewModel.resetToken = 'reset_token_123';
|
||||
authViewModel.newPasswordController.text = 'NewPass123!';
|
||||
|
||||
final resetPasswordFuture = authViewModel.resetPassword();
|
||||
|
||||
// Check loading state is set
|
||||
expect(authViewModel.isResetPasswordLoading, true);
|
||||
expect(authViewModel.resetPasswordErrorMessage, null);
|
||||
expect(authViewModel.resetPasswordSuccess, false);
|
||||
|
||||
await resetPasswordFuture;
|
||||
|
||||
expect(authViewModel.isResetPasswordLoading, false);
|
||||
});
|
||||
|
||||
test('should clear reset password success', () {
|
||||
// Set reset password success through a successful reset
|
||||
mockRepository.setResetPasswordResult(
|
||||
const Result.ok(TestFixtures.resetPasswordResponse),
|
||||
);
|
||||
authViewModel.resetToken = 'reset_token_123';
|
||||
authViewModel.newPasswordController.text = 'NewPass123!';
|
||||
|
||||
authViewModel.clearResetPasswordSuccess();
|
||||
|
||||
expect(authViewModel.resetPasswordSuccess, false);
|
||||
});
|
||||
|
||||
test('should clear reset flow', () {
|
||||
// Set some state first
|
||||
authViewModel.resetToken = 'some_token';
|
||||
authViewModel.newPasswordController.text = 'some_password';
|
||||
|
||||
authViewModel.clearResetFlow();
|
||||
|
||||
expect(authViewModel.resetPasswordErrorMessage, null);
|
||||
expect(authViewModel.resetPasswordSuccess, false);
|
||||
expect(authViewModel.isResetPasswordLoading, false);
|
||||
expect(authViewModel.newPasswordController.text, isEmpty);
|
||||
expect(authViewModel.resetToken, 'some_token'); // Should not be cleared
|
||||
});
|
||||
|
||||
test('should reset success state before reset password', () async {
|
||||
mockRepository.setResetPasswordResult(
|
||||
const Result.ok(TestFixtures.resetPasswordResponse),
|
||||
);
|
||||
|
||||
// Set resetPasswordSuccess to true first
|
||||
authViewModel.resetToken = 'reset_token_123';
|
||||
authViewModel.newPasswordController.text = 'NewPass123!';
|
||||
await authViewModel.resetPassword();
|
||||
expect(authViewModel.resetPasswordSuccess, true);
|
||||
|
||||
// Now test with error
|
||||
mockRepository.setResetPasswordResult(
|
||||
Result.error(Exception('Reset failed')),
|
||||
);
|
||||
await authViewModel.resetPassword();
|
||||
|
||||
expect(authViewModel.resetPasswordSuccess, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel Utility Methods', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
group('Password Visibility Toggle', () {
|
||||
test('should toggle password visibility', () {
|
||||
expect(authViewModel.obscurePassword, true);
|
||||
|
||||
authViewModel.togglePasswordVisibility();
|
||||
expect(authViewModel.obscurePassword, false);
|
||||
|
||||
authViewModel.togglePasswordVisibility();
|
||||
expect(authViewModel.obscurePassword, true);
|
||||
});
|
||||
|
||||
test('should toggle forgot password visibility', () {
|
||||
expect(authViewModel.obscureForgotPassword, true);
|
||||
|
||||
authViewModel.toggleForgotPasswordVisibility();
|
||||
expect(authViewModel.obscureForgotPassword, false);
|
||||
|
||||
authViewModel.toggleForgotPasswordVisibility();
|
||||
expect(authViewModel.obscureForgotPassword, true);
|
||||
});
|
||||
});
|
||||
|
||||
group('Message Clearing', () {
|
||||
test('should clear messages', () {
|
||||
// Set some messages first through login error
|
||||
mockRepository.setLoginResult(Result.error(Exception('Login failed')));
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'wrongpass';
|
||||
|
||||
authViewModel.clearMessages();
|
||||
|
||||
expect(authViewModel.successMessage, null);
|
||||
expect(authViewModel.errorMessage, null);
|
||||
});
|
||||
});
|
||||
|
||||
group('Check Login Status', () {
|
||||
test('should check if user is logged in - true', () async {
|
||||
mockRepository.setCheckIsLoggedInResult(const Result.ok(true));
|
||||
|
||||
await authViewModel.checkIsLoggedIn();
|
||||
|
||||
expect(authViewModel.isLoggedIn, true);
|
||||
});
|
||||
|
||||
test('should check if user is logged in - false', () async {
|
||||
mockRepository.setCheckIsLoggedInResult(const Result.ok(false));
|
||||
|
||||
await authViewModel.checkIsLoggedIn();
|
||||
|
||||
expect(authViewModel.isLoggedIn, false);
|
||||
});
|
||||
|
||||
test('should handle check login error', () async {
|
||||
mockRepository.setCheckIsLoggedInResult(
|
||||
Result.error(Exception('Check failed')),
|
||||
);
|
||||
|
||||
await authViewModel.checkIsLoggedIn();
|
||||
|
||||
expect(authViewModel.isLoggedIn, false);
|
||||
});
|
||||
});
|
||||
|
||||
group('Local Logout', () {
|
||||
test('should perform local logout', () async {
|
||||
// Set a logged in user first
|
||||
authViewModel.usernameController.text = 'testuser';
|
||||
authViewModel.passwordController.text = 'testpass';
|
||||
mockRepository.setLoginResult(
|
||||
const Result.ok(TestFixtures.loginResponse),
|
||||
);
|
||||
await authViewModel.login();
|
||||
|
||||
await authViewModel.localLogout();
|
||||
|
||||
expect(authViewModel.loggedInUser, null);
|
||||
});
|
||||
|
||||
test('should handle local logout exception', () async {
|
||||
mockRepository.setLocalLogoutException(
|
||||
Exception('Local logout failed'),
|
||||
);
|
||||
|
||||
// Should not throw exception
|
||||
await authViewModel.localLogout();
|
||||
|
||||
expect(authViewModel.loggedInUser, null);
|
||||
});
|
||||
});
|
||||
|
||||
group('Text Change Notification', () {
|
||||
test('should notify listeners on text change', () {
|
||||
int notificationCount = 0;
|
||||
|
||||
authViewModel.addListener(() {
|
||||
notificationCount++;
|
||||
});
|
||||
|
||||
// Trigger text change
|
||||
authViewModel.usernameController.text = 'test';
|
||||
|
||||
expect(notificationCount, greaterThan(0));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/view_models/auth_view_model.dart';
|
||||
|
||||
import '../mocks/mock_auth_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthViewModel Validation', () {
|
||||
late MockAuthRepository mockRepository;
|
||||
late AuthViewModel authViewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockAuthRepository();
|
||||
authViewModel = AuthViewModel(authRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
authViewModel.dispose();
|
||||
});
|
||||
|
||||
group('Email Validation', () {
|
||||
test('should return true for valid email', () {
|
||||
authViewModel.emailController.text = 'test@example.com';
|
||||
expect(authViewModel.isEmailValid, true);
|
||||
});
|
||||
|
||||
test('should return false for invalid email', () {
|
||||
authViewModel.emailController.text = 'invalid-email';
|
||||
expect(authViewModel.isEmailValid, false);
|
||||
});
|
||||
|
||||
test('should return false for empty email', () {
|
||||
authViewModel.emailController.text = '';
|
||||
expect(authViewModel.isEmailValid, false);
|
||||
});
|
||||
|
||||
test('should return false for email without domain', () {
|
||||
authViewModel.emailController.text = 'test@';
|
||||
expect(authViewModel.isEmailValid, false);
|
||||
});
|
||||
});
|
||||
|
||||
group('OTP Validation', () {
|
||||
test('should return true for valid 6-digit OTP', () {
|
||||
authViewModel.otpController.text = '123456';
|
||||
expect(authViewModel.isOtpValid, true);
|
||||
expect(authViewModel.canSubmitOtpPage, true);
|
||||
});
|
||||
|
||||
test('should return false for invalid OTP length', () {
|
||||
authViewModel.otpController.text = '12345';
|
||||
expect(authViewModel.isOtpValid, false);
|
||||
expect(authViewModel.canSubmitOtpPage, false);
|
||||
});
|
||||
|
||||
test('should return false for empty OTP', () {
|
||||
authViewModel.otpController.text = '';
|
||||
expect(authViewModel.isOtpValid, false);
|
||||
expect(authViewModel.canSubmitOtpPage, false);
|
||||
});
|
||||
});
|
||||
|
||||
group('Password Validation', () {
|
||||
test('should return true for valid password', () {
|
||||
authViewModel.newPasswordController.text = 'Test123!';
|
||||
expect(authViewModel.isNewPasswordValid, true);
|
||||
});
|
||||
|
||||
test('should return false for password without uppercase', () {
|
||||
authViewModel.newPasswordController.text = 'test123!';
|
||||
expect(authViewModel.isNewPasswordValid, false);
|
||||
});
|
||||
|
||||
test('should return false for password without lowercase', () {
|
||||
authViewModel.newPasswordController.text = 'TEST123!';
|
||||
expect(authViewModel.isNewPasswordValid, false);
|
||||
});
|
||||
|
||||
test('should return false for password without special character', () {
|
||||
authViewModel.newPasswordController.text = 'Test123';
|
||||
expect(authViewModel.isNewPasswordValid, false);
|
||||
});
|
||||
|
||||
test('should return false for password too short', () {
|
||||
authViewModel.newPasswordController.text = 'Te1!';
|
||||
expect(authViewModel.isNewPasswordValid, false);
|
||||
});
|
||||
|
||||
test('should return false for empty password', () {
|
||||
authViewModel.newPasswordController.text = '';
|
||||
expect(authViewModel.isNewPasswordValid, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/your_tenders_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_your_tenders_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('YourTendersViewModel GetTendersFeedback', () {
|
||||
late MockYourTendersRepository mockRepository;
|
||||
late YourTendersViewModel viewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockYourTendersRepository();
|
||||
viewModel = YourTendersViewModel(yourTendersRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
viewModel.dispose();
|
||||
});
|
||||
|
||||
test('should get tenders feedback successfully', () async {
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
await viewModel.getTendersFeedback(feedbackType: 'liked', reset: true);
|
||||
|
||||
expect(viewModel.isLoading, false);
|
||||
expect(viewModel.likedTendersData, TestFixtures.likedTendersResponse);
|
||||
expect(viewModel.errorMessage, null);
|
||||
expect(viewModel.hasMore, true);
|
||||
});
|
||||
|
||||
test('should handle get tenders feedback error', () async {
|
||||
const errorMessage = 'Network error';
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
Result.error(Exception(errorMessage)),
|
||||
);
|
||||
|
||||
await viewModel.getTendersFeedback(feedbackType: 'liked', reset: true);
|
||||
|
||||
expect(viewModel.isLoading, false);
|
||||
expect(viewModel.likedTendersData, null);
|
||||
expect(viewModel.errorMessage, errorMessage);
|
||||
});
|
||||
|
||||
test('should set loading state during get feedback', () async {
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
final getFeedbackFuture = viewModel.getTendersFeedback(
|
||||
feedbackType: 'liked',
|
||||
reset: true,
|
||||
);
|
||||
|
||||
expect(viewModel.isLoading, true);
|
||||
expect(viewModel.errorMessage, null);
|
||||
|
||||
await getFeedbackFuture;
|
||||
|
||||
expect(viewModel.isLoading, false);
|
||||
});
|
||||
|
||||
test('should reset data when reset is true', () async {
|
||||
// First load
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
await viewModel.getTendersFeedback(feedbackType: 'liked', reset: true);
|
||||
expect(viewModel.likedTendersData, TestFixtures.likedTendersResponse);
|
||||
|
||||
// Reset and load again
|
||||
await viewModel.getTendersFeedback(feedbackType: 'liked', reset: true);
|
||||
expect(viewModel.likedTendersData, TestFixtures.likedTendersResponse);
|
||||
});
|
||||
|
||||
test('should not load more when already loading', () async {
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
viewModel.isLoadingMore = true;
|
||||
await viewModel.getTendersFeedback(feedbackType: 'liked', reset: false);
|
||||
|
||||
expect(viewModel.likedTendersData, null);
|
||||
});
|
||||
|
||||
test('should not load more when no more data', () async {
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
viewModel.hasMore = false;
|
||||
await viewModel.getTendersFeedback(feedbackType: 'liked', reset: false);
|
||||
|
||||
expect(viewModel.likedTendersData, null);
|
||||
});
|
||||
|
||||
test('should load more feedback successfully', () async {
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
// Set current feedback type
|
||||
viewModel.getTendersFeedback(feedbackType: 'liked', reset: true);
|
||||
await viewModel.loadMoreFeedback();
|
||||
|
||||
expect(viewModel.likedTendersData, TestFixtures.likedTendersResponse);
|
||||
});
|
||||
|
||||
test('should not load more feedback when no current type', () async {
|
||||
await viewModel.loadMoreFeedback();
|
||||
expect(viewModel.likedTendersData, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/your_tenders_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_your_tenders_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('YourTendersViewModel Filter', () {
|
||||
late MockYourTendersRepository mockRepository;
|
||||
late YourTendersViewModel viewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockYourTendersRepository();
|
||||
viewModel = YourTendersViewModel(yourTendersRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
viewModel.dispose();
|
||||
});
|
||||
|
||||
test('should set date range correctly', () {
|
||||
final dateRange = DateTimeRange(
|
||||
start: DateTime(2024, 1, 1),
|
||||
end: DateTime(2024, 1, 31),
|
||||
);
|
||||
|
||||
viewModel.setDateRange(dateRange);
|
||||
|
||||
expect(viewModel.selectedDateRange, dateRange);
|
||||
expect(viewModel.startDateFormatted, '2024/01/01');
|
||||
expect(viewModel.endDateFormatted, '2024/01/31');
|
||||
expect(viewModel.startDateUnix, '1704067200');
|
||||
expect(viewModel.endDateUnix, '1706745600');
|
||||
});
|
||||
|
||||
test('should set status and clear data', () {
|
||||
// Set some initial data
|
||||
viewModel.data = TestFixtures.tenderApprovalsResponse;
|
||||
viewModel.likedTendersData = TestFixtures.likedTendersResponse;
|
||||
viewModel.isLoading = true;
|
||||
viewModel.errorMessage = 'Error';
|
||||
|
||||
viewModel.setStatus('submitted');
|
||||
|
||||
expect(viewModel.selectedStatus, 'submitted');
|
||||
expect(viewModel.data, null);
|
||||
expect(viewModel.likedTendersData, null);
|
||||
expect(viewModel.isLoading, false);
|
||||
expect(viewModel.errorMessage, null);
|
||||
expect(viewModel.currentPage, 1);
|
||||
});
|
||||
|
||||
test('should clear filter and reset state', () {
|
||||
// Set some initial data
|
||||
final dateRange = DateTimeRange(
|
||||
start: DateTime(2024, 1, 1),
|
||||
end: DateTime(2024, 1, 31),
|
||||
);
|
||||
viewModel.setDateRange(dateRange);
|
||||
viewModel.setStatus('submitted');
|
||||
viewModel.data = TestFixtures.tenderApprovalsResponse;
|
||||
|
||||
viewModel.clearFilter();
|
||||
|
||||
expect(viewModel.selectedDateRange, null);
|
||||
expect(viewModel.selectedStatus, 'All');
|
||||
expect(viewModel.data, null);
|
||||
expect(viewModel.likedTendersData, null);
|
||||
expect(viewModel.isLoading, false);
|
||||
expect(viewModel.errorMessage, null);
|
||||
});
|
||||
|
||||
test('should call with filter for all status', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'All';
|
||||
await viewModel.callWithFilter();
|
||||
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
expect(viewModel.isLoading, false);
|
||||
});
|
||||
|
||||
test('should call with filter for submitted status', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'Tenders Submitted';
|
||||
await viewModel.callWithFilter();
|
||||
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
expect(viewModel.isLoading, false);
|
||||
});
|
||||
|
||||
test('should call with filter for liked tenders', () async {
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'Like Tenders';
|
||||
await viewModel.callWithFilter();
|
||||
|
||||
expect(viewModel.likedTendersData, TestFixtures.likedTendersResponse);
|
||||
expect(viewModel.isLoading, false);
|
||||
});
|
||||
|
||||
test('should call with filter for disliked tenders', () async {
|
||||
mockRepository.setGetTendersFeedbackResult(
|
||||
const Result.ok(TestFixtures.likedTendersResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'Dislike Tenders';
|
||||
await viewModel.callWithFilter();
|
||||
|
||||
expect(viewModel.likedTendersData, TestFixtures.likedTendersResponse);
|
||||
expect(viewModel.isLoading, false);
|
||||
});
|
||||
|
||||
test('should format dates correctly with date range', () {
|
||||
final dateRange = DateTimeRange(
|
||||
start: DateTime(2024, 12, 25),
|
||||
end: DateTime(2024, 12, 31),
|
||||
);
|
||||
|
||||
viewModel.setDateRange(dateRange);
|
||||
|
||||
expect(viewModel.startDateFormatted, '2024/12/25');
|
||||
expect(viewModel.endDateFormatted, '2024/12/31');
|
||||
expect(viewModel.startDateUnix, '1735084800');
|
||||
expect(viewModel.endDateUnix, '1735689600');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/data/services/model/request_models/get_tenders_request_model/get_tenders_request_model.dart';
|
||||
import 'package:tm_app/view_models/your_tenders_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_your_tenders_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('YourTendersViewModel GetTenders', () {
|
||||
late MockYourTendersRepository mockRepository;
|
||||
late YourTendersViewModel viewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockYourTendersRepository();
|
||||
viewModel = YourTendersViewModel(yourTendersRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
viewModel.dispose();
|
||||
});
|
||||
|
||||
test('should get tenders successfully', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
final requestModel = GetTendersRequestModel(
|
||||
status: 'submitted',
|
||||
createdFrom: '1640995200',
|
||||
createdTo: '1640995200',
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
);
|
||||
|
||||
await viewModel.getTenders(requestModel: requestModel);
|
||||
|
||||
expect(viewModel.isLoading, false);
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
expect(viewModel.errorMessage, null);
|
||||
expect(viewModel.hasMoreTenders, true);
|
||||
});
|
||||
|
||||
test('should handle get tenders error', () async {
|
||||
const errorMessage = 'Network error';
|
||||
mockRepository.setGetTendersResult(Result.error(Exception(errorMessage)));
|
||||
|
||||
final requestModel = GetTendersRequestModel(
|
||||
status: 'submitted',
|
||||
createdFrom: '1640995200',
|
||||
createdTo: '1640995200',
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
);
|
||||
|
||||
await viewModel.getTenders(requestModel: requestModel);
|
||||
|
||||
expect(viewModel.isLoading, false);
|
||||
expect(viewModel.data, null);
|
||||
expect(viewModel.errorMessage, errorMessage);
|
||||
});
|
||||
|
||||
test('should set loading state during get tenders', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
final requestModel = GetTendersRequestModel(
|
||||
status: 'submitted',
|
||||
createdFrom: '1640995200',
|
||||
createdTo: '1640995200',
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
);
|
||||
|
||||
final getTendersFuture = viewModel.getTenders(requestModel: requestModel);
|
||||
|
||||
expect(viewModel.isLoading, true);
|
||||
expect(viewModel.errorMessage, null);
|
||||
|
||||
await getTendersFuture;
|
||||
|
||||
expect(viewModel.isLoading, false);
|
||||
});
|
||||
|
||||
test('should reset data when reset is true', () async {
|
||||
// First load
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
final requestModel = GetTendersRequestModel(
|
||||
status: 'submitted',
|
||||
createdFrom: '1640995200',
|
||||
createdTo: '1640995200',
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
);
|
||||
|
||||
await viewModel.getTenders(requestModel: requestModel);
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
|
||||
// Reset and load again
|
||||
await viewModel.getTenders(requestModel: requestModel, reset: true);
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
});
|
||||
|
||||
test('should not load more when already loading', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
final requestModel = GetTendersRequestModel(
|
||||
status: 'submitted',
|
||||
createdFrom: '1640995200',
|
||||
createdTo: '1640995200',
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
);
|
||||
|
||||
viewModel.isLoadingMoreTenders = true;
|
||||
await viewModel.getTenders(requestModel: requestModel);
|
||||
|
||||
expect(viewModel.data, null);
|
||||
});
|
||||
|
||||
test('should not load more when no more data', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
final requestModel = GetTendersRequestModel(
|
||||
status: 'submitted',
|
||||
createdFrom: '1640995200',
|
||||
createdTo: '1640995200',
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
);
|
||||
|
||||
viewModel.hasMoreTenders = false;
|
||||
await viewModel.getTenders(requestModel: requestModel);
|
||||
|
||||
expect(viewModel.data, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/view_models/your_tenders_view_model.dart';
|
||||
|
||||
import '../mocks/mock_your_tenders_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('YourTendersViewModel Initialization', () {
|
||||
late MockYourTendersRepository mockRepository;
|
||||
late YourTendersViewModel viewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockYourTendersRepository();
|
||||
viewModel = YourTendersViewModel(yourTendersRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
viewModel.dispose();
|
||||
});
|
||||
|
||||
test('should initialize with default values', () {
|
||||
expect(viewModel.isLoading, false);
|
||||
expect(viewModel.errorMessage, null);
|
||||
expect(viewModel.data, null);
|
||||
expect(viewModel.likedTendersData, null);
|
||||
expect(viewModel.isLoadingMore, false);
|
||||
expect(viewModel.hasMore, true);
|
||||
expect(viewModel.isLoadingMoreTenders, false);
|
||||
expect(viewModel.hasMoreTenders, true);
|
||||
expect(viewModel.selectedDateRange, null);
|
||||
expect(viewModel.selectedStatus, 'All');
|
||||
expect(viewModel.currentPage, 1);
|
||||
});
|
||||
|
||||
test('should format dates correctly when no date range is selected', () {
|
||||
expect(viewModel.startDateFormatted, 'YYYY/MM/DD');
|
||||
expect(viewModel.endDateFormatted, 'YYYY/MM/DD');
|
||||
expect(viewModel.startDateUnix, '');
|
||||
expect(viewModel.endDateUnix, '');
|
||||
});
|
||||
|
||||
test('should calculate total pages correctly when no data', () {
|
||||
expect(viewModel.totalPages, 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/utils/result.dart';
|
||||
import 'package:tm_app/view_models/your_tenders_view_model.dart';
|
||||
|
||||
import '../fixtures/test_fixtures.dart';
|
||||
import '../mocks/mock_your_tenders_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('YourTendersViewModel Pagination', () {
|
||||
late MockYourTendersRepository mockRepository;
|
||||
late YourTendersViewModel viewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockYourTendersRepository();
|
||||
viewModel = YourTendersViewModel(yourTendersRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
viewModel.dispose();
|
||||
});
|
||||
|
||||
test('should calculate total pages from tender data', () {
|
||||
viewModel.data = TestFixtures.tenderApprovalsResponse;
|
||||
expect(viewModel.totalPages, 1);
|
||||
});
|
||||
|
||||
test('should calculate total pages from feedback data', () {
|
||||
viewModel.likedTendersData = TestFixtures.likedTendersResponse;
|
||||
expect(viewModel.totalPages, 1);
|
||||
});
|
||||
|
||||
test('should return 1 when no data available', () {
|
||||
expect(viewModel.totalPages, 1);
|
||||
});
|
||||
|
||||
test('should jump to page successfully', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'All';
|
||||
await viewModel.jumpToPage(2);
|
||||
|
||||
expect(viewModel.currentPage, 2);
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
expect(viewModel.likedTendersData, null);
|
||||
expect(viewModel.hasMore, true);
|
||||
expect(viewModel.hasMoreTenders, true);
|
||||
});
|
||||
|
||||
test('should load more tenders for all status', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'All';
|
||||
await viewModel.loadMoreTenders();
|
||||
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
});
|
||||
|
||||
test('should load more tenders for submitted status', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'Tenders Submitted';
|
||||
await viewModel.loadMoreTenders();
|
||||
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
});
|
||||
|
||||
test('should not load more tenders when already loading', () async {
|
||||
viewModel.isLoadingMoreTenders = true;
|
||||
await viewModel.loadMoreTenders();
|
||||
|
||||
expect(viewModel.data, null);
|
||||
});
|
||||
|
||||
test('should not load more tenders when no more data', () async {
|
||||
viewModel.hasMoreTenders = false;
|
||||
await viewModel.loadMoreTenders();
|
||||
|
||||
expect(viewModel.data, null);
|
||||
});
|
||||
|
||||
test('should handle pagination with date range', () async {
|
||||
mockRepository.setGetTendersResult(
|
||||
const Result.ok(TestFixtures.tenderApprovalsResponse),
|
||||
);
|
||||
|
||||
viewModel.selectedStatus = 'All';
|
||||
viewModel.setDateRange(
|
||||
DateTimeRange(start: DateTime(2024, 1, 1), end: DateTime(2024, 1, 31)),
|
||||
);
|
||||
|
||||
await viewModel.loadMoreTenders();
|
||||
|
||||
expect(viewModel.data, TestFixtures.tenderApprovalsResponse);
|
||||
});
|
||||
|
||||
test('should reset pagination state when clearing data', () {
|
||||
// Set some pagination state
|
||||
viewModel.currentPage = 3;
|
||||
viewModel.data = TestFixtures.tenderApprovalsResponse;
|
||||
viewModel.likedTendersData = TestFixtures.likedTendersResponse;
|
||||
|
||||
viewModel.clearFilter();
|
||||
|
||||
expect(viewModel.currentPage, 1);
|
||||
expect(viewModel.data, null);
|
||||
expect(viewModel.likedTendersData, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tm_app/core/constants/assets.dart';
|
||||
import 'package:tm_app/core/constants/tender_approval_status.dart';
|
||||
import 'package:tm_app/core/constants/tender_feedback.dart';
|
||||
import 'package:tm_app/core/theme/colors.dart';
|
||||
import 'package:tm_app/view_models/your_tenders_view_model.dart';
|
||||
|
||||
import '../mocks/mock_your_tenders_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('YourTendersViewModel Utility Methods', () {
|
||||
late MockYourTendersRepository mockRepository;
|
||||
late YourTendersViewModel viewModel;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockYourTendersRepository();
|
||||
viewModel = YourTendersViewModel(yourTendersRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
viewModel.dispose();
|
||||
});
|
||||
|
||||
group('getBackGroundColorByStatus', () {
|
||||
test('should return green for liked status', () {
|
||||
final color = viewModel.getBackGroundColorByStatus(
|
||||
TenderFeedback.liked.value,
|
||||
);
|
||||
expect(color, AppColors.green0);
|
||||
});
|
||||
|
||||
test('should return green for submitted status', () {
|
||||
final color = viewModel.getBackGroundColorByStatus(
|
||||
TenderApprovalStatus.submitted.value,
|
||||
);
|
||||
expect(color, AppColors.green0);
|
||||
});
|
||||
|
||||
test('should return red for disliked status', () {
|
||||
final color = viewModel.getBackGroundColorByStatus(
|
||||
TenderFeedback.disliked.value,
|
||||
);
|
||||
expect(color, AppColors.red0);
|
||||
});
|
||||
|
||||
test('should return red for rejected status', () {
|
||||
final color = viewModel.getBackGroundColorByStatus(
|
||||
TenderApprovalStatus.rejected.value,
|
||||
);
|
||||
expect(color, AppColors.red0);
|
||||
});
|
||||
|
||||
test('should return grey for unknown status', () {
|
||||
final color = viewModel.getBackGroundColorByStatus('unknown');
|
||||
expect(color, AppColors.grey0);
|
||||
});
|
||||
});
|
||||
|
||||
group('getBorderColorByStatus', () {
|
||||
test('should return green for liked status', () {
|
||||
final color = viewModel.getBorderColorByStatus(
|
||||
TenderFeedback.liked.value,
|
||||
);
|
||||
expect(color, AppColors.green10);
|
||||
});
|
||||
|
||||
test('should return green for submitted status', () {
|
||||
final color = viewModel.getBorderColorByStatus(
|
||||
TenderApprovalStatus.submitted.value,
|
||||
);
|
||||
expect(color, AppColors.green10);
|
||||
});
|
||||
|
||||
test('should return red for disliked status', () {
|
||||
final color = viewModel.getBorderColorByStatus(
|
||||
TenderFeedback.disliked.value,
|
||||
);
|
||||
expect(color, AppColors.red10);
|
||||
});
|
||||
|
||||
test('should return red for rejected status', () {
|
||||
final color = viewModel.getBorderColorByStatus(
|
||||
TenderApprovalStatus.rejected.value,
|
||||
);
|
||||
expect(color, AppColors.red10);
|
||||
});
|
||||
|
||||
test('should return grey for unknown status', () {
|
||||
final color = viewModel.getBorderColorByStatus('unknown');
|
||||
expect(color, AppColors.grey30);
|
||||
});
|
||||
});
|
||||
|
||||
group('getStatusCardColorByStatus', () {
|
||||
test('should return green for liked status', () {
|
||||
final color = viewModel.getStatusCardColorByStatus(
|
||||
TenderFeedback.liked.value,
|
||||
);
|
||||
expect(color, AppColors.green20);
|
||||
});
|
||||
|
||||
test('should return green for submitted status', () {
|
||||
final color = viewModel.getStatusCardColorByStatus(
|
||||
TenderApprovalStatus.submitted.value,
|
||||
);
|
||||
expect(color, AppColors.green20);
|
||||
});
|
||||
|
||||
test('should return red for disliked status', () {
|
||||
final color = viewModel.getStatusCardColorByStatus(
|
||||
TenderFeedback.disliked.value,
|
||||
);
|
||||
expect(color, AppColors.red10);
|
||||
});
|
||||
|
||||
test('should return red for rejected status', () {
|
||||
final color = viewModel.getStatusCardColorByStatus(
|
||||
TenderApprovalStatus.rejected.value,
|
||||
);
|
||||
expect(color, AppColors.red10);
|
||||
});
|
||||
|
||||
test('should return grey for unknown status', () {
|
||||
final color = viewModel.getStatusCardColorByStatus('unknown');
|
||||
expect(color, AppColors.grey0);
|
||||
});
|
||||
});
|
||||
|
||||
group('getStatusTextColorByStatus', () {
|
||||
test('should return green for liked status', () {
|
||||
final color = viewModel.getStatusTextColorByStatus(
|
||||
TenderFeedback.liked.value,
|
||||
);
|
||||
expect(color, AppColors.green30);
|
||||
});
|
||||
|
||||
test('should return green for submitted status', () {
|
||||
final color = viewModel.getStatusTextColorByStatus(
|
||||
TenderApprovalStatus.submitted.value,
|
||||
);
|
||||
expect(color, AppColors.green30);
|
||||
});
|
||||
|
||||
test('should return red for disliked status', () {
|
||||
final color = viewModel.getStatusTextColorByStatus(
|
||||
TenderFeedback.disliked.value,
|
||||
);
|
||||
expect(color, AppColors.red20);
|
||||
});
|
||||
|
||||
test('should return red for rejected status', () {
|
||||
final color = viewModel.getStatusTextColorByStatus(
|
||||
TenderApprovalStatus.rejected.value,
|
||||
);
|
||||
expect(color, AppColors.red20);
|
||||
});
|
||||
|
||||
test('should return grey for unknown status', () {
|
||||
final color = viewModel.getStatusTextColorByStatus('unknown');
|
||||
expect(color, AppColors.grey60);
|
||||
});
|
||||
});
|
||||
|
||||
group('getStatusIconByStatus', () {
|
||||
test('should return tick circle for liked status', () {
|
||||
final icon = viewModel.getStatusIconByStatus(
|
||||
TenderFeedback.liked.value,
|
||||
);
|
||||
expect(icon, AssetsManager.tickCircle);
|
||||
});
|
||||
|
||||
test('should return tick circle for submitted status', () {
|
||||
final icon = viewModel.getStatusIconByStatus(
|
||||
TenderApprovalStatus.submitted.value,
|
||||
);
|
||||
expect(icon, AssetsManager.tickCircle);
|
||||
});
|
||||
|
||||
test('should return close circle for disliked status', () {
|
||||
final icon = viewModel.getStatusIconByStatus(
|
||||
TenderFeedback.disliked.value,
|
||||
);
|
||||
expect(icon, AssetsManager.closeCircle);
|
||||
});
|
||||
|
||||
test('should return close circle for rejected status', () {
|
||||
final icon = viewModel.getStatusIconByStatus(
|
||||
TenderApprovalStatus.rejected.value,
|
||||
);
|
||||
expect(icon, AssetsManager.closeCircle);
|
||||
});
|
||||
|
||||
test('should return null for unknown status', () {
|
||||
final icon = viewModel.getStatusIconByStatus('unknown');
|
||||
expect(icon, null);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user