mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-10 20:27:01 +01:00
Every split is by test-group/concern, with the shared setup moved to a
sibling helper the splits import. All 313 tests are preserved -- the count
is unchanged and `test('…')` names are byte-identical to the originals
(verified by diffing the sorted name lists).
note_repository_test 677 -> 4 files + note_repository_helpers
capture_screen_test 660 -> 4 files + capture_screen_harness
note_editor_test 502 -> 3 files + note_editor_harness
port_guard_test 405 -> 3 files + port_guard_fakes
wrapper_server_test 402 -> 2 files + wrapper_server_harness
settings_screen_test 391 -> 2 files + settings_screen_harness
github_mirror_screen_test 365 -> 2 files + github_mirror_harness
notes_list_screen_test 347 -> 2 files + notes_list_harness
analytics_service_test 300 -> 2 files + analytics_helpers
Helpers are deliberately NOT named `*_test.dart`; the runner would collect
them and fail on the missing `main()`.
Three things did not survive a mechanical split and were handled explicitly:
* wrapper_server's `enabledOrigin` closes over the `late root` that setUp
assigns, so a top-level function cannot see it. It is now a
WrapperHarness class with an install() that registers the setUp/tearDown
pair -- the only structural change in this commit.
* note_repository's splits each repeat `setUpAll(sqfliteFfiInit)`, and
analytics' each repeat `@TestOn('vm')`. Omitting either fails quietly
(uninitialised sqflite / wrong platform) rather than loudly.
* capture_screen's `recordingMock` was declared mid-file between two
tests, so it moved to the harness rather than being dropped.
Verified: 313 tests pass (same as before the refactor), 100% coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
117 lines
4.0 KiB
Dart
117 lines
4.0 KiB
Dart
/// The pumpSettings harness and its file-selector fakes.
|
||
///
|
||
/// Shared by the files `settings_screen_test.dart` was split into for the
|
||
/// 250-line cap. Deliberately NOT named `*_test.dart`: the runner would
|
||
/// collect it and fail on the missing `main()`.
|
||
library;
|
||
|
||
import 'dart:convert';
|
||
import 'dart:io';
|
||
|
||
import 'package:crdt_sync/crdt_sync.dart';
|
||
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:http/http.dart' as http;
|
||
import 'package:http/testing.dart';
|
||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
import 'package:sync_settings_ui/sync_settings_ui.dart';
|
||
import 'package:todo/analytics/analytics_service.dart';
|
||
import 'package:todo/data/app_settings.dart';
|
||
import 'package:todo/data/note.dart';
|
||
import 'package:todo/data/note_repository.dart';
|
||
import 'package:todo/sync/backlog_export_io.dart';
|
||
import 'package:todo/sync/notes_markdown.dart';
|
||
import 'package:todo/sync/sync_settings.dart';
|
||
import 'package:todo/ui/github_mirror_screen.dart';
|
||
import 'package:todo/ui/settings_screen.dart';
|
||
|
||
import 'fake_note_repository.dart';
|
||
import 'fake_secure_storage.dart';
|
||
|
||
/// Stub file picker that returns a fixed in-memory file (no disk I/O, so the
|
||
/// `_import` flow stays timer-free and deterministic under the widget tester).
|
||
class _FakeFileSelector extends FileSelectorPlatform
|
||
with MockPlatformInterfaceMixin {
|
||
_FakeFileSelector(this.file);
|
||
final XFile? file;
|
||
|
||
@override
|
||
Future<XFile?> openFile({
|
||
List<XTypeGroup>? acceptedTypeGroups,
|
||
String? initialDirectory,
|
||
String? confirmButtonText,
|
||
}) async => file;
|
||
}
|
||
|
||
/// Repository whose reads fail, to exercise the export error path.
|
||
class _ExplodingRepo extends FakeNoteRepository {
|
||
@override
|
||
Future<List<Note>> listNotes({
|
||
NoteSort sort = NoteSort.modifiedDesc,
|
||
NoteFilter filter = const NoteFilter(),
|
||
}) async => throw Exception('db down');
|
||
}
|
||
|
||
/// File picker stub that throws, to exercise the import error path.
|
||
class _ThrowingFileSelector extends FileSelectorPlatform
|
||
with MockPlatformInterfaceMixin {
|
||
@override
|
||
Future<XFile?> openFile({
|
||
List<XTypeGroup>? acceptedTypeGroups,
|
||
String? initialDirectory,
|
||
String? confirmButtonText,
|
||
}) async => throw Exception('picker blew up');
|
||
}
|
||
|
||
Future<FakeNoteRepository> pumpSettings(
|
||
WidgetTester tester, {
|
||
SyncSettings initial = const SyncSettings(
|
||
owner: 'kuhyx',
|
||
repo: 'syncs',
|
||
token: 't',
|
||
),
|
||
http.Client? httpClient,
|
||
List<Note> seed = const [],
|
||
FakeNoteRepository? repository,
|
||
Future<FirebaseRestClient?> Function()? firebaseFactory,
|
||
ValueNotifier<AppSettings>? appSettings,
|
||
AnalyticsService? analytics,
|
||
}) async {
|
||
SharedPreferences.setMockInitialValues({});
|
||
installFakeSecureStorage();
|
||
// Tall surface so the whole settings ListView builds and the pushed
|
||
// Sync settings screen's Backup section (below the default 800×600
|
||
// fold) isn't lazy-skipped.
|
||
tester.view.physicalSize = const Size(1200, 2800);
|
||
tester.view.devicePixelRatio = 1.0;
|
||
addTearDown(tester.view.resetPhysicalSize);
|
||
addTearDown(tester.view.resetDevicePixelRatio);
|
||
|
||
final repo = repository ?? FakeNoteRepository(seed);
|
||
addTearDown(repo.close);
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: SettingsScreen(
|
||
initial: initial,
|
||
repository: repo,
|
||
appSettings:
|
||
appSettings ??
|
||
ValueNotifier(const AppSettings(advancedMode: false)),
|
||
analytics: analytics,
|
||
httpClient: httpClient,
|
||
// Injected so the widget never reaches for the platform: the real
|
||
// factory wants the OS keystore, which doesn't exist under
|
||
// `flutter test`.
|
||
firebaseFactory: firebaseFactory ?? () async => null,
|
||
accountLoader: () async => null,
|
||
sessionProbe: () async => false,
|
||
stateStore: InMemorySyncStateStore(),
|
||
),
|
||
),
|
||
);
|
||
await tester.pump();
|
||
return repo;
|
||
}
|