@@ -195,6 +195,20 @@ final class _HoldingPutConnection extends RecordingConnection {
195195 }
196196}
197197
198+ final class _HoldingReviewConnection extends RecordingConnection {
199+ _HoldingReviewConnection () : super (initial: ConnState .ready);
200+
201+ final Completer <void > listStarted = Completer <void >();
202+ final Completer <void > releaseList = Completer <void >();
203+
204+ @override
205+ Future <DirectoryListing > listDirWithMetadata (String path) async {
206+ if (! listStarted.isCompleted) listStarted.complete ();
207+ await releaseList.future;
208+ return super .listDirWithMetadata (path);
209+ }
210+ }
211+
198212Key _entryKey (String remotePath) => ValueKey <String >('githubEntry_$remotePath ' );
199213
200214Key _selectionKey (String remotePath) =>
@@ -753,6 +767,115 @@ void main() {
753767 );
754768 });
755769
770+ testWidgets ('review cancellation cannot bypass a blob retry deadline' , (
771+ WidgetTester tester,
772+ ) async {
773+ final RecordingConnection connection = RecordingConnection (
774+ initial: ConnState .ready,
775+ );
776+ final _FakeGithubApi api = _FakeGithubApi (
777+ entries: const < GithubEntry > [_helloEntry],
778+ fetchFailuresRemaining: 1 ,
779+ fetchFailure: const GithubFailure (
780+ GithubFailureKind .rateLimited,
781+ retryAfter: Duration (seconds: 60 ),
782+ ),
783+ );
784+ addTearDown (connection.dispose);
785+
786+ await _openImport (tester, connection, api);
787+ await _browse (tester);
788+ await tester.tap (find.byKey (_selectionKey ('hello.py' )));
789+ await tester.pump ();
790+ await tester.tap (find.byKey (kGithubReviewButtonKey));
791+ await tester.pumpAndSettle ();
792+ await tester.tap (find.byKey (kGithubCommitButtonKey));
793+ await tester.pumpAndSettle ();
794+ expect (api.fetchedRemotePaths, < String > ['hello.py' ]);
795+
796+ await tester.tap (
797+ find.widgetWithText (TextButton , l10nOf (tester).commonCancel),
798+ );
799+ await tester.pumpAndSettle ();
800+ await tester.tap (find.byKey (kGithubReviewButtonKey));
801+ await tester.pumpAndSettle ();
802+
803+ expect (
804+ tester
805+ .widget <FilledButton >(find.byKey (kGithubCommitButtonKey))
806+ .onPressed,
807+ isNull,
808+ );
809+ expect (api.fetchedRemotePaths, < String > ['hello.py' ]);
810+
811+ await tester.pump (const Duration (seconds: 60 ));
812+ expect (
813+ tester
814+ .widget <FilledButton >(find.byKey (kGithubCommitButtonKey))
815+ .onPressed,
816+ isNotNull,
817+ );
818+ });
819+
820+ testWidgets ('folder navigation cannot bypass a retry deadline' , (
821+ WidgetTester tester,
822+ ) async {
823+ final RecordingConnection connection = RecordingConnection (
824+ initial: ConnState .ready,
825+ );
826+ final _FakeGithubApi api = _FakeGithubApi (
827+ childListFailure: const GithubFailure (
828+ GithubFailureKind .rateLimited,
829+ retryAfter: Duration (seconds: 60 ),
830+ ),
831+ );
832+ addTearDown (connection.dispose);
833+
834+ await _openImport (tester, connection, api);
835+ await _browse (tester);
836+ await tester.tap (find.byKey (_entryKey ('nested' )));
837+ await tester.pumpAndSettle ();
838+ expect (api.listedRemotePaths, < String > ['' , 'nested' ]);
839+
840+ await tester.tap (find.byKey (_entryKey ('nested' )));
841+ await tester.pumpAndSettle ();
842+ expect (api.listedRemotePaths, < String > ['' , 'nested' ]);
843+
844+ await tester.pump (const Duration (seconds: 60 ));
845+ await tester.tap (find.byKey (_entryKey ('nested' )));
846+ await tester.pumpAndSettle ();
847+ expect (api.listedRemotePaths, < String > ['' , 'nested' , 'nested' ]);
848+ });
849+
850+ testWidgets ('board target review has a distinct visible phase' , (
851+ WidgetTester tester,
852+ ) async {
853+ final _HoldingReviewConnection connection = _HoldingReviewConnection ();
854+ final _FakeGithubApi api = _FakeGithubApi (
855+ entries: const < GithubEntry > [_helloEntry],
856+ );
857+ addTearDown (() async {
858+ if (! connection.releaseList.isCompleted) {
859+ connection.releaseList.complete ();
860+ }
861+ await connection.dispose ();
862+ });
863+
864+ await _openImport (tester, connection, api);
865+ await _browse (tester);
866+ await tester.tap (find.byKey (_selectionKey ('hello.py' )));
867+ await tester.pump ();
868+ await tester.tap (find.byKey (kGithubReviewButtonKey));
869+ await connection.listStarted.future;
870+ await tester.pump ();
871+
872+ expect (find.text ('Checking board targets…' ), findsOneWidget);
873+
874+ connection.releaseList.complete ();
875+ await tester.pumpAndSettle ();
876+ expect (find.byKey (kGithubCommitButtonKey), findsOneWidget);
877+ });
878+
756879 testWidgets ('review marks an existing regular-file target before consent' , (
757880 WidgetTester tester,
758881 ) async {
0 commit comments