Skip to content

Commit

Permalink
AddCupertinoTesting
Browse files Browse the repository at this point in the history
  • Loading branch information
victor7w7r committed Jul 1, 2024
1 parent 7e804e1 commit 4c6587f
Show file tree
Hide file tree
Showing 22 changed files with 303 additions and 41 deletions.
6 changes: 3 additions & 3 deletions lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import 'package:flutterfly/features/fluent/ui/layout/fluent_layout.dart';
import 'package:flutterfly/features/material/ui/layout/material_layout.dart';

final class App extends StatelessWidget {
const App({super.key, @visibleForTesting this.mockChild});
const App({super.key, this.child});

final Widget? mockChild;
final Widget? child;

@override
Widget build(
Expand All @@ -19,7 +19,7 @@ final class App extends StatelessWidget {
LUViewModel<Platform, DesktopService>(
builder: (final pt, final ctl) {
if (pt.isIos()) {
return mockChild ?? const CupertinoLayout();
return child ?? const CupertinoLayout();
} else if (pt.isAndroid()) {
return const MaterialLayout();
} else if (pt.isDesktop() && ctl.state != 'none') {
Expand Down
7 changes: 3 additions & 4 deletions lib/features/common/ui/pages/desktop_selector_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import 'package:niku/namespace.dart' as n;
Expand Down Expand Up @@ -39,9 +38,9 @@ final class SelectionWrap extends StatelessWidget {
}

final class DesktopSelectorPage extends StatelessWidget {
const DesktopSelectorPage({super.key, @visibleForTesting this.mockChild});
const DesktopSelectorPage({super.key, this.child});

final Widget? mockChild;
final Widget? child;

@override
Widget build(
Expand Down Expand Up @@ -70,7 +69,7 @@ final class DesktopSelectorPage extends StatelessWidget {
..pt = 100)
: SelectionWrap(ctl),
if (inject.get<Platform>().isDesktop())
WindowTitleBar(isDark: true, mockChild: mockChild),
WindowTitleBar(isDark: true, child: child),
]),
),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/features/common/ui/services/data_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ class DataService extends ChangeNotifier {
notifyListeners();
}

String get state => _state;
String state() => _state;
}
6 changes: 3 additions & 3 deletions lib/features/common/ui/widgets/title_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:niku/namespace.dart' as n;

final class WindowTitleBar extends StatelessWidget {
const WindowTitleBar({required this.isDark, this.mockChild, super.key});
const WindowTitleBar({required this.isDark, this.child, super.key});

final Widget? mockChild;
final Widget? child;
final bool isDark;

@override
Expand All @@ -26,7 +26,7 @@ final class WindowTitleBar extends StatelessWidget {
: Colors.white.withOpacity(0.08),
);

return mockChild ??
return child ??
WindowTitleBarBox(
child: n.Row([
Expanded(child: MoveWindow()),
Expand Down
13 changes: 9 additions & 4 deletions lib/features/cupertino/ui/layout/cupertino_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import 'package:flutterfly/features/cupertino/ui/services/cupertino_service.dart
import 'package:flutterfly/features/cupertino/ui/widgets/title.dart';

final class CupertinoLayout extends StatelessWidget {
const CupertinoLayout({super.key});
const CupertinoLayout({super.key, this.child});

final Widget? child;

@override
Widget build(
Expand All @@ -26,7 +28,7 @@ final class CupertinoLayout extends StatelessWidget {
),
home: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: CupTitle(ctl.isDark),
middle: CupTitle(ctl.isDark(), child: child),
),
child: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
Expand All @@ -45,8 +47,11 @@ final class CupertinoLayout extends StatelessWidget {
),
],
),
tabBuilder: (final _, final i) =>
const [HomePage(), CryptoPage(), StorePage()][i],
tabBuilder: (final _, final i) => [
HomePage(child: child),
CryptoPage(child: child),
StorePage(child: child),
][i],
),
),
),
Expand Down
5 changes: 4 additions & 1 deletion lib/features/cupertino/ui/pages/crypto/crypto_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import 'package:flutterfly/features/common/ui/services/binance_service.dart';
import 'package:flutterfly/features/cupertino/ui/pages/crypto/crypto_widgets.dart';

final class CryptoPage extends StatefulWidget {
const CryptoPage({super.key});
const CryptoPage({super.key, this.child});

final Widget? child;

@override
State<CryptoPage> createState() => _CryptoPageState();
Expand Down Expand Up @@ -46,6 +48,7 @@ final class _CryptoPageState extends State<CryptoPage> {
Widget build(
final BuildContext context,
) =>
widget.child ??
ViewModel<BinanceService>(
builder: (final ctl) => BaseQueryBuilder<List<Binance>, FetchException>(
'binance_fetch',
Expand Down
12 changes: 8 additions & 4 deletions lib/features/cupertino/ui/pages/home/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ import 'package:flutterfly/features/cupertino/ui/pages/home/home_widgets.dart';
import 'package:flutterfly/features/cupertino/ui/widgets/theme_toggle.dart';

final class HomePage extends StatelessWidget {
const HomePage({super.key});
const HomePage({super.key, this.child});

final Widget? child;

@override
Widget build(final BuildContext context) => n.Stack([
Widget build(final BuildContext context) =>
child ??
n.Stack([
const ThemeToggle().niku
..top = 70
..right = 0,
Expand All @@ -25,12 +29,12 @@ final class HomePage extends StatelessWidget {
const SizedBox(height: 10),
ListenViewModel<DataService>(
builder: (final ctl) => n.Text(
ctl.state.isEmpty
ctl.state().isEmpty
? 'Store state: Not yet.'
: 'Store state: Yes, you write. ${ctl.state}',
)
..fontSize =
ctl.state.isEmpty ? ((context.mHeight > 960) ? 20 : 15) : 20
ctl.state().isEmpty ? ((context.mHeight > 960) ? 20 : 15) : 20
..n.center,
),
const SizedBox(height: 20),
Expand Down
1 change: 1 addition & 0 deletions lib/features/cupertino/ui/pages/home/home_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ final class DynamicChip extends StatelessWidget {
..width = 77.0
..height = 35.0,
'Flutter Template'.n
..expanded
..freezed
..fontSize = 20,
],
Expand Down
10 changes: 7 additions & 3 deletions lib/features/cupertino/ui/pages/store/store_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import 'package:flutterfly/features/cupertino/ui/services/cupertino_service.dart
import 'package:flutterfly/features/cupertino/ui/widgets/theme_toggle.dart';

final class StorePage extends StatefulWidget {
const StorePage({super.key});
const StorePage({super.key, this.child});

final Widget? child;

@override
State<StorePage> createState() => _StoreState();
Expand Down Expand Up @@ -50,7 +52,9 @@ final class _StoreState extends State<StorePage> {
}

@override
Widget build(final BuildContext context) => GestureDetector(
Widget build(final BuildContext context) =>
widget.child ??
GestureDetector(
onTap: FocusManager.instance.primaryFocus?.unfocus,
child: n.Stack([
const ThemeToggle().niku
Expand Down Expand Up @@ -89,7 +93,7 @@ final class _StoreState extends State<StorePage> {
const SizedBox(height: 20),
ListenViewModel<DataService>(
builder: (final ctl) => n.Text(
ctl.state.isEmpty
ctl.state().isEmpty
? 'Store state: Not yet.'
: 'Store state: Yes, you write. ${ctl.state}',
)
Expand Down
8 changes: 4 additions & 4 deletions lib/features/cupertino/ui/widgets/title.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import 'package:flutterfly/core/utils/platforms.dart';
import 'package:flutterfly/features/common/ui/widgets/title_bar.dart';

final class CupTitle extends StatelessWidget {
const CupTitle(this.dark, {super.key, @visibleForTesting this.mockChild});
const CupTitle(this.dark, {super.key, this.child});

final Widget? mockChild;
final Widget? child;
final bool dark;

@override
Widget build(final BuildContext context) {
if (inject.get<Platform>().isMacOS()) {
return WindowTitleBar(isDark: dark, mockChild: mockChild);
return WindowTitleBar(isDark: dark, child: child);
} else if (!inject.get<Platform>().isDesktop()) {
return 'CupertinoApp'.n..freezed;
} else {
Expand All @@ -24,7 +24,7 @@ final class CupTitle extends StatelessWidget {
..freezed
..mx = 10
..my = 5,
WindowTitleBar(isDark: dark, mockChild: mockChild),
WindowTitleBar(isDark: dark, child: child),
]);
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/features/fluent/ui/pages/home/home_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ final class HomeCardCrypto extends StatelessWidget {
const SizedBox(height: 45),
ListenViewModel<DataService>(
builder: (final ctlData) => n.Text(
ctlData.state.isEmpty
ctlData.state().isEmpty
? 'Store state: Not yet.'
: 'Store state: Yes, you write. ${ctlData.state}',
)
Expand Down
2 changes: 1 addition & 1 deletion lib/features/fluent/ui/pages/store/store_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class _StoreState extends State<StorePage> {
const SizedBox(height: 45),
ListenViewModel<DataService>(
builder: (final ctlData) => n.Text(
ctlData.state.isEmpty
ctlData.state().isEmpty
? 'Store state: Not yet.'
: 'Store state: Yes, you write. '
'${ctlData.state}',
Expand Down
4 changes: 2 additions & 2 deletions lib/features/material/ui/pages/home/home_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ final class TopContent extends StatelessWidget {
const SizedBox(height: 10),
ListenViewModel<DataService>(
builder: (final ctl) => n.Text(
ctl.state.isEmpty
ctl.state().isEmpty
? 'Store state: Not yet.'
: 'Store state: Yes, you write. ${ctl.state}',
)
..fontSize = ctl.state.isEmpty ? ((height > 960) ? 25 : 15) : 20
..fontSize = ctl.state().isEmpty ? ((height > 960) ? 25 : 15) : 20
..n.center,
),
const SizedBox(height: 10),
Expand Down
2 changes: 1 addition & 1 deletion lib/features/material/ui/pages/store/store_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class _StoreState extends State<StorePage> {
const SizedBox(height: 10),
ListenViewModel<DataService>(
builder: (final ctl) => n.Text(
ctl.state.isEmpty
ctl.state().isEmpty
? 'Store state: Not yet.'
: 'Store state: Yes, you write. ${ctl.state}',
)
Expand Down
5 changes: 3 additions & 2 deletions lib/features/material/ui/widgets/navbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ final class NavBar extends StatelessWidget {
leading: inject.get<Platform>().isMacOS() ? Container() : null,
title: inject.get<Platform>().isMacOS()
? ListenViewModel<MaterialService>(
builder: (final ctl) => WindowTitleBar(isDark: ctl.isDark),
builder: (final ctl) => WindowTitleBar(isDark: ctl.isDark()),
)
: n.Stack([
title.n,
if (inject.get<Platform>().isDesktop())
ListenViewModel<MaterialService>(
builder: (final ctl) => WindowTitleBar(isDark: ctl.isDark),
builder: (final ctl) =>
WindowTitleBar(isDark: ctl.isDark()),
),
]),
actions: inject.get<Platform>().isMacOS()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void main() {
when(() => controller.isInitAnim).thenReturn(false);

await tester.pumpWidget(
const MaterialApp(home: DesktopSelectorPage(mockChild: SizedBox())),
const MaterialApp(home: DesktopSelectorPage(child: SizedBox())),
);

when(() => controller.isInitAnim).thenReturn(true);
Expand Down
6 changes: 3 additions & 3 deletions test/features/common/ui/services/data_service_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ void main() {
});

test('Should start with an empty state', () {
expect(dataService.state, isEmpty);
expect(dataService.state(), isEmpty);
});

test('Mutate should update state and notify listeners', () {
Expand All @@ -22,14 +22,14 @@ void main() {
})
..mutate = 'new state';

expect(dataService.state, equals('new state'));
expect(dataService.state(), equals('new state'));
expect(listenerCallCount, 1);
});

test('State getter should return the current state', () {
dataService.mutate = 'another state';

expect(dataService.state, equals('another state'));
expect(dataService.state(), equals('another state'));
});
});
}
46 changes: 46 additions & 0 deletions test/features/cupertino/ui/layout/cupertino_layout_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'package:flutter/cupertino.dart';

import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';
import 'package:mocktail/mocktail.dart';

import 'package:flutterfly/core/utils/platforms.dart';
import 'package:flutterfly/features/cupertino/ui/layout/cupertino_layout.dart';
import 'package:flutterfly/features/cupertino/ui/services/cupertino_service.dart';

class MockPlatform extends Mock implements Platform {}

class MockCupertinoService extends Mock implements CupertinoService {}

void main() {
group('Title', () {
setUp(() async {
await GetIt.I.reset();
GetIt.I.registerSingleton<CupertinoService>(MockCupertinoService());
GetIt.I.registerSingleton<Platform>(Platform());
});

testWidgets('Render widget successfully', (final tester) async {
await tester.runAsync(() async {
final service = GetIt.I.get<CupertinoService>();

when(service.isDark).thenReturn(false);

await tester.pumpWidget(const CupertinoLayout(child: SizedBox()));

expect(find.byType(CupertinoApp), findsOneWidget);
expect(find.byType(CupertinoPageScaffold), findsOneWidget);
expect(find.byType(CupertinoTabScaffold), findsOneWidget);
expect(find.byType(SizedBox), findsAtLeastNWidgets(3));

reset(service);

when(service.isDark).thenReturn(false);

await tester.pumpWidget(const CupertinoLayout(child: SizedBox()));

verify(service.isDark).called(2);
});
});
});
}
Loading

0 comments on commit 4c6587f

Please sign in to comment.