fix: auth token handling, add tests
- Read bearer token from set-auth-token header - Add mounted checks to prevent setState after dispose - Add mocktail for testing - Add widget tests for login, clients, events screens - Add unit tests for auth provider, API client - 110 tests passing
This commit is contained in:
183
test/features/auth/login_screen_test.dart
Normal file
183
test/features/auth/login_screen_test.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:network_app/features/auth/presentation/login_screen.dart';
|
||||
import 'package:network_app/shared/providers/auth_provider.dart';
|
||||
import 'package:network_app/shared/services/api_client.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockApiClient extends Mock implements ApiClient {}
|
||||
|
||||
void main() {
|
||||
late MockApiClient mockApiClient;
|
||||
|
||||
setUp(() {
|
||||
mockApiClient = MockApiClient();
|
||||
});
|
||||
|
||||
Widget createTestWidget() {
|
||||
return ProviderScope(
|
||||
overrides: [
|
||||
apiClientProvider.overrideWithValue(mockApiClient),
|
||||
],
|
||||
child: MaterialApp(
|
||||
home: const LoginScreen(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
group('LoginScreen Widget Tests', () {
|
||||
testWidgets('renders login form', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Network App'), findsOneWidget);
|
||||
expect(find.text('Sign in to your account'), findsOneWidget);
|
||||
expect(find.byType(TextFormField), findsNWidgets(2));
|
||||
expect(find.text('Sign In'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('shows email field', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.widgetWithText(TextFormField, 'Email'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('shows password field', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.widgetWithText(TextFormField, 'Password'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('validates empty email', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Enter only password
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Password'),
|
||||
'password123',
|
||||
);
|
||||
|
||||
// Tap sign in
|
||||
await tester.tap(find.text('Sign In'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter your email'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('validates invalid email format', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Email'),
|
||||
'notanemail',
|
||||
);
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Password'),
|
||||
'password123',
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Sign In'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter a valid email'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('validates empty password', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Email'),
|
||||
'test@test.com',
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Sign In'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter your password'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('shows loading indicator when signing in', (tester) async {
|
||||
final completer = Completer<Map<String, dynamic>>();
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
when(() => mockApiClient.signIn(
|
||||
email: any(named: 'email'),
|
||||
password: any(named: 'password'),
|
||||
)).thenAnswer((_) => completer.future);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Email'),
|
||||
'test@test.com',
|
||||
);
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Password'),
|
||||
'password123',
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Sign In'));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(CircularProgressIndicator), findsOneWidget);
|
||||
|
||||
// Complete to cleanup
|
||||
completer.complete({'user': {'id': '1', 'email': 'test@test.com'}});
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('shows sign up link', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text("Don't have an account?"), findsOneWidget);
|
||||
expect(find.text('Sign Up'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('shows error message on failed login', (tester) async {
|
||||
when(() => mockApiClient.getSession()).thenAnswer((_) async => null);
|
||||
when(() => mockApiClient.signIn(
|
||||
email: any(named: 'email'),
|
||||
password: any(named: 'password'),
|
||||
)).thenThrow(Exception('Invalid credentials'));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Email'),
|
||||
'test@test.com',
|
||||
);
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Password'),
|
||||
'wrongpassword',
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Sign In'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Invalid email or password'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user