From 1956bd96e46610890cd6dfbad367a025aa29aa44 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Fri, 15 May 2026 11:54:43 +0200 Subject: [PATCH] test: dfx_widget_service + real_unit_account_service (+9 tests) Stage 15 of the coverage push. - dfx_widget_service (5): wallet getter returns appStore.wallet.currentAccount; walletAddress is the EIP-55 hex of the primary address; isAvailable=false without auth token; isAvailable=true once token set; flips back after clearAuthToken - real_unit_account_service (4): getPortfolioHistory GETs /v1/realunit/account/ and parses CHF values scaled by 100; EUR variant uses valueEur; null value treated as 0; returns [] on non-200 (does not throw) --- .../service/dfx/dfx_widget_service_test.dart | 66 +++++++++++ .../dfx/real_unit_account_service_test.dart | 109 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 test/packages/service/dfx/dfx_widget_service_test.dart create mode 100644 test/packages/service/dfx/real_unit_account_service_test.dart diff --git a/test/packages/service/dfx/dfx_widget_service_test.dart b/test/packages/service/dfx/dfx_widget_service_test.dart new file mode 100644 index 00000000..2ec086a9 --- /dev/null +++ b/test/packages/service/dfx/dfx_widget_service_test.dart @@ -0,0 +1,66 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:realunit_wallet/packages/repository/cache_repository.dart'; +import 'package:realunit_wallet/packages/service/app_store.dart'; +import 'package:realunit_wallet/packages/service/dfx/dfx_widget_service.dart'; +import 'package:realunit_wallet/packages/service/session_cache.dart'; +import 'package:realunit_wallet/packages/wallet/wallet.dart'; + +class _MockAppStore extends Mock implements AppStore {} + +class _MockCacheRepository extends Mock implements CacheRepository {} + +const _testMnemonic = + 'test test test test test test test test test test test junk'; + +void main() { + late _MockAppStore appStore; + late SessionCache sessionCache; + late SoftwareWallet wallet; + + setUp(() { + appStore = _MockAppStore(); + sessionCache = SessionCache(_MockCacheRepository()); + wallet = SoftwareWallet(1, 'Main', _testMnemonic); + when(() => appStore.sessionCache).thenReturn(sessionCache); + when(() => appStore.wallet).thenReturn(wallet); + }); + + group('$DfxWidgetService', () { + test('wallet getter returns appStore.wallet.currentAccount', () { + final service = DfxWidgetService(appStore); + + expect(service.wallet, same(wallet.currentAccount)); + }); + + test('walletAddress is the EIP-55 hex of the current account primaryAddress', () { + final service = DfxWidgetService(appStore); + + // Hardhat #0 EIP-55. + expect( + service.walletAddress, + '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + ); + }); + + test('isAvailable=false when no auth token is set', () { + expect(DfxWidgetService(appStore).isAvailable, isFalse); + }); + + test('isAvailable=true once an auth token is set', () { + sessionCache.setAuthToken('jwt-1'); + + expect(DfxWidgetService(appStore).isAvailable, isTrue); + }); + + test('isAvailable flips back to false after clearAuthToken', () { + sessionCache.setAuthToken('jwt-1'); + final service = DfxWidgetService(appStore); + expect(service.isAvailable, isTrue); + + sessionCache.clearAuthToken(); + + expect(service.isAvailable, isFalse); + }); + }); +} diff --git a/test/packages/service/dfx/real_unit_account_service_test.dart b/test/packages/service/dfx/real_unit_account_service_test.dart new file mode 100644 index 00000000..807bce78 --- /dev/null +++ b/test/packages/service/dfx/real_unit_account_service_test.dart @@ -0,0 +1,109 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:realunit_wallet/packages/config/api_config.dart'; +import 'package:realunit_wallet/packages/config/network_mode.dart'; +import 'package:realunit_wallet/packages/service/app_store.dart'; +import 'package:realunit_wallet/packages/service/dfx/real_unit_account_service.dart'; +import 'package:realunit_wallet/packages/wallet/wallet.dart'; +import 'package:realunit_wallet/styles/currency.dart'; + +class _MockAppStore extends Mock implements AppStore {} + +const _testMnemonic = + 'test test test test test test test test test test test junk'; + +Map _summary({ + double? chf, + double? eur, + String balance = '0', + String timestamp = '2026-01-01T00:00:00Z', +}) => + { + 'address': '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', + 'addressType': 0, + 'balance': '0', + 'lastUpdated': '2026-01-01T00:00:00Z', + 'historicalBalances': [ + { + 'balance': balance, + 'timestamp': timestamp, + 'valueChf': chf, + 'valueEur': eur, + }, + ], + }; + +void main() { + late _MockAppStore appStore; + late SoftwareWallet wallet; + + setUp(() { + appStore = _MockAppStore(); + wallet = SoftwareWallet(1, 'Main', _testMnemonic); + when(() => appStore.wallet).thenReturn(wallet); + when(() => appStore.apiConfig) + .thenReturn(const ApiConfig(networkMode: NetworkMode.mainnet)); + }); + + RealUnitAccountService build(http.Client client) { + when(() => appStore.httpClient).thenReturn(client); + return RealUnitAccountService(appStore); + } + + group('$RealUnitAccountService', () { + test('getPortfolioHistory GETs /v1/realunit/account/ and parses CHF values', () async { + String? path; + final client = MockClient((request) async { + path = request.url.path; + return http.Response( + jsonEncode(_summary(chf: 12.34, balance: '1000000')), + 200, + ); + }); + + final points = await build(client).getPortfolioHistory(Currency.chf); + + expect(points, hasLength(1)); + // 12.34 CHF → 1234 rappen (×100). + expect(points.single.value, BigInt.from(1234)); + expect(points.single.balance, BigInt.from(1000000)); + expect(points.single.time, DateTime.utc(2026, 1, 1)); + // Path uses EIP-55 hex of the Hardhat #0 address. + expect(path, '/v1/realunit/account/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'); + }); + + test('getPortfolioHistory uses EUR values when Currency.eur is requested', () async { + final client = MockClient((_) async => http.Response( + jsonEncode(_summary(chf: 12.34, eur: 11.50)), + 200, + )); + + final points = await build(client).getPortfolioHistory(Currency.eur); + + expect(points.single.value, BigInt.from(1150)); + }); + + test('getPortfolioHistory treats a null value as 0', () async { + final client = MockClient((_) async => http.Response( + jsonEncode(_summary(chf: null)), + 200, + )); + + final points = await build(client).getPortfolioHistory(Currency.chf); + + expect(points.single.value, BigInt.zero); + }); + + test('getPortfolioHistory returns [] on non-200 (does not throw)', () async { + final client = MockClient((_) async => http.Response('boom', 500)); + + final points = await build(client).getPortfolioHistory(Currency.chf); + + expect(points, isEmpty); + }); + }); +}