Skip to content

Commit c760320

Browse files
committed
[red] reproduce recovery retry and compact volatile UI gaps
Signed-off-by: Viwat Vchirawongkwin <viwat.v@chula.ac.th>
1 parent 6a6d086 commit c760320

1 file changed

Lines changed: 133 additions & 0 deletions

File tree

‎app/test/widget/recovery_gate_test.dart‎

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class _Store implements DraftRepository {
3434
);
3535
Completer<DraftRead>? delayed;
3636
bool failClear = false;
37+
DraftStorageFailure? failWrite;
3738
@override
3839
Future<DraftRead> load() async => delayed == null ? slot : delayed!.future;
3940
@override
@@ -50,6 +51,7 @@ class _Store implements DraftRepository {
5051
DraftSnapshot snapshot, {
5152
required int expectedGeneration,
5253
}) async {
54+
if (failWrite != null) throw DraftStorageException(failWrite!);
5355
slot = DraftRead(generation: snapshot.generation, snapshot: snapshot);
5456
}
5557

@@ -309,4 +311,135 @@ void main() {
309311
expect(tester.takeException(), isNull);
310312
},
311313
);
314+
testWidgets(
315+
'runtime unsafe storage failure offers Retry and volatile continuation',
316+
(WidgetTester tester) async {
317+
final _Store store = _Store();
318+
final FakeConnection connection = FakeConnection();
319+
addTearDown(connection.dispose);
320+
await pumpSurface(
321+
tester,
322+
const RecoveryGate(child: EditorView()),
323+
connection: connection,
324+
extra: <Override>[draftRepositoryProvider.overrideWithValue(store)],
325+
);
326+
await tester.pump();
327+
await tester.tap(find.byKey(kRecoveryRestoreKey));
328+
await tester.pump();
329+
store.failWrite = DraftStorageFailure.conflict;
330+
containerOf(
331+
tester,
332+
).read(editorDocumentProvider.notifier).setContent('live newer text');
333+
await tester.pump();
334+
await tester.tap(find.byKey(kRecoverySaveKey));
335+
await tester.pumpAndSettle();
336+
expect(find.byKey(kRecoveryRetryKey), findsOneWidget);
337+
expect(find.byKey(kRecoveryContinueKey), findsOneWidget);
338+
expect(
339+
containerOf(tester).read(editorDocumentProvider).content,
340+
'live newer text',
341+
);
342+
await tester.tap(find.byKey(kRecoveryRetryKey));
343+
await tester.pumpAndSettle();
344+
expect(find.text('prior text'), findsOneWidget);
345+
expect(find.text('live newer text'), findsOneWidget);
346+
expect(find.byKey(kRecoveryRestoreKey), findsOneWidget);
347+
expect(store.slot.snapshot!.content, 'prior text');
348+
},
349+
);
350+
351+
testWidgets(
352+
'New in an explicitly volatile session needs no second storage-failure choice',
353+
(WidgetTester tester) async {
354+
final _Store store = _Store();
355+
final FakeConnection connection = FakeConnection();
356+
addTearDown(connection.dispose);
357+
await pumpSurface(
358+
tester,
359+
const RecoveryGate(child: EditorView()),
360+
connection: connection,
361+
extra: <Override>[draftRepositoryProvider.overrideWithValue(store)],
362+
);
363+
await tester.pump();
364+
await tester.tap(find.byKey(kRecoveryRestoreKey));
365+
await tester.pump();
366+
containerOf(
367+
tester,
368+
).read(draftRecoveryProvider.notifier).continueWithoutRecovery();
369+
await tester.pump();
370+
await tester.tap(find.byKey(kEditorNewButtonKey));
371+
await tester.pumpAndSettle();
372+
await tester.tap(find.text('Replace draft'));
373+
await tester.pumpAndSettle();
374+
expect(containerOf(tester).read(editorDocumentProvider).content, isEmpty);
375+
expect(find.byType(AlertDialog), findsNothing);
376+
expect(store.slot.snapshot!.content, 'prior text');
377+
},
378+
);
379+
380+
testWidgets(
381+
'disconnected shell retains a deliberately empty named file preview',
382+
(WidgetTester tester) async {
383+
final _Store store = _Store()..slot = const DraftRead(generation: 0);
384+
final FakeConnection connection = FakeConnection();
385+
final FakeScanner scanner = FakeScanner();
386+
final FakeSeamReadiness readiness = FakeSeamReadiness();
387+
final PbleConnectionManager manager = PbleConnectionManager(
388+
scanner: scanner,
389+
readiness: readiness,
390+
connectionFactory: (String _) async => connection,
391+
);
392+
addTearDown(manager.dispose);
393+
addTearDown(scanner.dispose);
394+
addTearDown(readiness.dispose);
395+
addTearDown(connection.dispose);
396+
await tester.pumpWidget(
397+
ProviderScope(
398+
overrides: <Override>[
399+
draftRepositoryProvider.overrideWithValue(store),
400+
connectionManagerProvider.overrideWithValue(manager),
401+
],
402+
child: const PybleApp(),
403+
),
404+
);
405+
await tester.pump();
406+
await tester.pump();
407+
containerOf(tester)
408+
.read(editorDocumentProvider.notifier)
409+
.openFromBoard(path: '/empty.py', content: '');
410+
await tester.pump();
411+
expect(find.text('Your current text draft'), findsOneWidget);
412+
expect(find.text('empty.py'), findsOneWidget);
413+
expect(find.byType(ConnectScreen), findsNothing);
414+
},
415+
);
416+
testWidgets(
417+
'volatile editor remains usable at 2x text with the keyboard present',
418+
(WidgetTester tester) async {
419+
tester.platformDispatcher.textScaleFactorTestValue = 2;
420+
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue);
421+
tester.view.viewInsets = const FakeViewPadding(bottom: 350);
422+
addTearDown(tester.view.resetViewInsets);
423+
final _Store store = _Store()..slot = const DraftRead(generation: 0);
424+
final FakeConnection connection = FakeConnection();
425+
addTearDown(connection.dispose);
426+
await pumpSurface(
427+
tester,
428+
const RecoveryGate(child: EditorView()),
429+
connection: connection,
430+
size: const Size(400, 800),
431+
extra: <Override>[draftRepositoryProvider.overrideWithValue(store)],
432+
);
433+
await tester.pump();
434+
containerOf(
435+
tester,
436+
).read(editorDocumentProvider.notifier).setContent('live text');
437+
containerOf(
438+
tester,
439+
).read(draftRecoveryProvider.notifier).continueWithoutRecovery();
440+
await tester.pump();
441+
expect(tester.takeException(), isNull);
442+
expect(tester.getSize(find.byType(EditableText)).height, greaterThan(80));
443+
},
444+
);
312445
}

0 commit comments

Comments
 (0)