mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 19:07:17 +01:00
sync_settings_ui 0.5.2: cancelled backup is not success
Some checks failed
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
music_theory tests / test (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
web_ui tests / test (push) Waiting to run
data_transfer_flutter tests / test (push) Has been cancelled
sync_settings_ui tests / test (push) Has been cancelled
Some checks failed
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
music_theory tests / test (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
web_ui tests / test (push) Waiting to run
data_transfer_flutter tests / test (push) Has been cancelled
sync_settings_ui tests / test (push) Has been cancelled
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWXTUM9dpnCS2wtFkx4
This commit is contained in:
parent
bbb7f0f0c0
commit
648bde44b1
@ -1,5 +1,14 @@
|
||||
import 'package:data_transfer_flutter/data_transfer_flutter.dart';
|
||||
|
||||
/// Thrown by a [BackupSlot] callback when the user dismissed the file dialog.
|
||||
///
|
||||
/// Not a failure: [SyncSettingsScreen] clears its status line instead of
|
||||
/// claiming success or showing an error.
|
||||
class BackupCancelled implements Exception {
|
||||
/// Creates the signal.
|
||||
const BackupCancelled();
|
||||
}
|
||||
|
||||
/// An injectable local export/import delegate for [SyncSettingsScreen]'s
|
||||
/// optional "Backup" section.
|
||||
///
|
||||
@ -24,7 +33,8 @@ class BackupSlot {
|
||||
/// Export saves `build()` as [fileName] to device storage (system Save-as
|
||||
/// on Android/iOS, a save dialog on desktop, a download on web). Import
|
||||
/// lets the user pick a JSON file and hands the decoded object to
|
||||
/// [restore]; a cancelled picker restores nothing.
|
||||
/// [restore]. A dismissed dialog throws [BackupCancelled] (and a cancelled
|
||||
/// picker restores nothing).
|
||||
factory BackupSlot.json({
|
||||
required String label,
|
||||
required String fileName,
|
||||
@ -33,11 +43,13 @@ class BackupSlot {
|
||||
}) => BackupSlot(
|
||||
label: label,
|
||||
export: () async {
|
||||
await exportJson(fileName: fileName, json: await build());
|
||||
final saved = await exportJson(fileName: fileName, json: await build());
|
||||
if (!saved) throw const BackupCancelled();
|
||||
},
|
||||
import: () async {
|
||||
final json = await pickJson();
|
||||
if (json != null) await restore(json);
|
||||
if (json == null) throw const BackupCancelled();
|
||||
await restore(json);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -123,6 +123,8 @@ class _SyncSettingsScreenState extends State<SyncSettingsScreen> {
|
||||
try {
|
||||
await backup.export();
|
||||
if (mounted) setState(() => _status = 'Exported ${backup.label}.');
|
||||
} on BackupCancelled {
|
||||
if (mounted) setState(() => _status = null);
|
||||
} on Exception catch (error) {
|
||||
if (mounted) setState(() => _status = 'Export failed: $error');
|
||||
}
|
||||
@ -132,6 +134,8 @@ class _SyncSettingsScreenState extends State<SyncSettingsScreen> {
|
||||
try {
|
||||
await backup.import();
|
||||
if (mounted) setState(() => _status = 'Imported ${backup.label}.');
|
||||
} on BackupCancelled {
|
||||
if (mounted) setState(() => _status = null);
|
||||
} on Exception catch (error) {
|
||||
if (mounted) setState(() => _status = 'Import failed: $error');
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ description: >-
|
||||
injected closures -- no keystore or platform plugin access lives in this
|
||||
package itself.
|
||||
publish_to: 'none'
|
||||
version: 0.5.1
|
||||
version: 0.5.2
|
||||
|
||||
environment:
|
||||
sdk: ^3.12.2
|
||||
|
||||
@ -70,15 +70,28 @@ void main() {
|
||||
restore: (_) async => called = true,
|
||||
);
|
||||
|
||||
await slot.import();
|
||||
await expectLater(slot.import(), throwsA(isA<BackupCancelled>()));
|
||||
|
||||
expect(called, isFalse);
|
||||
});
|
||||
|
||||
test('a cancelled save dialog reports the cancellation', () async {
|
||||
fake.acceptSave = false;
|
||||
final slot = BackupSlot.json(
|
||||
label: 'inventory',
|
||||
fileName: 'inv.json',
|
||||
build: () async => {'items': 3},
|
||||
restore: (_) async {},
|
||||
);
|
||||
|
||||
await expectLater(slot.export(), throwsA(isA<BackupCancelled>()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class _FakePlatform implements DataTransferPlatform {
|
||||
String? picked;
|
||||
bool acceptSave = true;
|
||||
final saved = <(String, String)>[];
|
||||
|
||||
@override
|
||||
@ -88,7 +101,7 @@ class _FakePlatform implements DataTransferPlatform {
|
||||
String mimeType = 'application/json',
|
||||
}) async {
|
||||
saved.add((fileName, text));
|
||||
return true;
|
||||
return acceptSave;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -17,6 +17,38 @@ Widget _wrap(Widget child) => MaterialApp(home: child);
|
||||
|
||||
void main() {
|
||||
group('Backup section', () {
|
||||
testWidgets('a cancelled export or import claims no success', (
|
||||
tester,
|
||||
) async {
|
||||
await tester.pumpWidget(
|
||||
_wrap(
|
||||
SyncSettingsScreen(
|
||||
accountLoader: () async => null,
|
||||
accountSaver: (_) async {},
|
||||
accountClearer: () async {},
|
||||
sessionProbe: () async => false,
|
||||
firebaseFactory: () async => null,
|
||||
backup: BackupSlot(
|
||||
label: 'notes',
|
||||
export: () async => throw const BackupCancelled(),
|
||||
import: () async => throw const BackupCancelled(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.text('Export notes'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Exported notes.'), findsNothing);
|
||||
expect(find.textContaining('failed'), findsNothing);
|
||||
|
||||
await tester.tap(find.text('Import notes'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Imported notes.'), findsNothing);
|
||||
expect(find.textContaining('failed'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('omitted entirely when backup is null', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
_wrap(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user