···
1
+
import 'package:coves_flutter/models/community.dart';
2
+
import 'package:coves_flutter/providers/auth_provider.dart';
3
+
import 'package:coves_flutter/screens/home/create_post_screen.dart';
4
+
import 'package:flutter/material.dart';
5
+
import 'package:flutter_test/flutter_test.dart';
6
+
import 'package:provider/provider.dart';
8
+
// Fake AuthProvider for testing
9
+
class FakeAuthProvider extends AuthProvider {
10
+
bool _isAuthenticated = true;
11
+
String? _did = 'did:plc:testuser';
12
+
String? _handle = 'testuser.coves.social';
15
+
bool get isAuthenticated => _isAuthenticated;
18
+
String? get did => _did;
21
+
String? get handle => _handle;
23
+
void setAuthenticated({required bool value, String? did, String? handle}) {
24
+
_isAuthenticated = value;
31
+
Future<String?> getAccessToken() async {
32
+
return _isAuthenticated ? 'mock_access_token' : null;
36
+
Future<bool> refreshToken() async {
37
+
return _isAuthenticated;
41
+
Future<void> signOut() async {
42
+
_isAuthenticated = false;
50
+
group('CreatePostScreen Widget Tests', () {
51
+
late FakeAuthProvider fakeAuthProvider;
54
+
fakeAuthProvider = FakeAuthProvider();
57
+
Widget createTestWidget({VoidCallback? onNavigateToFeed}) {
58
+
return MultiProvider(
60
+
ChangeNotifierProvider<AuthProvider>.value(value: fakeAuthProvider),
63
+
home: CreatePostScreen(onNavigateToFeed: onNavigateToFeed),
68
+
testWidgets('should display Create Post title', (tester) async {
69
+
await tester.pumpWidget(createTestWidget());
70
+
await tester.pumpAndSettle();
72
+
expect(find.text('Create Post'), findsOneWidget);
75
+
testWidgets('should display user handle', (tester) async {
76
+
await tester.pumpWidget(createTestWidget());
77
+
await tester.pumpAndSettle();
79
+
expect(find.text('@testuser.coves.social'), findsOneWidget);
82
+
testWidgets('should display community selector', (tester) async {
83
+
await tester.pumpWidget(createTestWidget());
84
+
await tester.pumpAndSettle();
86
+
expect(find.text('Select a community'), findsOneWidget);
89
+
testWidgets('should display title field', (tester) async {
90
+
await tester.pumpWidget(createTestWidget());
91
+
await tester.pumpAndSettle();
93
+
expect(find.widgetWithText(TextField, 'Title'), findsOneWidget);
96
+
testWidgets('should display URL field', (tester) async {
97
+
await tester.pumpWidget(createTestWidget());
98
+
await tester.pumpAndSettle();
100
+
expect(find.widgetWithText(TextField, 'URL'), findsOneWidget);
103
+
testWidgets('should display body field', (tester) async {
104
+
await tester.pumpWidget(createTestWidget());
105
+
await tester.pumpAndSettle();
108
+
find.widgetWithText(TextField, 'What are your thoughts?'),
113
+
testWidgets('should display language dropdown', (tester) async {
114
+
await tester.pumpWidget(createTestWidget());
115
+
await tester.pumpAndSettle();
117
+
// Default language should be English
118
+
expect(find.text('English'), findsOneWidget);
121
+
testWidgets('should display NSFW toggle', (tester) async {
122
+
await tester.pumpWidget(createTestWidget());
123
+
await tester.pumpAndSettle();
125
+
expect(find.text('NSFW'), findsOneWidget);
126
+
expect(find.byType(Switch), findsOneWidget);
129
+
testWidgets('should have disabled Post button initially', (tester) async {
130
+
await tester.pumpWidget(createTestWidget());
131
+
await tester.pumpAndSettle();
133
+
// Find the Post button
134
+
final postButton = find.widgetWithText(TextButton, 'Post');
135
+
expect(postButton, findsOneWidget);
137
+
// Button should be disabled (no community selected, no content)
138
+
final button = tester.widget<TextButton>(postButton);
139
+
expect(button.onPressed, isNull);
142
+
testWidgets('should enable Post button when title is entered and community selected', (tester) async {
143
+
await tester.pumpWidget(createTestWidget());
144
+
await tester.pumpAndSettle();
147
+
await tester.enterText(find.widgetWithText(TextField, 'Title'), 'Test Post');
148
+
await tester.pumpAndSettle();
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);
156
+
testWidgets('should toggle NSFW switch', (tester) async {
157
+
await tester.pumpWidget(createTestWidget());
158
+
await tester.pumpAndSettle();
161
+
final switchWidget = find.byType(Switch);
162
+
expect(switchWidget, findsOneWidget);
164
+
// Initially should be off
165
+
Switch switchBefore = tester.widget<Switch>(switchWidget);
166
+
expect(switchBefore.value, false);
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();
174
+
// Should be on now
175
+
Switch switchAfter = tester.widget<Switch>(switchWidget);
176
+
expect(switchAfter.value, true);
179
+
testWidgets('should show thumbnail field when URL is entered', (tester) async {
180
+
await tester.pumpWidget(createTestWidget());
181
+
await tester.pumpAndSettle();
183
+
// Initially no thumbnail field
184
+
expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsNothing);
187
+
await tester.enterText(
188
+
find.widgetWithText(TextField, 'URL'),
189
+
'https://example.com',
191
+
await tester.pumpAndSettle();
193
+
// Thumbnail field should now be visible
194
+
expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsOneWidget);
197
+
testWidgets('should hide thumbnail field when URL is cleared', (tester) async {
198
+
await tester.pumpWidget(createTestWidget());
199
+
await tester.pumpAndSettle();
202
+
final urlField = find.widgetWithText(TextField, 'URL');
203
+
await tester.enterText(urlField, 'https://example.com');
204
+
await tester.pumpAndSettle();
206
+
// Thumbnail field should be visible
207
+
expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsOneWidget);
210
+
await tester.enterText(urlField, '');
211
+
await tester.pumpAndSettle();
213
+
// Thumbnail field should be hidden
214
+
expect(find.widgetWithText(TextField, 'Thumbnail URL'), findsNothing);
217
+
testWidgets('should display close button', (tester) async {
218
+
await tester.pumpWidget(createTestWidget());
219
+
await tester.pumpAndSettle();
221
+
expect(find.byIcon(Icons.close), findsOneWidget);
224
+
testWidgets('should call onNavigateToFeed when close button is tapped', (tester) async {
225
+
bool callbackCalled = false;
227
+
await tester.pumpWidget(
228
+
createTestWidget(onNavigateToFeed: () => callbackCalled = true),
230
+
await tester.pumpAndSettle();
232
+
await tester.tap(find.byIcon(Icons.close));
233
+
await tester.pumpAndSettle();
235
+
expect(callbackCalled, true);
238
+
testWidgets('should have character limit on title field', (tester) async {
239
+
await tester.pumpWidget(createTestWidget());
240
+
await tester.pumpAndSettle();
242
+
// Find the title TextField
243
+
final titleField = find.widgetWithText(TextField, 'Title');
244
+
final textField = tester.widget<TextField>(titleField);
246
+
// Should have maxLength set to 300 (kTitleMaxLength)
247
+
expect(textField.maxLength, 300);
250
+
testWidgets('should have character limit on body field', (tester) async {
251
+
await tester.pumpWidget(createTestWidget());
252
+
await tester.pumpAndSettle();
254
+
// Find the body TextField
255
+
final bodyField = find.widgetWithText(TextField, 'What are your thoughts?');
256
+
final textField = tester.widget<TextField>(bodyField);
258
+
// Should have maxLength set to 10000 (kContentMaxLength)
259
+
expect(textField.maxLength, 10000);
262
+
testWidgets('should be scrollable', (tester) async {
263
+
await tester.pumpWidget(createTestWidget());
264
+
await tester.pumpAndSettle();
266
+
// Should have a SingleChildScrollView
267
+
expect(find.byType(SingleChildScrollView), findsOneWidget);
271
+
group('CreatePostScreen Form Validation', () {
272
+
late FakeAuthProvider fakeAuthProvider;
275
+
fakeAuthProvider = FakeAuthProvider();
278
+
Widget createTestWidget() {
279
+
return MultiProvider(
281
+
ChangeNotifierProvider<AuthProvider>.value(value: fakeAuthProvider),
283
+
child: const MaterialApp(home: CreatePostScreen()),
287
+
testWidgets('form is invalid with no community and no content', (tester) async {
288
+
await tester.pumpWidget(createTestWidget());
289
+
await tester.pumpAndSettle();
291
+
final postButton = find.widgetWithText(TextButton, 'Post');
292
+
final button = tester.widget<TextButton>(postButton);
293
+
expect(button.onPressed, isNull);
296
+
testWidgets('form is invalid with content but no community', (tester) async {
297
+
await tester.pumpWidget(createTestWidget());
298
+
await tester.pumpAndSettle();
301
+
await tester.enterText(find.widgetWithText(TextField, 'Title'), 'Test');
302
+
await tester.pumpAndSettle();
304
+
final postButton = find.widgetWithText(TextButton, 'Post');
305
+
final button = tester.widget<TextButton>(postButton);
306
+
expect(button.onPressed, isNull);
309
+
testWidgets('entering text updates form state', (tester) async {
310
+
await tester.pumpWidget(createTestWidget());
311
+
await tester.pumpAndSettle();
314
+
await tester.enterText(
315
+
find.widgetWithText(TextField, 'Title'),
318
+
await tester.pumpAndSettle();
320
+
// Verify text was entered
321
+
expect(find.text('My Test Post'), findsOneWidget);
324
+
testWidgets('entering body text updates form state', (tester) async {
325
+
await tester.pumpWidget(createTestWidget());
326
+
await tester.pumpAndSettle();
329
+
await tester.enterText(
330
+
find.widgetWithText(TextField, 'What are your thoughts?'),
331
+
'This is my post content',
333
+
await tester.pumpAndSettle();
335
+
// Verify text was entered
336
+
expect(find.text('This is my post content'), findsOneWidget);