From d6f7e999410edf07337fe40a262245f85f9b0e8c Mon Sep 17 00:00:00 2001 From: Doug Borg Date: Sun, 1 Feb 2026 16:01:11 -0700 Subject: [PATCH 1/2] Fix pre-existing test failures in tile provider tests - tile_provider_test: Fix stale package:flock_map_app import (now deflockapp), correct test assertion for Mapbox requiring API key - deflock_tile_provider_test: Fix relative imports, replace invalid const TileLayer with final, mock AppState.instance for getImage test - Remove widget_test.dart (default flutter create scaffold, references nonexistent MyApp counter widget) Co-Authored-By: Claude Opus 4.5 --- test/models/tile_provider_test.dart | 13 +++-- test/services/deflock_tile_provider_test.dart | 52 +++++++++++-------- test/widget_test.dart | 30 ----------- 3 files changed, 41 insertions(+), 54 deletions(-) delete mode 100644 test/widget_test.dart diff --git a/test/models/tile_provider_test.dart b/test/models/tile_provider_test.dart index f26810a..3d825b0 100644 --- a/test/models/tile_provider_test.dart +++ b/test/models/tile_provider_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:flock_map_app/models/tile_provider.dart'; +import 'package:deflockapp/models/tile_provider.dart'; void main() { group('TileType', () { @@ -127,10 +127,17 @@ void main() { expect(satelliteType.attribution, '© Microsoft Corporation'); }); - test('all default providers are usable', () { + test('providers without API key requirements are usable', () { final providers = DefaultTileProviders.createDefaults(); for (final provider in providers) { - expect(provider.isUsable, isTrue, reason: '${provider.name} should be usable'); + final needsKey = provider.tileTypes.any((t) => t.requiresApiKey); + if (needsKey) { + expect(provider.isUsable, isFalse, + reason: '${provider.name} requires API key and has none set'); + } else { + expect(provider.isUsable, isTrue, + reason: '${provider.name} should be usable without API key'); + } } }); }); diff --git a/test/services/deflock_tile_provider_test.dart b/test/services/deflock_tile_provider_test.dart index 44b900a..8ea7bed 100644 --- a/test/services/deflock_tile_provider_test.dart +++ b/test/services/deflock_tile_provider_test.dart @@ -1,40 +1,50 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_map/flutter_map.dart'; +import 'package:mocktail/mocktail.dart'; -import '../../lib/services/deflock_tile_provider.dart'; -import '../../lib/services/map_data_provider.dart'; +import 'package:deflockapp/app_state.dart'; +import 'package:deflockapp/services/deflock_tile_provider.dart'; +import 'package:deflockapp/services/map_data_provider.dart'; + +class MockAppState extends Mock implements AppState {} void main() { group('DeflockTileProvider', () { late DeflockTileProvider provider; - + late MockAppState mockAppState; + setUp(() { provider = DeflockTileProvider(); + mockAppState = MockAppState(); + when(() => mockAppState.selectedTileProvider).thenReturn(null); + when(() => mockAppState.selectedTileType).thenReturn(null); + AppState.instance = mockAppState; }); - + test('creates image provider for tile coordinates', () { const coordinates = TileCoordinates(0, 0, 0); - const options = TileLayer( + final options = TileLayer( urlTemplate: 'test/{z}/{x}/{y}', ); - + final imageProvider = provider.getImage(coordinates, options); - + expect(imageProvider, isA()); - expect((imageProvider as DeflockTileImageProvider).coordinates, equals(coordinates)); + expect((imageProvider as DeflockTileImageProvider).coordinates, + equals(coordinates)); }); }); - + group('DeflockTileImageProvider', () { test('generates consistent keys for same coordinates', () { const coordinates1 = TileCoordinates(1, 2, 3); const coordinates2 = TileCoordinates(1, 2, 3); const coordinates3 = TileCoordinates(1, 2, 4); - - const options = TileLayer(urlTemplate: 'test/{z}/{x}/{y}'); - + + final options = TileLayer(urlTemplate: 'test/{z}/{x}/{y}'); + final mapDataProvider = MapDataProvider(); - + final provider1 = DeflockTileImageProvider( coordinates: coordinates1, options: options, @@ -56,20 +66,20 @@ void main() { providerId: 'test_provider', tileTypeId: 'test_type', ); - + // Same coordinates should be equal expect(provider1, equals(provider2)); expect(provider1.hashCode, equals(provider2.hashCode)); - + // Different coordinates should not be equal expect(provider1, isNot(equals(provider3))); }); - + test('generates different keys for different providers/types', () { const coordinates = TileCoordinates(1, 2, 3); - const options = TileLayer(urlTemplate: 'test/{z}/{x}/{y}'); + final options = TileLayer(urlTemplate: 'test/{z}/{x}/{y}'); final mapDataProvider = MapDataProvider(); - + final provider1 = DeflockTileImageProvider( coordinates: coordinates, options: options, @@ -91,14 +101,14 @@ void main() { providerId: 'provider_a', tileTypeId: 'type_2', ); - + // Different providers should not be equal (even with same coordinates) expect(provider1, isNot(equals(provider2))); expect(provider1.hashCode, isNot(equals(provider2.hashCode))); - + // Different tile types should not be equal (even with same coordinates and provider) expect(provider1, isNot(equals(provider3))); expect(provider1.hashCode, isNot(equals(provider3.hashCode))); }); }); -} \ No newline at end of file +} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index d370707..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:deflockapp/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} From 73160c32de75bc717b7081b6a615763f041a806a Mon Sep 17 00:00:00 2001 From: Doug Borg Date: Sat, 7 Feb 2026 11:35:28 -0700 Subject: [PATCH 2/2] Add mocktail dev dependency and fix test state leak Address PR review comments: - Add mocktail and flutter_test to dev_dependencies in pubspec.yaml - Add tearDown to reset AppState.instance between tests Co-Authored-By: Claude Opus 4.6 --- pubspec.lock | 101 +++++++++++++++++- pubspec.yaml | 3 + test/services/deflock_tile_provider_test.dart | 5 + 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 723b491..2a86471 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -65,6 +65,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" characters: dependency: transitive description: @@ -161,6 +169,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.3" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" ffi: dependency: transitive description: @@ -310,6 +326,11 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" flutter_web_auth_2: dependency: "direct main" description: @@ -443,6 +464,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" linkify: dependency: transitive description: @@ -467,6 +512,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -479,10 +532,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mgrs_dart: dependency: transitive description: @@ -491,6 +544,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + mocktail: + dependency: "direct dev" + description: + name: mocktail + sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" + url: "https://pub.dev" + source: hosted + version: "1.0.4" nested: dependency: transitive description: @@ -760,6 +821,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" string_scanner: dependency: transitive description: @@ -784,6 +861,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + url: "https://pub.dev" + source: hosted + version: "0.7.7" timezone: dependency: transitive description: @@ -916,10 +1001,18 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4cff551..1dda115 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,9 @@ dependencies: csv: ^6.0.0 dev_dependencies: + flutter_test: + sdk: flutter + mocktail: ^1.0.4 flutter_launcher_icons: ^0.14.4 flutter_native_splash: ^2.4.6 diff --git a/test/services/deflock_tile_provider_test.dart b/test/services/deflock_tile_provider_test.dart index 8ea7bed..a09e7b2 100644 --- a/test/services/deflock_tile_provider_test.dart +++ b/test/services/deflock_tile_provider_test.dart @@ -21,6 +21,11 @@ void main() { AppState.instance = mockAppState; }); + tearDown(() { + // Reset to a clean mock so stubbed state doesn't leak to other tests + AppState.instance = MockAppState(); + }); + test('creates image provider for tile coordinates', () { const coordinates = TileCoordinates(0, 0, 0); final options = TileLayer(