mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
chore(mobile): Favorite provider unit test (#1874)
* Favorite provider tests * Remove unused mock * Add setUp function to avoid duplicate code
This commit is contained in:
parent
807bdfeda9
commit
c9a6820de7
@ -3,14 +3,15 @@ import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||
|
||||
class FavoriteSelectionNotifier extends StateNotifier<Set<String>> {
|
||||
FavoriteSelectionNotifier(this.ref) : super({}) {
|
||||
state = ref.watch(assetProvider).allAssets
|
||||
FavoriteSelectionNotifier(this.assetsState, this.assetNotifier) : super({}) {
|
||||
state = assetsState.allAssets
|
||||
.where((asset) => asset.isFavorite)
|
||||
.map((asset) => asset.id)
|
||||
.toSet();
|
||||
}
|
||||
|
||||
final Ref ref;
|
||||
final AssetsState assetsState;
|
||||
final AssetNotifier assetNotifier;
|
||||
|
||||
void _setFavoriteForAssetId(String id, bool favorite) {
|
||||
if (!favorite) {
|
||||
@ -29,7 +30,7 @@ class FavoriteSelectionNotifier extends StateNotifier<Set<String>> {
|
||||
|
||||
_setFavoriteForAssetId(asset.id, !_isFavorite(asset.id));
|
||||
|
||||
await ref.watch(assetProvider.notifier).toggleFavorite(
|
||||
await assetNotifier.toggleFavorite(
|
||||
asset,
|
||||
state.contains(asset.id),
|
||||
);
|
||||
@ -37,8 +38,8 @@ class FavoriteSelectionNotifier extends StateNotifier<Set<String>> {
|
||||
|
||||
Future<void> addToFavorites(Iterable<Asset> assets) {
|
||||
state = state.union(assets.map((a) => a.id).toSet());
|
||||
final futures = assets.map((a) =>
|
||||
ref.watch(assetProvider.notifier).toggleFavorite(
|
||||
final futures = assets.map((a) =>
|
||||
assetNotifier.toggleFavorite(
|
||||
a,
|
||||
true,
|
||||
),
|
||||
@ -50,7 +51,10 @@ class FavoriteSelectionNotifier extends StateNotifier<Set<String>> {
|
||||
|
||||
final favoriteProvider =
|
||||
StateNotifierProvider<FavoriteSelectionNotifier, Set<String>>((ref) {
|
||||
return FavoriteSelectionNotifier(ref);
|
||||
return FavoriteSelectionNotifier(
|
||||
ref.watch(assetProvider),
|
||||
ref.watch(assetProvider.notifier),
|
||||
);
|
||||
});
|
||||
|
||||
final favoriteAssetProvider = StateProvider((ref) {
|
||||
|
@ -740,6 +740,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
mockito:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: mockito
|
||||
sha256: "2a8a17b82b1bde04d514e75d90d634a0ac23f6cb4991f6098009dd56836aeafe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.3.2"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -64,6 +64,7 @@ dev_dependencies:
|
||||
flutter_launcher_icons: "^0.9.2"
|
||||
flutter_native_splash: ^2.2.16
|
||||
isar_generator: *isar_version
|
||||
mockito: ^5.3.2
|
||||
integration_test:
|
||||
sdk: flutter
|
||||
|
||||
|
104
mobile/test/favorite_provider_test.dart
Normal file
104
mobile/test/favorite_provider_test.dart
Normal file
@ -0,0 +1,104 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/favorite/providers/favorite_provider.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<AssetsState>(),
|
||||
MockSpec<AssetNotifier>(),
|
||||
])
|
||||
import 'favorite_provider_test.mocks.dart';
|
||||
|
||||
Asset _getTestAsset(String id, bool favorite) {
|
||||
return Asset(
|
||||
remoteId: id,
|
||||
deviceAssetId: '',
|
||||
deviceId: '',
|
||||
ownerId: '',
|
||||
fileCreatedAt: DateTime.now(),
|
||||
fileModifiedAt: DateTime.now(),
|
||||
durationInSeconds: 0,
|
||||
fileName: '',
|
||||
isFavorite: favorite,
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group("Test favoriteProvider", () {
|
||||
|
||||
late MockAssetsState assetsState;
|
||||
late MockAssetNotifier assetNotifier;
|
||||
late ProviderContainer container;
|
||||
late StateNotifierProvider<FavoriteSelectionNotifier, Set<String>> testFavoritesProvider;
|
||||
|
||||
setUp(() {
|
||||
assetsState = MockAssetsState();
|
||||
assetNotifier = MockAssetNotifier();
|
||||
container = ProviderContainer();
|
||||
|
||||
testFavoritesProvider =
|
||||
StateNotifierProvider<FavoriteSelectionNotifier, Set<String>>((ref) {
|
||||
return FavoriteSelectionNotifier(
|
||||
assetsState,
|
||||
assetNotifier,
|
||||
);
|
||||
});
|
||||
},);
|
||||
|
||||
test("Empty favorites provider", () {
|
||||
when(assetsState.allAssets).thenReturn([]);
|
||||
expect(<String>{}, container.read(testFavoritesProvider));
|
||||
});
|
||||
|
||||
test("Non-empty favorites provider", () {
|
||||
when(assetsState.allAssets).thenReturn([
|
||||
_getTestAsset("001", false),
|
||||
_getTestAsset("002", true),
|
||||
_getTestAsset("003", false),
|
||||
_getTestAsset("004", false),
|
||||
_getTestAsset("005", true),
|
||||
]);
|
||||
|
||||
expect(<String>{"002", "005"}, container.read(testFavoritesProvider));
|
||||
});
|
||||
|
||||
test("Toggle favorite", () {
|
||||
when(assetNotifier.toggleFavorite(null, false))
|
||||
.thenAnswer((_) async => false);
|
||||
|
||||
final testAsset1 = _getTestAsset("001", false);
|
||||
final testAsset2 = _getTestAsset("002", true);
|
||||
|
||||
when(assetsState.allAssets).thenReturn([testAsset1, testAsset2]);
|
||||
|
||||
expect(<String>{"002"}, container.read(testFavoritesProvider));
|
||||
|
||||
container.read(testFavoritesProvider.notifier).toggleFavorite(testAsset2);
|
||||
expect(<String>{}, container.read(testFavoritesProvider));
|
||||
|
||||
container.read(testFavoritesProvider.notifier).toggleFavorite(testAsset1);
|
||||
expect(<String>{"001"}, container.read(testFavoritesProvider));
|
||||
});
|
||||
|
||||
test("Add favorites", () {
|
||||
when(assetNotifier.toggleFavorite(null, false))
|
||||
.thenAnswer((_) async => false);
|
||||
|
||||
when(assetsState.allAssets).thenReturn([]);
|
||||
|
||||
expect(<String>{}, container.read(testFavoritesProvider));
|
||||
|
||||
container.read(testFavoritesProvider.notifier).addToFavorites(
|
||||
[
|
||||
_getTestAsset("001", false),
|
||||
_getTestAsset("002", false),
|
||||
],
|
||||
);
|
||||
|
||||
expect(<String>{"001", "002"}, container.read(testFavoritesProvider));
|
||||
});
|
||||
});
|
||||
}
|
259
mobile/test/favorite_provider_test.mocks.dart
Normal file
259
mobile/test/favorite_provider_test.mocks.dart
Normal file
@ -0,0 +1,259 @@
|
||||
// Mocks generated by Mockito 5.3.2 from annotations
|
||||
// in immich_mobile/test/favorite_provider_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i5;
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart' as _i7;
|
||||
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart'
|
||||
as _i6;
|
||||
import 'package:immich_mobile/shared/models/asset.dart' as _i4;
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart' as _i2;
|
||||
import 'package:logging/logging.dart' as _i3;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:state_notifier/state_notifier.dart' as _i8;
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: avoid_redundant_argument_values
|
||||
// ignore_for_file: avoid_setters_without_getters
|
||||
// ignore_for_file: comment_references
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeAssetsState_0 extends _i1.SmartFake implements _i2.AssetsState {
|
||||
_FakeAssetsState_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
parent,
|
||||
parentInvocation,
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeLogger_1 extends _i1.SmartFake implements _i3.Logger {
|
||||
_FakeLogger_1(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
parent,
|
||||
parentInvocation,
|
||||
);
|
||||
}
|
||||
|
||||
/// A class which mocks [AssetsState].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockAssetsState extends _i1.Mock implements _i2.AssetsState {
|
||||
@override
|
||||
List<_i4.Asset> get allAssets => (super.noSuchMethod(
|
||||
Invocation.getter(#allAssets),
|
||||
returnValue: <_i4.Asset>[],
|
||||
returnValueForMissingStub: <_i4.Asset>[],
|
||||
) as List<_i4.Asset>);
|
||||
@override
|
||||
_i5.Future<_i2.AssetsState> withRenderDataStructure(
|
||||
_i6.AssetGridLayoutParameters? layout) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#withRenderDataStructure,
|
||||
[layout],
|
||||
),
|
||||
returnValue: _i5.Future<_i2.AssetsState>.value(_FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#withRenderDataStructure,
|
||||
[layout],
|
||||
),
|
||||
)),
|
||||
returnValueForMissingStub:
|
||||
_i5.Future<_i2.AssetsState>.value(_FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#withRenderDataStructure,
|
||||
[layout],
|
||||
),
|
||||
)),
|
||||
) as _i5.Future<_i2.AssetsState>);
|
||||
@override
|
||||
_i2.AssetsState withAdditionalAssets(List<_i4.Asset>? toAdd) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#withAdditionalAssets,
|
||||
[toAdd],
|
||||
),
|
||||
returnValue: _FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#withAdditionalAssets,
|
||||
[toAdd],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.method(
|
||||
#withAdditionalAssets,
|
||||
[toAdd],
|
||||
),
|
||||
),
|
||||
) as _i2.AssetsState);
|
||||
}
|
||||
|
||||
/// A class which mocks [AssetNotifier].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockAssetNotifier extends _i1.Mock implements _i2.AssetNotifier {
|
||||
@override
|
||||
_i3.Logger get log => (super.noSuchMethod(
|
||||
Invocation.getter(#log),
|
||||
returnValue: _FakeLogger_1(
|
||||
this,
|
||||
Invocation.getter(#log),
|
||||
),
|
||||
returnValueForMissingStub: _FakeLogger_1(
|
||||
this,
|
||||
Invocation.getter(#log),
|
||||
),
|
||||
) as _i3.Logger);
|
||||
@override
|
||||
set onError(_i7.ErrorListener? _onError) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#onError,
|
||||
_onError,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
bool get mounted => (super.noSuchMethod(
|
||||
Invocation.getter(#mounted),
|
||||
returnValue: false,
|
||||
returnValueForMissingStub: false,
|
||||
) as bool);
|
||||
@override
|
||||
_i5.Stream<_i2.AssetsState> get stream => (super.noSuchMethod(
|
||||
Invocation.getter(#stream),
|
||||
returnValue: _i5.Stream<_i2.AssetsState>.empty(),
|
||||
returnValueForMissingStub: _i5.Stream<_i2.AssetsState>.empty(),
|
||||
) as _i5.Stream<_i2.AssetsState>);
|
||||
@override
|
||||
_i2.AssetsState get state => (super.noSuchMethod(
|
||||
Invocation.getter(#state),
|
||||
returnValue: _FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.getter(#state),
|
||||
),
|
||||
returnValueForMissingStub: _FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.getter(#state),
|
||||
),
|
||||
) as _i2.AssetsState);
|
||||
@override
|
||||
set state(_i2.AssetsState? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#state,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i2.AssetsState get debugState => (super.noSuchMethod(
|
||||
Invocation.getter(#debugState),
|
||||
returnValue: _FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.getter(#debugState),
|
||||
),
|
||||
returnValueForMissingStub: _FakeAssetsState_0(
|
||||
this,
|
||||
Invocation.getter(#debugState),
|
||||
),
|
||||
) as _i2.AssetsState);
|
||||
@override
|
||||
bool get hasListeners => (super.noSuchMethod(
|
||||
Invocation.getter(#hasListeners),
|
||||
returnValue: false,
|
||||
returnValueForMissingStub: false,
|
||||
) as bool);
|
||||
@override
|
||||
_i5.Future<void> rebuildAssetGridDataStructure() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#rebuildAssetGridDataStructure,
|
||||
[],
|
||||
),
|
||||
returnValue: _i5.Future<void>.value(),
|
||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
||||
) as _i5.Future<void>);
|
||||
@override
|
||||
void onNewAssetUploaded(_i4.Asset? newAsset) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#onNewAssetUploaded,
|
||||
[newAsset],
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
dynamic deleteAssets(Set<_i4.Asset>? deleteAssets) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#deleteAssets,
|
||||
[deleteAssets],
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i5.Future<bool> toggleFavorite(
|
||||
_i4.Asset? asset,
|
||||
bool? status,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#toggleFavorite,
|
||||
[
|
||||
asset,
|
||||
status,
|
||||
],
|
||||
),
|
||||
returnValue: _i5.Future<bool>.value(false),
|
||||
returnValueForMissingStub: _i5.Future<bool>.value(false),
|
||||
) as _i5.Future<bool>);
|
||||
@override
|
||||
bool updateShouldNotify(
|
||||
_i2.AssetsState? old,
|
||||
_i2.AssetsState? current,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateShouldNotify,
|
||||
[
|
||||
old,
|
||||
current,
|
||||
],
|
||||
),
|
||||
returnValue: false,
|
||||
returnValueForMissingStub: false,
|
||||
) as bool);
|
||||
@override
|
||||
_i7.RemoveListener addListener(
|
||||
_i8.Listener<_i2.AssetsState>? listener, {
|
||||
bool? fireImmediately = true,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#addListener,
|
||||
[listener],
|
||||
{#fireImmediately: fireImmediately},
|
||||
),
|
||||
returnValue: () {},
|
||||
returnValueForMissingStub: () {},
|
||||
) as _i7.RemoveListener);
|
||||
@override
|
||||
void dispose() => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#dispose,
|
||||
[],
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user