Skip to content

Commit

Permalink
test: Introduce widget tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustl22 committed Feb 23, 2024
1 parent a79c207 commit b374765
Show file tree
Hide file tree
Showing 16 changed files with 190 additions and 125 deletions.
78 changes: 78 additions & 0 deletions wrestling_scoreboard_client/lib/app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:wrestling_scoreboard_client/provider/local_preferences.dart';
import 'package:wrestling_scoreboard_client/provider/local_preferences_provider.dart';
import 'package:wrestling_scoreboard_client/routes/router.dart';
import 'package:wrestling_scoreboard_client/services/audio/audio.dart';
import 'package:wrestling_scoreboard_client/view/shortcuts/app_shortcuts.dart';
import 'package:wrestling_scoreboard_client/view/widgets/loading_builder.dart';

class WrestlingScoreboardApp extends ConsumerStatefulWidget {
const WrestlingScoreboardApp({super.key});

@override
ConsumerState<ConsumerStatefulWidget> createState() => WrestlingScoreboardAppState();
}

class WrestlingScoreboardAppState extends ConsumerState<WrestlingScoreboardApp> {
@override
void initState() {
super.initState();

// Need to init to listen to changes of settings.
AudioCache.instance = AudioCache(prefix: '');
HornSound.init();
}

ThemeData _buildTheme(brightness) {
var baseTheme = ThemeData(brightness: brightness);
return baseTheme.copyWith(
textTheme: GoogleFonts.robotoTextTheme(baseTheme.textTheme),
);
}

@override
Widget build(BuildContext context) {
return FutureBuilder<Locale?>(
future: ref.watch(localeNotifierProvider),
builder: (context, localeSnapshot) {
return LoadingBuilder<ThemeMode>(
future: ref.watch(themeModeNotifierProvider),
builder: (context, themeMode) {
final materialApp = MaterialApp.router(
title: AppLocalizations.of(context)?.appName ?? 'Wrestling Scoreboard',
theme: _buildTheme(Brightness.light),
darkTheme: _buildTheme(Brightness.dark),
themeMode: themeMode,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: Preferences.supportedLanguages.values,
locale: localeSnapshot.data,
routerConfig: router,
);
return Shortcuts(
shortcuts: appShortcuts,
child: Consumer(
builder: (context, ref, child) {
return Actions(actions: <Type, Action<Intent>>{
AppActionIntent: CallbackAction<AppActionIntent>(
onInvoke: (AppActionIntent intent) => intent.handle(context, ref),
)
}, child: materialApp);
},
),
);
},
);
},
);
}
}
86 changes: 6 additions & 80 deletions wrestling_scoreboard_client/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:window_manager/window_manager.dart';
import 'package:wrestling_scoreboard_client/provider/local_preferences.dart';
import 'package:wrestling_scoreboard_client/provider/local_preferences_provider.dart';
import 'package:wrestling_scoreboard_client/view/widgets/loading_builder.dart';
import 'package:wrestling_scoreboard_client/routes/router.dart';
import 'package:wrestling_scoreboard_client/view/shortcuts/app_shortcuts.dart';
import 'package:wrestling_scoreboard_client/view/utils.dart';
import 'package:wrestling_scoreboard_client/services/audio/audio.dart';
import 'package:wrestling_scoreboard_client/app.dart';
import 'package:wrestling_scoreboard_client/mocks/main.dart';
import 'package:wrestling_scoreboard_client/utils/environment.dart';
import 'package:wrestling_scoreboard_client/view/utils.dart';

late PackageInfo packageInfo;

const defaultProviderScope = ProviderScope(child: WrestlingScoreboardApp());

void main() async {
// Use [HashUrlStrategy] by default to support Single Page Application without configuring the server.
if (Env.usePathUrlStrategy.fromBool()) {
Expand All @@ -40,72 +33,5 @@ void main() async {
await windowManager.ensureInitialized();
}

runApp(const ProviderScope(child: WrestlingScoreboardApp()));
}

class WrestlingScoreboardApp extends ConsumerStatefulWidget {
const WrestlingScoreboardApp({super.key});

@override
ConsumerState<ConsumerStatefulWidget> createState() => WrestlingScoreboardAppState();
}

class WrestlingScoreboardAppState extends ConsumerState<WrestlingScoreboardApp> {
@override
void initState() {
super.initState();

// Need to init to listen to changes of settings.
AudioCache.instance = AudioCache(prefix: '');
HornSound.init();
}

ThemeData _buildTheme(brightness) {
var baseTheme = ThemeData(brightness: brightness);
return baseTheme.copyWith(
textTheme: GoogleFonts.robotoTextTheme(baseTheme.textTheme),
);
}

@override
Widget build(BuildContext context) {
return FutureBuilder<Locale?>(
future: ref.watch(localeNotifierProvider),
builder: (context, localeSnapshot) {
return LoadingBuilder<ThemeMode>(
future: ref.watch(themeModeNotifierProvider),
builder: (context, themeMode) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
final materialApp = MaterialApp.router(
title: AppLocalizations.of(context)?.appName ?? 'Wrestling Scoreboard',
theme: _buildTheme(Brightness.light),
darkTheme: _buildTheme(Brightness.dark),
themeMode: themeMode,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: Preferences.supportedLanguages.values,
locale: localeSnapshot.data,
routerConfig: router,
);
return Shortcuts(
shortcuts: appShortcuts,
child: Consumer(
builder: (context, ref, child) {
return Actions(actions: <Type, Action<Intent>>{
AppActionIntent: CallbackAction<AppActionIntent>(
onInvoke: (AppActionIntent intent) => intent.handle(context, ref),
)
}, child: materialApp);
},
),
);
},
);
},
);
}
runApp(Env.appEnvironment.fromString() == 'mock' ? mockProviderScope : defaultProviderScope);
}
11 changes: 11 additions & 0 deletions wrestling_scoreboard_client/lib/mocks/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:wrestling_scoreboard_client/app.dart';
import 'package:wrestling_scoreboard_client/mocks/provider/network_provider.dart';
import 'package:wrestling_scoreboard_client/provider/network_provider.dart';

final mockProviderScope = ProviderScope(
overrides: [
dataManagerNotifierProvider.overrideWith(() => MockDataManagerNotifier()),
],
child: const WrestlingScoreboardApp(),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:wrestling_scoreboard_client/mocks/services/network/data_manager.dart';
import 'package:wrestling_scoreboard_client/provider/network_provider.dart';
import 'package:wrestling_scoreboard_client/services/network/data_manager.dart';

part 'network_provider.g.dart';

@Riverpod(keepAlive: true)
class MockDataManagerNotifier extends _$MockDataManagerNotifier implements DataManagerNotifier {
@override
Raw<Future<DataManager>> build() async {
return MockDataManager();
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,7 @@ List<Bout> getBoutsOfTeamMatch(TeamMatch match) {

List<BoutAction> getBoutActions() => _boutActions;

List<BoutAction> getBoutActionsOfBout(Bout bout) =>
getBoutActions().where((element) => element.bout == bout).toList();
List<BoutAction> getBoutActionsOfBout(Bout bout) => getBoutActions().where((element) => element.bout == bout).toList();

List<League> getLeagues() => _leagues;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:math';

import 'package:wrestling_scoreboard_client/mocks/mocks.dart';
import 'package:wrestling_scoreboard_client/services/network/data_provider.dart';
import 'package:wrestling_scoreboard_client/mocks/services/network/data.dart';
import 'package:wrestling_scoreboard_client/services/network/data_manager.dart';
import 'package:wrestling_scoreboard_client/services/network/remote/web_socket.dart';
import 'package:wrestling_scoreboard_common/common.dart';

Expand Down Expand Up @@ -108,8 +108,7 @@ class MockDataManager extends DataManager {
List<WeightClass> weightClasses;
if (wrestlingEvent is TeamMatch) {
final homeParticipations = await readMany<Participation, Lineup>(filterObject: wrestlingEvent.home);
final guestParticipations =
await readMany<Participation, Lineup>(filterObject: wrestlingEvent.guest);
final guestParticipations = await readMany<Participation, Lineup>(filterObject: wrestlingEvent.guest);
teamParticipations = [homeParticipations, guestParticipations];
weightClasses = await readMany<WeightClass, League>(filterObject: wrestlingEvent.league);
} else if (wrestlingEvent is Competition) {
Expand Down Expand Up @@ -394,6 +393,26 @@ class MockDataManager extends DataManager {
}

@override
// TODO: implement webSocketManager
WebSocketManager get webSocketManager => throw UnimplementedError();
WebSocketManager get webSocketManager => MockWebSocketManager((message) {
// TODO: implement messageHandler
return null;
});
}

class MockWebSocketManager implements WebSocketManager {
MockWebSocketManager(this.messageHandler, {String? url}) {
// TODO: implement
}

@override
Function(dynamic message) messageHandler;

@override
addToSink(String val) {
// TODO: implement addToSink
throw UnimplementedError();
}

@override
StreamController<WebSocketConnectionState> onWebSocketConnection = StreamController.broadcast();
}
6 changes: 3 additions & 3 deletions wrestling_scoreboard_client/lib/provider/data_provider.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 2 additions & 8 deletions wrestling_scoreboard_client/lib/provider/network_provider.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:wrestling_scoreboard_client/mocks/mock_data_provider.dart';
import 'package:wrestling_scoreboard_client/provider/local_preferences_provider.dart';
import 'package:wrestling_scoreboard_client/utils/environment.dart';
import 'package:wrestling_scoreboard_client/services/network/data_provider.dart';
import 'package:wrestling_scoreboard_client/services/network/data_manager.dart';
import 'package:wrestling_scoreboard_client/services/network/remote/rest.dart';
import 'package:wrestling_scoreboard_client/services/network/remote/web_socket.dart';

part 'network_provider.g.dart';

final _isMock = Env.appEnvironment.fromString() == 'mock';

@Riverpod(keepAlive: true)
class DataManagerNotifier extends _$DataManagerNotifier {
@override
Raw<Future<DataManager>> build() async {
final apiUrl = await ref.watch(apiUrlNotifierProvider);
final wsUrl = await ref.watch(webSocketUrlNotifierProvider);

// TODO: override with mock via rivperpod overrides.
final dataManager = _isMock ? MockDataManager() : RestDataManager(apiUrl: apiUrl, wsUrl: wsUrl);
return dataManager;
return RestDataManager(apiUrl: apiUrl, wsUrl: wsUrl);
}
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:wrestling_scoreboard_client/services/network/data_provider.dart';
import 'package:wrestling_scoreboard_client/services/network/data_manager.dart';
import 'package:wrestling_scoreboard_client/services/network/remote/url.dart';
import 'package:wrestling_scoreboard_client/services/network/remote/web_socket.dart';
import 'package:wrestling_scoreboard_common/common.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:wrestling_scoreboard_client/provider/network_provider.dart';
import 'package:wrestling_scoreboard_client/services/audio/audio.dart';
import 'package:wrestling_scoreboard_client/services/network/data_provider.dart';
import 'package:wrestling_scoreboard_client/services/network/data_manager.dart';
import 'package:wrestling_scoreboard_common/common.dart';

enum BoutScreenActions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'package:wrestling_scoreboard_client/view/screens/edit/team_match/team_ma
import 'package:wrestling_scoreboard_client/view/screens/overview/common.dart';
import 'package:wrestling_scoreboard_client/view/screens/overview/team_match/team_match_bout_overview.dart';
import 'package:wrestling_scoreboard_client/localization/date_time.dart';
import 'package:wrestling_scoreboard_client/services/network/data_provider.dart';
import 'package:wrestling_scoreboard_client/services/network/data_manager.dart';
import 'package:wrestling_scoreboard_common/common.dart';

class TeamMatchOverview extends ConsumerWidget {
Expand Down
Loading

0 comments on commit b374765

Please sign in to comment.