+4
-4
justfile
+4
-4
justfile
···
7
7
flutter analyze
8
8
9
9
# Test with failures only to focus on failures and hanging tests
10
-
test-quiet:
11
-
flutter test --reporter=failures-only --timeout=90s
10
+
test-quiet *paths='':
11
+
flutter test {{ paths }} --reporter=failures-only --timeout=90s
12
12
13
13
# Run all tests
14
-
test:
15
-
flutter test --timeout=90s
14
+
test *paths='':
15
+
flutter test {{ paths }} --timeout=90s
16
16
17
17
# Run code gen
18
18
gen:
+66
lib/src/app/router.dart
+66
lib/src/app/router.dart
···
136
136
state: state,
137
137
controller: animationController,
138
138
),
139
+
routes: [
140
+
GoRoute(
141
+
path: 'followers',
142
+
name: '${AppRouteNames.home}_${AppRouteNames.followers}',
143
+
pageBuilder: (context, state) => LazuritePageTransitions.build(
144
+
child: FollowersPage(did: Uri.decodeComponent(state.pathParameters['did']!)),
145
+
type: LazuriteTransitionType.sharedAxisHorizontal,
146
+
state: state,
147
+
controller: animationController,
148
+
),
149
+
),
150
+
GoRoute(
151
+
path: 'following',
152
+
name: '${AppRouteNames.home}_${AppRouteNames.following}',
153
+
pageBuilder: (context, state) => LazuritePageTransitions.build(
154
+
child: FollowingPage(did: Uri.decodeComponent(state.pathParameters['did']!)),
155
+
type: LazuriteTransitionType.sharedAxisHorizontal,
156
+
state: state,
157
+
controller: animationController,
158
+
),
159
+
),
160
+
],
139
161
),
140
162
],
141
163
),
···
176
198
state: state,
177
199
controller: animationController,
178
200
),
201
+
routes: [
202
+
GoRoute(
203
+
path: 'followers',
204
+
name: '${AppRouteNames.search}_${AppRouteNames.followers}',
205
+
pageBuilder: (context, state) => LazuritePageTransitions.build(
206
+
child: FollowersPage(did: Uri.decodeComponent(state.pathParameters['did']!)),
207
+
type: LazuriteTransitionType.sharedAxisHorizontal,
208
+
state: state,
209
+
controller: animationController,
210
+
),
211
+
),
212
+
GoRoute(
213
+
path: 'following',
214
+
name: '${AppRouteNames.search}_${AppRouteNames.following}',
215
+
pageBuilder: (context, state) => LazuritePageTransitions.build(
216
+
child: FollowingPage(did: Uri.decodeComponent(state.pathParameters['did']!)),
217
+
type: LazuriteTransitionType.sharedAxisHorizontal,
218
+
state: state,
219
+
controller: animationController,
220
+
),
221
+
),
222
+
],
179
223
),
180
224
],
181
225
),
···
209
253
state: state,
210
254
controller: animationController,
211
255
),
256
+
routes: [
257
+
GoRoute(
258
+
path: 'followers',
259
+
name: '${AppRouteNames.notifications}_${AppRouteNames.followers}',
260
+
pageBuilder: (context, state) => LazuritePageTransitions.build(
261
+
child: FollowersPage(did: Uri.decodeComponent(state.pathParameters['did']!)),
262
+
type: LazuriteTransitionType.sharedAxisHorizontal,
263
+
state: state,
264
+
controller: animationController,
265
+
),
266
+
),
267
+
GoRoute(
268
+
path: 'following',
269
+
name: '${AppRouteNames.notifications}_${AppRouteNames.following}',
270
+
pageBuilder: (context, state) => LazuritePageTransitions.build(
271
+
child: FollowingPage(did: Uri.decodeComponent(state.pathParameters['did']!)),
272
+
type: LazuriteTransitionType.sharedAxisHorizontal,
273
+
state: state,
274
+
controller: animationController,
275
+
),
276
+
),
277
+
],
212
278
),
213
279
],
214
280
),
+24
-2
lib/src/features/profile/presentation/profile_screen.dart
+24
-2
lib/src/features/profile/presentation/profile_screen.dart
···
189
189
profile: profile,
190
190
onFollowersPressed: () {
191
191
final encodedDid = Uri.encodeComponent(profile.did);
192
-
context.push('/profile/followers/$encodedDid');
192
+
if (widget.isCurrentUser) {
193
+
context.push('/profile/followers/$encodedDid');
194
+
} else {
195
+
final currentLocation = GoRouter.of(context).routerDelegate.currentConfiguration.uri.path;
196
+
String basePath = AppRoutes.home;
197
+
if (currentLocation.startsWith(AppRoutes.search)) {
198
+
basePath = AppRoutes.search;
199
+
} else if (currentLocation.startsWith(AppRoutes.notifications)) {
200
+
basePath = AppRoutes.notifications;
201
+
}
202
+
context.push('$basePath/u/$encodedDid/followers');
203
+
}
193
204
},
194
205
onFollowingPressed: () {
195
206
final encodedDid = Uri.encodeComponent(profile.did);
196
-
context.push('/profile/following/$encodedDid');
207
+
if (widget.isCurrentUser) {
208
+
context.push('/profile/following/$encodedDid');
209
+
} else {
210
+
final currentLocation = GoRouter.of(context).routerDelegate.currentConfiguration.uri.path;
211
+
String basePath = AppRoutes.home;
212
+
if (currentLocation.startsWith(AppRoutes.search)) {
213
+
basePath = AppRoutes.search;
214
+
} else if (currentLocation.startsWith(AppRoutes.notifications)) {
215
+
basePath = AppRoutes.notifications;
216
+
}
217
+
context.push('$basePath/u/$encodedDid/following');
218
+
}
197
219
},
198
220
followButton: widget.isCurrentUser ? null : _followButton(profile),
199
221
),
+2
-1
lib/src/features/search/presentation/search_screen.dart
+2
-1
lib/src/features/search/presentation/search_screen.dart
···
483
483
484
484
return InkWell(
485
485
onTap: () {
486
-
GoRouter.of(context).push('/profile/${actor.did}');
486
+
final encodedDid = Uri.encodeComponent(actor.did);
487
+
GoRouter.of(context).push('/search/u/$encodedDid');
487
488
},
488
489
child: Padding(
489
490
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
+165
test/src/app/router_test.dart
+165
test/src/app/router_test.dart
···
26
26
import 'package:lazurite/src/features/notifications/application/notifications_providers.dart';
27
27
import 'package:lazurite/src/features/profile/application/profile_providers.dart';
28
28
import 'package:lazurite/src/features/profile/infrastructure/profile_repository.dart';
29
+
import 'package:lazurite/src/features/profile/presentation/followers_page.dart';
30
+
import 'package:lazurite/src/features/profile/presentation/following_page.dart';
31
+
import 'package:lazurite/src/features/profile/presentation/profile_screen.dart';
29
32
import 'package:lazurite/src/features/search/application/search_providers.dart';
30
33
import 'package:lazurite/src/features/settings/domain/animation_preferences.dart';
31
34
import 'package:lazurite/src/features/splash/presentation/splash_screen.dart';
···
352
355
await tester.pumpAndSettle();
353
356
354
357
expect(find.byType(DevToolsHomePage), findsOneWidget);
358
+
});
359
+
360
+
group('Profile detail routing regression', () {
361
+
testWidgets('navigates to profile detail from search tab', (tester) async {
362
+
await tester.pumpRouterApp(
363
+
overrides: [
364
+
...getTestOverrides(),
365
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
366
+
],
367
+
);
368
+
369
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
370
+
final router = app.routerConfig as GoRouter;
371
+
372
+
final encodedDid = Uri.encodeComponent('did:plc:test123');
373
+
unawaited(router.push('/search/u/$encodedDid'));
374
+
await tester.pumpAndSettle();
375
+
376
+
expect(find.byType(ProfilePage), findsOneWidget);
377
+
final profilePage = tester.widget<ProfilePage>(find.byType(ProfilePage));
378
+
expect(profilePage.did, 'did:plc:test123');
379
+
});
380
+
381
+
testWidgets('navigates to profile detail from home tab', (tester) async {
382
+
await tester.pumpRouterApp(
383
+
overrides: [
384
+
...getTestOverrides(),
385
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
386
+
],
387
+
);
388
+
389
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
390
+
final router = app.routerConfig as GoRouter;
391
+
392
+
final encodedDid = Uri.encodeComponent('did:plc:test456');
393
+
unawaited(router.push('/home/u/$encodedDid'));
394
+
await tester.pumpAndSettle();
395
+
396
+
expect(find.byType(ProfilePage), findsOneWidget);
397
+
final profilePage = tester.widget<ProfilePage>(find.byType(ProfilePage));
398
+
expect(profilePage.did, 'did:plc:test456');
399
+
});
400
+
401
+
testWidgets('navigates to profile detail from notifications tab', (tester) async {
402
+
await tester.pumpRouterApp(
403
+
overrides: [
404
+
...getTestOverrides(),
405
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
406
+
],
407
+
);
408
+
409
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
410
+
final router = app.routerConfig as GoRouter;
411
+
412
+
final encodedDid = Uri.encodeComponent('did:plc:test789');
413
+
unawaited(router.push('/notifications/u/$encodedDid'));
414
+
await tester.pumpAndSettle();
415
+
416
+
expect(find.byType(ProfilePage), findsOneWidget);
417
+
final profilePage = tester.widget<ProfilePage>(find.byType(ProfilePage));
418
+
expect(profilePage.did, 'did:plc:test789');
419
+
});
420
+
421
+
testWidgets('navigates to followers from search profile detail', (tester) async {
422
+
await tester.pumpRouterApp(
423
+
overrides: [
424
+
...getTestOverrides(),
425
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
426
+
],
427
+
);
428
+
429
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
430
+
final router = app.routerConfig as GoRouter;
431
+
432
+
final encodedDid = Uri.encodeComponent('did:plc:testfollowers');
433
+
unawaited(router.push('/search/u/$encodedDid/followers'));
434
+
await tester.pumpAndSettle();
435
+
436
+
expect(find.byType(FollowersPage), findsOneWidget);
437
+
final followersPage = tester.widget<FollowersPage>(find.byType(FollowersPage));
438
+
expect(followersPage.did, 'did:plc:testfollowers');
439
+
});
440
+
441
+
testWidgets('navigates to following from home profile detail', (tester) async {
442
+
await tester.pumpRouterApp(
443
+
overrides: [
444
+
...getTestOverrides(),
445
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
446
+
],
447
+
);
448
+
449
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
450
+
final router = app.routerConfig as GoRouter;
451
+
452
+
final encodedDid = Uri.encodeComponent('did:plc:testfollowing');
453
+
unawaited(router.push('/home/u/$encodedDid/following'));
454
+
await tester.pumpAndSettle();
455
+
456
+
expect(find.byType(FollowingPage), findsOneWidget);
457
+
final followingPage = tester.widget<FollowingPage>(find.byType(FollowingPage));
458
+
expect(followingPage.did, 'did:plc:testfollowing');
459
+
});
460
+
461
+
testWidgets('navigates to followers from notifications profile detail', (tester) async {
462
+
await tester.pumpRouterApp(
463
+
overrides: [
464
+
...getTestOverrides(),
465
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
466
+
],
467
+
);
468
+
469
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
470
+
final router = app.routerConfig as GoRouter;
471
+
472
+
final encodedDid = Uri.encodeComponent('did:plc:notiffollowers');
473
+
unawaited(router.push('/notifications/u/$encodedDid/followers'));
474
+
await tester.pumpAndSettle();
475
+
476
+
expect(find.byType(FollowersPage), findsOneWidget);
477
+
final followersPage = tester.widget<FollowersPage>(find.byType(FollowersPage));
478
+
expect(followersPage.did, 'did:plc:notiffollowers');
479
+
});
480
+
481
+
testWidgets('navigates to followers from current user profile', (tester) async {
482
+
await tester.pumpRouterApp(
483
+
overrides: [
484
+
...getTestOverrides(),
485
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
486
+
],
487
+
);
488
+
489
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
490
+
final router = app.routerConfig as GoRouter;
491
+
492
+
final encodedDid = Uri.encodeComponent(testSession.did);
493
+
unawaited(router.push('/profile/followers/$encodedDid'));
494
+
await tester.pumpAndSettle();
495
+
496
+
expect(find.byType(FollowersPage), findsOneWidget);
497
+
final followersPage = tester.widget<FollowersPage>(find.byType(FollowersPage));
498
+
expect(followersPage.did, testSession.did);
499
+
});
500
+
501
+
testWidgets('navigates to following from current user profile', (tester) async {
502
+
await tester.pumpRouterApp(
503
+
overrides: [
504
+
...getTestOverrides(),
505
+
authProvider.overrideWith(() => _TestAuthNotifier(testSession)),
506
+
],
507
+
);
508
+
509
+
final app = tester.widget<MaterialApp>(find.byType(MaterialApp));
510
+
final router = app.routerConfig as GoRouter;
511
+
512
+
final encodedDid = Uri.encodeComponent(testSession.did);
513
+
unawaited(router.push('/profile/following/$encodedDid'));
514
+
await tester.pumpAndSettle();
515
+
516
+
expect(find.byType(FollowingPage), findsOneWidget);
517
+
final followingPage = tester.widget<FollowingPage>(find.byType(FollowingPage));
518
+
expect(followingPage.did, testSession.did);
519
+
});
355
520
});
356
521
});
357
522