@@ -79,6 +79,7 @@ final class _FakeGithubApi implements GithubApi {
7979 this .resolveGate,
8080 this .listGate,
8181 this .fetchFailuresRemaining = 0 ,
82+ this .listFailuresRemaining = 0 ,
8283 }) : _bytesByRemotePath = < String , Uint8List > {
8384 for (final MapEntry <String , String > source
8485 in sourceByRemotePath.entries)
@@ -92,6 +93,7 @@ final class _FakeGithubApi implements GithubApi {
9293 final Completer <void >? resolveGate;
9394 final Completer <void >? listGate;
9495 int fetchFailuresRemaining;
96+ int listFailuresRemaining;
9597 final List <(RepositoryLocator , String )> resolveCalls =
9698 < (RepositoryLocator , String )> [];
9799 final List <String > listedRemotePaths = < String > [];
@@ -124,8 +126,12 @@ final class _FakeGithubApi implements GithubApi {
124126 }) async {
125127 listedRemotePaths.add (remotePath);
126128 await listGate? .future;
127- if (remotePath.isNotEmpty && childListFailure
128- case final GithubFailure failure) {
129+ if (listFailuresRemaining > 0 ) {
130+ listFailuresRemaining -= 1 ;
131+ throw GithubFailure (GithubFailureKind .offline, path: remotePath);
132+ }
133+ final GithubFailure ? failure = childListFailure;
134+ if (remotePath.isNotEmpty && failure != null ) {
129135 throw failure;
130136 }
131137 return GithubDirectory (
@@ -421,8 +427,54 @@ void main() {
421427 expect (tester.widget <Focus >(failure).focusNode? .hasFocus, isTrue);
422428 expect (
423429 tester.getSemantics (failure),
424- matchesSemantics (isLiveRegion: true ),
430+ matchesSemantics (
431+ isLiveRegion: true ,
432+ isFocusable: true ,
433+ isFocused: true ,
434+ hasFocusAction: true ,
435+ ),
436+ );
437+ expect (find.text (l10nOf (tester).githubImportRetry), findsNothing);
438+ expect (
439+ tester
440+ .widget <FilledButton >(find.byKey (kGithubBrowseButtonKey))
441+ .onPressed,
442+ isNull,
443+ );
444+
445+ await tester.pump (const Duration (seconds: 120 ));
446+ expect (find.text (l10nOf (tester).githubImportRetry), findsOneWidget);
447+ expect (
448+ tester
449+ .widget <FilledButton >(find.byKey (kGithubBrowseButtonKey))
450+ .onPressed,
451+ isNotNull,
452+ );
453+ },
454+ );
455+
456+ testWidgets (
457+ 'a failed root listing keeps its pin and retries only that listing' ,
458+ (WidgetTester tester) async {
459+ final RecordingConnection connection = RecordingConnection (
460+ initial: ConnState .ready,
425461 );
462+ final _FakeGithubApi api = _FakeGithubApi (listFailuresRemaining: 1 );
463+ addTearDown (connection.dispose);
464+
465+ await _openImport (tester, connection, api);
466+ await _browse (tester);
467+
468+ expect (api.resolveCalls, hasLength (1 ));
469+ expect (api.listedRemotePaths, < String > ['' ]);
470+ expect (find.textContaining (_commitSha), findsOneWidget);
471+
472+ await tester.tap (find.text (l10nOf (tester).githubImportRetry));
473+ await tester.pumpAndSettle ();
474+
475+ expect (api.resolveCalls, hasLength (1 ));
476+ expect (api.listedRemotePaths, < String > ['' , '' ]);
477+ expect (find.text ('hello.py' ), findsOneWidget);
426478 },
427479 );
428480
@@ -606,7 +658,7 @@ void main() {
606658 .value,
607659 isTrue,
608660 );
609- expect (find.text ('/' ), findsOneWidget );
661+ expect (find.text ('/' ), findsNWidgets ( 2 ) );
610662 });
611663
612664 testWidgets ('a zero-write blob failure retries from the same review' , (
0 commit comments