mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Start adding support for trophies
This commit is contained in:
72
test/trophies/models/trophy_test.dart
Normal file
72
test/trophies/models/trophy_test.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (c) 2025 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:wger/models/trophies/trophy.dart';
|
||||
|
||||
void main() {
|
||||
group('Trophy model', () {
|
||||
final sampleJson = {
|
||||
'id': 1,
|
||||
'uuid': '550e8400-e29b-41d4-a716-446655440000',
|
||||
'name': 'First Steps',
|
||||
'description': 'Awarded for the first workout',
|
||||
'image': 'https://example.org/trophy.png',
|
||||
'trophy_type': 'count',
|
||||
'is_hidden': false,
|
||||
'is_progressive': true,
|
||||
};
|
||||
|
||||
test('fromJson creates valid Trophy instance', () {
|
||||
final trophy = Trophy.fromJson(sampleJson);
|
||||
|
||||
expect(trophy.id, 1);
|
||||
expect(trophy.uuid, '550e8400-e29b-41d4-a716-446655440000');
|
||||
expect(trophy.name, 'First Steps');
|
||||
expect(trophy.description, 'Awarded for the first workout');
|
||||
expect(trophy.image, 'https://example.org/trophy.png');
|
||||
expect(trophy.type, TrophyType.count);
|
||||
expect(trophy.isHidden, isFalse);
|
||||
expect(trophy.isProgressive, isTrue);
|
||||
});
|
||||
|
||||
test('toJson returns expected map', () {
|
||||
final trophy = Trophy(
|
||||
id: 2,
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
name: 'Progressor',
|
||||
description: 'Progressive trophy',
|
||||
image: 'https://example.org/prog.png',
|
||||
type: TrophyType.time,
|
||||
isHidden: true,
|
||||
isProgressive: false,
|
||||
);
|
||||
|
||||
final json = trophy.toJson();
|
||||
|
||||
expect(json['id'], 2);
|
||||
expect(json['uuid'], '00000000-0000-0000-0000-000000000000');
|
||||
expect(json['name'], 'Progressor');
|
||||
expect(json['description'], 'Progressive trophy');
|
||||
expect(json['image'], 'https://example.org/prog.png');
|
||||
expect(json['trophy_type'], 'time');
|
||||
expect(json['is_hidden'], true);
|
||||
expect(json['is_progressive'], false);
|
||||
});
|
||||
});
|
||||
}
|
||||
97
test/trophies/models/user_trophy_progression_test.dart
Normal file
97
test/trophies/models/user_trophy_progression_test.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (c) 2025 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:wger/models/trophies/trophy.dart';
|
||||
import 'package:wger/models/trophies/user_trophy_progression.dart';
|
||||
|
||||
void main() {
|
||||
group('UserTrophyProgression model', () {
|
||||
final trophyJson = {
|
||||
'id': 1,
|
||||
'uuid': '550e8400-e29b-41d4-a716-446655440000',
|
||||
'name': 'First Steps',
|
||||
'description': 'Awarded for the first workout',
|
||||
'image': 'https://example.org/trophy.png',
|
||||
'trophy_type': 'count',
|
||||
'is_hidden': false,
|
||||
'is_progressive': true,
|
||||
};
|
||||
|
||||
final trophyProgressionJson = {
|
||||
'trophy': trophyJson,
|
||||
'is_earned': false,
|
||||
'earned_at': '2020-01-02T15:04:05Z',
|
||||
'progress': 42.5,
|
||||
'current_value': '12.5',
|
||||
'target_value': '100',
|
||||
'progress_display': '12.5/100',
|
||||
};
|
||||
|
||||
test('fromJson creates valid UserTrophyProgression instance', () {
|
||||
final utp = UserTrophyProgression.fromJson(trophyProgressionJson);
|
||||
|
||||
expect(utp.trophy.id, 1);
|
||||
expect(utp.trophy.uuid, '550e8400-e29b-41d4-a716-446655440000');
|
||||
expect(utp.isEarned, isFalse);
|
||||
|
||||
final expectedEarnedAt = DateTime.parse('2020-01-02T15:04:05Z').toLocal();
|
||||
expect(utp.earnedAt, expectedEarnedAt);
|
||||
|
||||
expect(utp.progress, 42.5);
|
||||
expect(utp.currentValue, 12.5);
|
||||
expect(utp.targetValue, 100);
|
||||
expect(utp.progressDisplay, '12.5/100');
|
||||
});
|
||||
|
||||
test('toJson returns expected map', () {
|
||||
final trophy = Trophy(
|
||||
id: 2,
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
name: 'Progressor',
|
||||
description: 'Progressive trophy',
|
||||
image: 'https://example.org/prog.png',
|
||||
type: TrophyType.time,
|
||||
isHidden: true,
|
||||
isProgressive: false,
|
||||
);
|
||||
|
||||
final earnedAt = DateTime.parse('2020-01-02T15:04:05Z').toLocal();
|
||||
|
||||
final utp = UserTrophyProgression(
|
||||
trophy: trophy,
|
||||
isEarned: true,
|
||||
earnedAt: earnedAt,
|
||||
progress: 75,
|
||||
currentValue: 75,
|
||||
targetValue: 100,
|
||||
progressDisplay: '75/100',
|
||||
);
|
||||
|
||||
final json = utp.toJson();
|
||||
|
||||
expect(json['trophy'], same(trophy));
|
||||
expect(json['is_earned'], true);
|
||||
expect(json['earned_at'], earnedAt.toIso8601String());
|
||||
expect(json['progress'], 75);
|
||||
expect(json['current_value'], 75);
|
||||
expect(json['target_value'], 100);
|
||||
expect(json['progress_display'], '75/100');
|
||||
});
|
||||
});
|
||||
}
|
||||
117
test/trophies/trophies_provider_test.dart
Normal file
117
test/trophies/trophies_provider_test.dart
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (c) 2025 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:wger/providers/base_provider.dart';
|
||||
import 'package:wger/providers/trophies.dart';
|
||||
import 'package:wger/providers/wger_base_riverpod.dart';
|
||||
|
||||
import 'trophies_provider_test.mocks.dart';
|
||||
|
||||
const trophyJson = {
|
||||
'id': 1,
|
||||
'uuid': '550e8400-e29b-41d4-a716-446655440000',
|
||||
'name': 'First Steps',
|
||||
'description': 'Awarded for the first workout',
|
||||
'image': 'https://example.org/trophy.png',
|
||||
'trophy_type': 'count',
|
||||
'is_hidden': false,
|
||||
'is_progressive': true,
|
||||
};
|
||||
|
||||
@GenerateMocks([WgerBaseProvider])
|
||||
void main() {
|
||||
group('Trophies providers', () {
|
||||
test('trophies provider returns list of Trophy models', () async {
|
||||
// Arrange
|
||||
final mockBase = MockWgerBaseProvider();
|
||||
when(mockBase.fetchPaginated(any)).thenAnswer((_) async => [trophyJson]);
|
||||
when(
|
||||
mockBase.makeUrl(
|
||||
any,
|
||||
id: anyNamed('id'),
|
||||
objectMethod: anyNamed('objectMethod'),
|
||||
query: anyNamed('query'),
|
||||
),
|
||||
).thenReturn(Uri.parse('https://example.org/trophies'));
|
||||
|
||||
final container = ProviderContainer.test(
|
||||
overrides: [
|
||||
wgerBaseProvider.overrideWithValue(mockBase),
|
||||
],
|
||||
);
|
||||
|
||||
// Act
|
||||
final result = await container.read(trophiesProvider.future);
|
||||
|
||||
// Assert
|
||||
expect(result, isA<List>());
|
||||
expect(result, hasLength(1));
|
||||
final trophy = result.first;
|
||||
expect(trophy.id, 1);
|
||||
expect(trophy.name, 'First Steps');
|
||||
expect(trophy.type.toString(), contains('count'));
|
||||
});
|
||||
|
||||
test('trophyProgression provider returns list of UserTrophyProgression models', () async {
|
||||
// Arrange
|
||||
final progressionJson = {
|
||||
'trophy': trophyJson,
|
||||
'is_earned': true,
|
||||
'earned_at': '2020-01-02T15:04:05Z',
|
||||
'progress': 42.5,
|
||||
'current_value': '12.5',
|
||||
'target_value': '100',
|
||||
'progress_display': '12.5/100',
|
||||
};
|
||||
|
||||
final mockBase = MockWgerBaseProvider();
|
||||
when(mockBase.fetchPaginated(any)).thenAnswer((_) async => [progressionJson]);
|
||||
when(
|
||||
mockBase.makeUrl(
|
||||
any,
|
||||
id: anyNamed('id'),
|
||||
objectMethod: anyNamed('objectMethod'),
|
||||
query: anyNamed('query'),
|
||||
),
|
||||
).thenReturn(Uri.parse('https://example.org/user_progressions'));
|
||||
final container = ProviderContainer.test(
|
||||
overrides: [
|
||||
wgerBaseProvider.overrideWithValue(mockBase),
|
||||
],
|
||||
);
|
||||
|
||||
// Act
|
||||
final result = await container.read(trophyProgressionProvider.future);
|
||||
|
||||
// Assert
|
||||
expect(result, isA<List>());
|
||||
expect(result, hasLength(1));
|
||||
final p = result.first;
|
||||
expect(p.isEarned, isTrue);
|
||||
expect(p.progress, 42.5);
|
||||
expect(p.currentValue, 12.5);
|
||||
expect(p.progressDisplay, '12.5/100');
|
||||
|
||||
verify(mockBase.fetchPaginated(any)).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
183
test/trophies/trophies_provider_test.mocks.dart
Normal file
183
test/trophies/trophies_provider_test.mocks.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (c) 2025 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Mocks generated by Mockito 5.4.6 from annotations
|
||||
// in wger/test/trophies/trophies_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:http/http.dart' as _i3;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:wger/providers/auth.dart' as _i2;
|
||||
import 'package:wger/providers/base_provider.dart' as _i4;
|
||||
|
||||
// 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: deprecated_member_use
|
||||
// ignore_for_file: deprecated_member_use_from_same_package
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
// ignore_for_file: must_be_immutable
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: subtype_of_sealed_class
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
class _FakeAuthProvider_0 extends _i1.SmartFake implements _i2.AuthProvider {
|
||||
_FakeAuthProvider_0(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeClient_1 extends _i1.SmartFake implements _i3.Client {
|
||||
_FakeClient_1(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeUri_2 extends _i1.SmartFake implements Uri {
|
||||
_FakeUri_2(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeResponse_3 extends _i1.SmartFake implements _i3.Response {
|
||||
_FakeResponse_3(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
/// A class which mocks [WgerBaseProvider].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
MockWgerBaseProvider() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_i2.AuthProvider get auth =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#auth),
|
||||
returnValue: _FakeAuthProvider_0(this, Invocation.getter(#auth)),
|
||||
)
|
||||
as _i2.AuthProvider);
|
||||
|
||||
@override
|
||||
_i3.Client get client =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#client),
|
||||
returnValue: _FakeClient_1(this, Invocation.getter(#client)),
|
||||
)
|
||||
as _i3.Client);
|
||||
|
||||
@override
|
||||
set auth(_i2.AuthProvider? value) => super.noSuchMethod(
|
||||
Invocation.setter(#auth, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set client(_i3.Client? value) => super.noSuchMethod(
|
||||
Invocation.setter(#client, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, String> getDefaultHeaders({bool? includeAuth = false}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getDefaultHeaders, [], {
|
||||
#includeAuth: includeAuth,
|
||||
}),
|
||||
returnValue: <String, String>{},
|
||||
)
|
||||
as Map<String, String>);
|
||||
|
||||
@override
|
||||
Uri makeUrl(
|
||||
String? path, {
|
||||
int? id,
|
||||
String? objectMethod,
|
||||
Map<String, dynamic>? query,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#makeUrl,
|
||||
[path],
|
||||
{#id: id, #objectMethod: objectMethod, #query: query},
|
||||
),
|
||||
returnValue: _FakeUri_2(
|
||||
this,
|
||||
Invocation.method(
|
||||
#makeUrl,
|
||||
[path],
|
||||
{#id: id, #objectMethod: objectMethod, #query: query},
|
||||
),
|
||||
),
|
||||
)
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i5.Future<dynamic> fetch(Uri? uri) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetch, [uri]),
|
||||
returnValue: _i5.Future<dynamic>.value(),
|
||||
)
|
||||
as _i5.Future<dynamic>);
|
||||
|
||||
@override
|
||||
_i5.Future<List<dynamic>> fetchPaginated(Uri? uri) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetchPaginated, [uri]),
|
||||
returnValue: _i5.Future<List<dynamic>>.value(<dynamic>[]),
|
||||
)
|
||||
as _i5.Future<List<dynamic>>);
|
||||
|
||||
@override
|
||||
_i5.Future<Map<String, dynamic>> post(Map<String, dynamic>? data, Uri? uri) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#post, [data, uri]),
|
||||
returnValue: _i5.Future<Map<String, dynamic>>.value(
|
||||
<String, dynamic>{},
|
||||
),
|
||||
)
|
||||
as _i5.Future<Map<String, dynamic>>);
|
||||
|
||||
@override
|
||||
_i5.Future<Map<String, dynamic>> patch(
|
||||
Map<String, dynamic>? data,
|
||||
Uri? uri,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#patch, [data, uri]),
|
||||
returnValue: _i5.Future<Map<String, dynamic>>.value(
|
||||
<String, dynamic>{},
|
||||
),
|
||||
)
|
||||
as _i5.Future<Map<String, dynamic>>);
|
||||
|
||||
@override
|
||||
_i5.Future<_i3.Response> deleteRequest(String? url, int? id) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#deleteRequest, [url, id]),
|
||||
returnValue: _i5.Future<_i3.Response>.value(
|
||||
_FakeResponse_3(
|
||||
this,
|
||||
Invocation.method(#deleteRequest, [url, id]),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i5.Future<_i3.Response>);
|
||||
}
|
||||
Reference in New Issue
Block a user