at main 11 kB view raw
1import 'package:coves_flutter/models/community.dart'; 2import 'package:coves_flutter/providers/auth_provider.dart'; 3import 'package:coves_flutter/screens/home/create_post_screen.dart'; 4import 'package:flutter/material.dart'; 5import 'package:flutter_test/flutter_test.dart'; 6import 'package:provider/provider.dart'; 7 8// Fake AuthProvider for testing 9class FakeAuthProvider extends AuthProvider { 10 bool _isAuthenticated = true; 11 String? _did = 'did:plc:testuser'; 12 String? _handle = 'testuser.coves.social'; 13 14 @override 15 bool get isAuthenticated => _isAuthenticated; 16 17 @override 18 String? get did => _did; 19 20 @override 21 String? get handle => _handle; 22 23 void setAuthenticated({required bool value, String? did, String? handle}) { 24 _isAuthenticated = value; 25 _did = did; 26 _handle = handle; 27 notifyListeners(); 28 } 29 30 @override 31 Future<String?> getAccessToken() async { 32 return _isAuthenticated ? 'mock_access_token' : null; 33 } 34 35 @override 36 Future<bool> refreshToken() async { 37 return _isAuthenticated; 38 } 39 40 @override 41 Future<void> signOut() async { 42 _isAuthenticated = false; 43 _did = null; 44 _handle = null; 45 notifyListeners(); 46 } 47} 48 49void main() { 50 group('CreatePostScreen Widget Tests', () { 51 late FakeAuthProvider fakeAuthProvider; 52 53 setUp(() { 54 fakeAuthProvider = FakeAuthProvider(); 55 }); 56 57 Widget createTestWidget({VoidCallback? onNavigateToFeed}) { 58 return MultiProvider( 59 providers: [ 60 ChangeNotifierProvider<AuthProvider>.value(value: fakeAuthProvider), 61 ], 62 child: MaterialApp( 63 home: CreatePostScreen(onNavigateToFeed: onNavigateToFeed), 64 ), 65 ); 66 } 67 68 testWidgets('should display Create Post title', (tester) async { 69 await tester.pumpWidget(createTestWidget()); 70 await tester.pumpAndSettle(); 71 72 expect(find.text('Create Post'), findsOneWidget); 73 }); 74 75 testWidgets('should display user handle', (tester) async { 76 await tester.pumpWidget(createTestWidget()); 77 await tester.pumpAndSettle(); 78 79 expect(find.text('@testuser.coves.social'), findsOneWidget); 80 }); 81 82 testWidgets('should display community selector', (tester) async { 83 await tester.pumpWidget(createTestWidget()); 84 await tester.pumpAndSettle(); 85 86 expect(find.text('Select a community'), findsOneWidget); 87 }); 88 89 testWidgets('should display title field', (tester) async { 90 await tester.pumpWidget(createTestWidget()); 91 await tester.pumpAndSettle(); 92 93 expect(find.widgetWithText(TextField, 'Title'), findsOneWidget); 94 }); 95 96 testWidgets('should display URL field', (tester) async { 97 await tester.pumpWidget(createTestWidget()); 98 await tester.pumpAndSettle(); 99 100 expect(find.widgetWithText(TextField, 'URL'), findsOneWidget); 101 }); 102 103 testWidgets('should display body field', (tester) async { 104 await tester.pumpWidget(createTestWidget()); 105 await tester.pumpAndSettle(); 106 107 expect( 108 find.widgetWithText(TextField, 'What are your thoughts?'), 109 findsOneWidget, 110 ); 111 }); 112 113 testWidgets('should display language dropdown', (tester) async { 114 await tester.pumpWidget(createTestWidget()); 115 await tester.pumpAndSettle(); 116 117 // Default language should be English 118 expect(find.text('English'), findsOneWidget); 119 }); 120 121 testWidgets('should display NSFW toggle', (tester) async { 122 await tester.pumpWidget(createTestWidget()); 123 await tester.pumpAndSettle(); 124 125 expect(find.text('NSFW'), findsOneWidget); 126 expect(find.byType(Switch), findsOneWidget); 127 }); 128 129 testWidgets('should have disabled Post button initially', (tester) async { 130 await tester.pumpWidget(createTestWidget()); 131 await tester.pumpAndSettle(); 132 133 // Find the Post button 134 final postButton = find.widgetWithText(TextButton, 'Post'); 135 expect(postButton, findsOneWidget); 136 137 // Button should be disabled (no community selected, no content) 138 final button = tester.widget<TextButton>(postButton); 139 expect(button.onPressed, isNull); 140 }); 141 142 testWidgets('should enable Post button when title is entered and community selected', (tester) async { 143 await tester.pumpWidget(createTestWidget()); 144 await tester.pumpAndSettle(); 145 146 // Enter a title 147 await tester.enterText(find.widgetWithText(TextField, 'Title'), 'Test Post'); 148 await tester.pumpAndSettle(); 149 150 // Post button should still be disabled (no community selected) 151 final postButton = find.widgetWithText(TextButton, 'Post'); 152 final button = tester.widget<TextButton>(postButton); 153 expect(button.onPressed, isNull); 154 }); 155 156 testWidgets('should toggle NSFW switch', (tester) async { 157 await tester.pumpWidget(createTestWidget()); 158 await tester.pumpAndSettle(); 159 160 // Find the switch 161 final switchWidget = find.byType(Switch); 162 expect(switchWidget, findsOneWidget); 163 164 // Initially should be off 165 Switch switchBefore = tester.widget<Switch>(switchWidget); 166 expect(switchBefore.value, false); 167 168 // Scroll to make switch visible, then tap 169 await tester.ensureVisible(switchWidget); 170 await tester.pumpAndSettle(); 171 await tester.tap(switchWidget); 172 await tester.pumpAndSettle(); 173 174 // Should be on now 175 Switch switchAfter = tester.widget<Switch>(switchWidget); 176 expect(switchAfter.value, true); 177 }); 178 179 testWidgets('should show thumbnail field when URL is entered', (tester) async { 180 await tester.pumpWidget(createTestWidget()); 181 await tester.pumpAndSettle(); 182 183 // Initially no thumbnail field 184 expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsNothing); 185 186 // Enter a URL 187 await tester.enterText( 188 find.widgetWithText(TextField, 'URL'), 189 'https://example.com', 190 ); 191 await tester.pumpAndSettle(); 192 193 // Thumbnail field should now be visible 194 expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsOneWidget); 195 }); 196 197 testWidgets('should hide thumbnail field when URL is cleared', (tester) async { 198 await tester.pumpWidget(createTestWidget()); 199 await tester.pumpAndSettle(); 200 201 // Enter a URL 202 final urlField = find.widgetWithText(TextField, 'URL'); 203 await tester.enterText(urlField, 'https://example.com'); 204 await tester.pumpAndSettle(); 205 206 // Thumbnail field should be visible 207 expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsOneWidget); 208 209 // Clear the URL 210 await tester.enterText(urlField, ''); 211 await tester.pumpAndSettle(); 212 213 // Thumbnail field should be hidden 214 expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsNothing); 215 }); 216 217 testWidgets('should display close button', (tester) async { 218 await tester.pumpWidget(createTestWidget()); 219 await tester.pumpAndSettle(); 220 221 expect(find.byIcon(Icons.close), findsOneWidget); 222 }); 223 224 testWidgets('should call onNavigateToFeed when close button is tapped', (tester) async { 225 bool callbackCalled = false; 226 227 await tester.pumpWidget( 228 createTestWidget(onNavigateToFeed: () => callbackCalled = true), 229 ); 230 await tester.pumpAndSettle(); 231 232 await tester.tap(find.byIcon(Icons.close)); 233 await tester.pumpAndSettle(); 234 235 expect(callbackCalled, true); 236 }); 237 238 testWidgets('should have character limit on title field', (tester) async { 239 await tester.pumpWidget(createTestWidget()); 240 await tester.pumpAndSettle(); 241 242 // Find the title TextField 243 final titleField = find.widgetWithText(TextField, 'Title'); 244 final textField = tester.widget<TextField>(titleField); 245 246 // Should have maxLength set to 300 (kTitleMaxLength) 247 expect(textField.maxLength, 300); 248 }); 249 250 testWidgets('should have character limit on body field', (tester) async { 251 await tester.pumpWidget(createTestWidget()); 252 await tester.pumpAndSettle(); 253 254 // Find the body TextField 255 final bodyField = find.widgetWithText(TextField, 'What are your thoughts?'); 256 final textField = tester.widget<TextField>(bodyField); 257 258 // Should have maxLength set to 10000 (kContentMaxLength) 259 expect(textField.maxLength, 10000); 260 }); 261 262 testWidgets('should be scrollable', (tester) async { 263 await tester.pumpWidget(createTestWidget()); 264 await tester.pumpAndSettle(); 265 266 // Should have a SingleChildScrollView 267 expect(find.byType(SingleChildScrollView), findsOneWidget); 268 }); 269 }); 270 271 group('CreatePostScreen Form Validation', () { 272 late FakeAuthProvider fakeAuthProvider; 273 274 setUp(() { 275 fakeAuthProvider = FakeAuthProvider(); 276 }); 277 278 Widget createTestWidget() { 279 return MultiProvider( 280 providers: [ 281 ChangeNotifierProvider<AuthProvider>.value(value: fakeAuthProvider), 282 ], 283 child: const MaterialApp(home: CreatePostScreen()), 284 ); 285 } 286 287 testWidgets('form is invalid with no community and no content', (tester) async { 288 await tester.pumpWidget(createTestWidget()); 289 await tester.pumpAndSettle(); 290 291 final postButton = find.widgetWithText(TextButton, 'Post'); 292 final button = tester.widget<TextButton>(postButton); 293 expect(button.onPressed, isNull); 294 }); 295 296 testWidgets('form is invalid with content but no community', (tester) async { 297 await tester.pumpWidget(createTestWidget()); 298 await tester.pumpAndSettle(); 299 300 // Enter title 301 await tester.enterText(find.widgetWithText(TextField, 'Title'), 'Test'); 302 await tester.pumpAndSettle(); 303 304 final postButton = find.widgetWithText(TextButton, 'Post'); 305 final button = tester.widget<TextButton>(postButton); 306 expect(button.onPressed, isNull); 307 }); 308 309 testWidgets('entering text updates form state', (tester) async { 310 await tester.pumpWidget(createTestWidget()); 311 await tester.pumpAndSettle(); 312 313 // Enter title 314 await tester.enterText( 315 find.widgetWithText(TextField, 'Title'), 316 'My Test Post', 317 ); 318 await tester.pumpAndSettle(); 319 320 // Verify text was entered 321 expect(find.text('My Test Post'), findsOneWidget); 322 }); 323 324 testWidgets('entering body text updates form state', (tester) async { 325 await tester.pumpWidget(createTestWidget()); 326 await tester.pumpAndSettle(); 327 328 // Enter body 329 await tester.enterText( 330 find.widgetWithText(TextField, 'What are your thoughts?'), 331 'This is my post content', 332 ); 333 await tester.pumpAndSettle(); 334 335 // Verify text was entered 336 expect(find.text('This is my post content'), findsOneWidget); 337 }); 338 }); 339}