diff --git a/frontend/lib/features/account/account_page.dart b/frontend/lib/features/account/account_page.dart index 93660424..6df6a46c 100644 --- a/frontend/lib/features/account/account_page.dart +++ b/frontend/lib/features/account/account_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_starter/features/account/account_did_page.dart'; +import 'package:flutter_starter/features/account/account_vc_page.dart'; class AccountPage extends StatelessWidget { const AccountPage({super.key}); @@ -11,15 +12,27 @@ class AccountPage extends StatelessWidget { body: ListView( children: [ ListTile( - title: const Text('My DID'), - trailing: const Icon(Icons.chevron_right), - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const AccountDidPage(), - ), - ); - }), + title: const Text('My DID'), + trailing: const Icon(Icons.chevron_right), + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const AccountDidPage(), + ), + ); + }, + ), + ListTile( + title: const Text('My verifiable credential'), + trailing: const Icon(Icons.chevron_right), + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const AccountVCPage(), + ), + ); + }, + ), ], ), ); diff --git a/frontend/lib/features/account/account_providers.dart b/frontend/lib/features/account/account_providers.dart index 17673f5f..90371a1a 100644 --- a/frontend/lib/features/account/account_providers.dart +++ b/frontend/lib/features/account/account_providers.dart @@ -2,3 +2,4 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:web5_flutter/web5_flutter.dart'; final didProvider = Provider((ref) => throw UnimplementedError()); +final vcProvider = StateProvider((ref) => null); diff --git a/frontend/lib/features/account/account_vc_page.dart b/frontend/lib/features/account/account_vc_page.dart new file mode 100644 index 00000000..cb1258c1 --- /dev/null +++ b/frontend/lib/features/account/account_vc_page.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_starter/features/account/account_providers.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class AccountVCPage extends HookConsumerWidget { + const AccountVCPage({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final vc = ref.watch(vcProvider); + + return Scaffold( + appBar: AppBar(title: const Text('My VC')), + body: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Center(child: SelectableText(vc ?? '')), + ), + ); + } +} diff --git a/frontend/lib/features/app/app.dart b/frontend/lib/features/app/app.dart index 62ea4f47..781ada7f 100644 --- a/frontend/lib/features/app/app.dart +++ b/frontend/lib/features/app/app.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_starter/features/app/app_tabs.dart'; +import 'package:flutter_starter/features/onboarding/onboarding_welcome_page.dart'; import 'package:flutter_starter/l10n/app_localizations.dart'; import 'package:flutter_starter/shared/theme/theme.dart'; class App extends StatelessWidget { - const App({super.key}); + final bool onboarding; + const App({required this.onboarding, super.key}); @override Widget build(BuildContext context) { @@ -12,7 +14,7 @@ class App extends StatelessWidget { title: 'DIDPay', theme: lightTheme(context), darkTheme: darkTheme(context), - home: const AppTabs(), + home: onboarding ? const OnboardingWelcomePage() : const AppTabs(), localizationsDelegates: Loc.localizationsDelegates, supportedLocales: const [ Locale('en', ''), diff --git a/frontend/lib/features/home/home_page.dart b/frontend/lib/features/home/home_page.dart index 94dc75d0..48e07728 100644 --- a/frontend/lib/features/home/home_page.dart +++ b/frontend/lib/features/home/home_page.dart @@ -1,41 +1,33 @@ import 'package:flutter/material.dart'; -import 'package:flutter_starter/features/pfis/pfi_providers.dart'; -import 'package:flutter_starter/features/pfis/pfi_verification_page.dart'; +import 'package:flutter_starter/l10n/app_localizations.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:web5_flutter/web5_flutter.dart'; class HomePage extends HookConsumerWidget { const HomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final pfis = ref.watch(pfisProvider); return Scaffold( - appBar: AppBar(title: const Text('Home')), - body: ListView( + appBar: AppBar(title: Text(Loc.of(context).home)), + body: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - ...pfis.map( - (pfi) => ListTile( - title: Text(pfi.name), - subtitle: Text(pfi.didUri), - trailing: const Icon(Icons.chevron_right), - onTap: () async { - final result = await DidDht.resolve(pfi.didUri); - final widgetService = result.didDocument?.service - ?.firstWhere((e) => e.type == 'kyc-widget'); - if (widgetService?.serviceEndpoint != null) { - // ignore: use_build_context_synchronously - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => PfiVerificationPage( - widgetUri: widgetService!.serviceEndpoint, - ), - ), - ); - } - }, - ), - ) + const SizedBox(height: 40), + Text( + 'Balance: \$0.00 USD', + style: Theme.of(context).textTheme.titleLarge, + textAlign: TextAlign.center, + ), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + FilledButton( + onPressed: () {}, child: Text(Loc.of(context).deposit)), + FilledButton(onPressed: () {}, child: Text(Loc.of(context).send)), + ], + ), + const SizedBox(height: 40), ], ), ); diff --git a/frontend/lib/features/onboarding/onboarding_welcome_page.dart b/frontend/lib/features/onboarding/onboarding_welcome_page.dart new file mode 100644 index 00000000..7afdd100 --- /dev/null +++ b/frontend/lib/features/onboarding/onboarding_welcome_page.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_starter/features/pfis/pfis_page.dart'; +import 'package:flutter_starter/l10n/app_localizations.dart'; + +class OnboardingWelcomePage extends StatelessWidget { + const OnboardingWelcomePage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox(height: 40), + Text( + Loc.of(context).welcomeToDIDPay, + style: Theme.of(context).textTheme.displayMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 80), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Text( + Loc.of(context).toSendMoney, + style: Theme.of(context).textTheme.titleLarge, + textAlign: TextAlign.center, + ), + ), + const Spacer(), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: FilledButton( + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const PfisPage(), + fullscreenDialog: true, + ), + ); + }, + child: Text(Loc.of(context).getStarted), + ), + ), + ], + ), + ), + ); + } +} diff --git a/frontend/lib/features/pfis/pfi_confirmation_page.dart b/frontend/lib/features/pfis/pfi_confirmation_page.dart new file mode 100644 index 00000000..20f3c689 --- /dev/null +++ b/frontend/lib/features/pfis/pfi_confirmation_page.dart @@ -0,0 +1,120 @@ +import 'dart:convert'; + +import 'package:collection/collection.dart'; +import 'package:flutter_starter/features/account/account_providers.dart'; +import 'package:flutter_starter/services/service_providers.dart'; +import 'package:flutter_starter/shared/constants.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_starter/features/app/app_tabs.dart'; +import 'package:flutter_starter/features/pfis/pfi.dart'; +import 'package:flutter_starter/l10n/app_localizations.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:web5_flutter/web5_flutter.dart'; + +class PfiConfirmationPage extends HookConsumerWidget { + final Pfi pfi; + final String transactionId; + + const PfiConfirmationPage({ + required this.pfi, + required this.transactionId, + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final vcJwt = ref.watch(vcProvider); + + useEffect(() { + verifyCredential(ref); + return null; + }, []); + + return Scaffold( + body: SafeArea( + child: vcJwt == null ? verifying(context) : verified(context, vcJwt), + ), + ); + } + + Widget verifying(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 40), + Text( + 'Verifying your credentials...', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 40), + const Center(child: CircularProgressIndicator()) + ], + ); + } + + Widget verified(BuildContext context, String vcJwt) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox(height: 40), + Expanded( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Your credentials have been verified!', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 40), + Icon(Icons.check_circle, + size: 80, color: Theme.of(context).colorScheme.primary), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: FilledButton( + onPressed: () { + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (context) => const AppTabs()), + (Route route) => false, + ); + }, + child: Text(Loc.of(context).done), + ), + ), + ], + ); + } + + Future verifyCredential(WidgetRef ref) async { + final result = await DidDht.resolve(pfi.didUri); + final pfiService = + result.didDocument?.service?.firstWhereOrNull((e) => e.type == 'PFI'); + + if (pfiService == null) { + // Add real error handling here... + throw Exception('PFI service endpoint not found'); + } + + var uri = Uri.parse( + '${pfiService.serviceEndpoint}/credential?transaction_id=$transactionId'); + final response = await http.get(uri); + if (response.statusCode != 200) { + // Add real error handling here... + throw Exception('Failed to get credential'); + } + + final jsonResponse = json.decode(response.body); + ref.read(secureStorageProvider).write( + key: Constants.verifiableCredentialKey, value: jsonResponse['jwt']); + ref.read(vcProvider.notifier).state = jsonResponse['jwt']; + } +} diff --git a/frontend/lib/features/pfis/pfi_verification_page.dart b/frontend/lib/features/pfis/pfi_verification_page.dart index 3539165b..60615dcb 100644 --- a/frontend/lib/features/pfis/pfi_verification_page.dart +++ b/frontend/lib/features/pfis/pfi_verification_page.dart @@ -1,14 +1,21 @@ +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_starter/features/pfis/pfi.dart'; +import 'package:flutter_starter/features/pfis/pfi_confirmation_page.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:web5_flutter/web5_flutter.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:flutter/material.dart'; -class PfiVerificationPage extends StatelessWidget { - final String widgetUri; +class PfiVerificationPage extends HookConsumerWidget { + final Pfi pfi; - const PfiVerificationPage({required this.widgetUri, super.key}); + const PfiVerificationPage({required this.pfi, super.key}); @override - Widget build(BuildContext context) { - final fullPath = '$widgetUri?proof=moegrammer&callback_uri=didpay://kyc'; + Widget build(BuildContext context, WidgetRef ref) { + const proof = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; + final controller = WebViewController() ..setBackgroundColor(Theme.of(context).colorScheme.background) ..setNavigationDelegate( @@ -20,15 +27,40 @@ class PfiVerificationPage extends StatelessWidget { onPageFinished: (String url) {}, onWebResourceError: (WebResourceError error) {}, onNavigationRequest: (NavigationRequest request) { - if (request.url.startsWith('didpay://')) { + if (request.url.startsWith('didpay://kyc')) { _handleDidPay(context, request.url); return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), - ) - ..loadRequest(Uri.parse(fullPath)); + ); + + useEffect(() { + Future.microtask(() async { + final result = await DidDht.resolve(pfi.didUri); + final widgetService = result.didDocument?.service + ?.firstWhere((e) => e.type == 'kyc-widget'); + if (widgetService?.serviceEndpoint == null) { + final snackBar = SnackBar( + content: const Text('PFI does not support KYC widget'), + // ignore: use_build_context_synchronously + backgroundColor: Theme.of(context).colorScheme.error, + ); + + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).showSnackBar(snackBar); + return; + } + + final fullPath = + '${widgetService?.serviceEndpoint}?proof=$proof&callback_uri=didpay://kyc'; + + controller.loadRequest(Uri.parse(fullPath)); + }); + + return null; + }, []); return Scaffold( appBar: AppBar(title: const Text('PFI Verification')), @@ -39,11 +71,23 @@ class PfiVerificationPage extends StatelessWidget { } void _handleDidPay(BuildContext context, String url) { - final snackBar = SnackBar( - content: Text('Received custom URL callback: $url'), - ); + final uri = Uri.parse(url); + final transactionId = uri.queryParameters['transaction_id']; + + if (transactionId == null) { + const snackBar = SnackBar( + content: Text('KYC widget did not return transaction id'), + ); + + ScaffoldMessenger.of(context).showSnackBar(snackBar); + return; + } - ScaffoldMessenger.of(context).showSnackBar(snackBar); - Navigator.of(context).pop(); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + PfiConfirmationPage(pfi: pfi, transactionId: transactionId), + ), + ); } } diff --git a/frontend/lib/features/pfis/pfis_page.dart b/frontend/lib/features/pfis/pfis_page.dart new file mode 100644 index 00000000..cb42d70e --- /dev/null +++ b/frontend/lib/features/pfis/pfis_page.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_starter/features/pfis/pfi_providers.dart'; +import 'package:flutter_starter/features/pfis/pfi_verification_page.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class PfisPage extends HookConsumerWidget { + const PfisPage({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final pfis = ref.watch(pfisProvider); + return Scaffold( + appBar: AppBar(title: const Text('Select your PFI')), + body: ListView( + children: [ + ...pfis.map( + (pfi) => ListTile( + title: Text(pfi.name), + subtitle: Text(pfi.didUri), + trailing: const Icon(Icons.chevron_right), + onTap: () async { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => PfiVerificationPage(pfi: pfi), + ), + ); + }, + ), + ) + ], + ), + ); + } +} diff --git a/frontend/lib/l10n/app_en.arb b/frontend/lib/l10n/app_en.arb index b07153a9..191f2cdc 100644 --- a/frontend/lib/l10n/app_en.arb +++ b/frontend/lib/l10n/app_en.arb @@ -1,8 +1,10 @@ { "appName": "DIDPay", - "welcome": "Welcome", + "welcomeToDIDPay": "Welcome to DIDPay", "getStarted": "Get started", - "toSendMoney": "To send money, we need to quickly verify your identity", - "congratsOnYourDid": "Congrats on your new DID!", - "verifyIdentity": "Verify your identity" + "toSendMoney": "To send money, you'll need to verify your identity with a PFI", + "home": "Home", + "done": "Done", + "deposit": "Deposit", + "send": "Send" } diff --git a/frontend/lib/l10n/app_localizations.dart b/frontend/lib/l10n/app_localizations.dart index 13b66b3f..7c96a66c 100644 --- a/frontend/lib/l10n/app_localizations.dart +++ b/frontend/lib/l10n/app_localizations.dart @@ -97,11 +97,11 @@ abstract class Loc { /// **'DIDPay'** String get appName; - /// No description provided for @welcome. + /// No description provided for @welcomeToDIDPay. /// /// In en, this message translates to: - /// **'Welcome'** - String get welcome; + /// **'Welcome to DIDPay'** + String get welcomeToDIDPay; /// No description provided for @getStarted. /// @@ -112,20 +112,32 @@ abstract class Loc { /// No description provided for @toSendMoney. /// /// In en, this message translates to: - /// **'To send money, we need to quickly verify your identity'** + /// **'To send money, you\'ll need to verify your identity with a PFI'** String get toSendMoney; - /// No description provided for @congratsOnYourDid. + /// No description provided for @home. /// /// In en, this message translates to: - /// **'Congrats on your new DID!'** - String get congratsOnYourDid; + /// **'Home'** + String get home; - /// No description provided for @verifyIdentity. + /// No description provided for @done. /// /// In en, this message translates to: - /// **'Verify your identity'** - String get verifyIdentity; + /// **'Done'** + String get done; + + /// No description provided for @deposit. + /// + /// In en, this message translates to: + /// **'Deposit'** + String get deposit; + + /// No description provided for @send. + /// + /// In en, this message translates to: + /// **'Send'** + String get send; } class _LocDelegate extends LocalizationsDelegate { diff --git a/frontend/lib/l10n/app_localizations_en.dart b/frontend/lib/l10n/app_localizations_en.dart index 2bde8c33..b912097b 100644 --- a/frontend/lib/l10n/app_localizations_en.dart +++ b/frontend/lib/l10n/app_localizations_en.dart @@ -8,17 +8,23 @@ class LocEn extends Loc { String get appName => 'DIDPay'; @override - String get welcome => 'Welcome'; + String get welcomeToDIDPay => 'Welcome to DIDPay'; @override String get getStarted => 'Get started'; @override - String get toSendMoney => 'To send money, we need to quickly verify your identity'; + String get toSendMoney => 'To send money, you\'ll need to verify your identity with a PFI'; @override - String get congratsOnYourDid => 'Congrats on your new DID!'; + String get home => 'Home'; @override - String get verifyIdentity => 'Verify your identity'; + String get done => 'Done'; + + @override + String get deposit => 'Deposit'; + + @override + String get send => 'Send'; } diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart index 60e1c754..5f8359ca 100644 --- a/frontend/lib/main.dart +++ b/frontend/lib/main.dart @@ -3,6 +3,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_starter/features/account/account_providers.dart'; import 'package:flutter_starter/features/app/app.dart'; import 'package:flutter_starter/services/service_providers.dart'; +import 'package:flutter_starter/shared/constants.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:web5_flutter/web5_flutter.dart'; @@ -16,12 +17,14 @@ void main() async { final keyManager = SecureStorageKeyManager(storage: storage); final did = await getOrCreateDid(keyManager, storage); + final vc = await storage.read(key: Constants.verifiableCredentialKey); + runApp(ProviderScope( overrides: [ - secureStorage.overrideWithValue(storage), + secureStorageProvider.overrideWithValue(storage), didProvider.overrideWithValue(did), ], - child: const App(), + child: App(onboarding: vc == null), )); } @@ -29,13 +32,12 @@ Future getOrCreateDid( KeyManager keyManager, FlutterSecureStorage storage, ) async { - const didUriKey = 'did.uri'; - final didUri = await storage.read(key: didUriKey); + final didUri = await storage.read(key: Constants.didUriKey); if (didUri != null) { return DidJwk(uri: didUri, keyManager: keyManager); } final did = await DidJwk.create(keyManager: keyManager); - await storage.write(key: didUriKey, value: did.uri); + await storage.write(key: Constants.didUriKey, value: did.uri); return did; } diff --git a/frontend/lib/services/service_providers.dart b/frontend/lib/services/service_providers.dart index d319e381..03c602c7 100644 --- a/frontend/lib/services/service_providers.dart +++ b/frontend/lib/services/service_providers.dart @@ -1,5 +1,5 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -final secureStorage = +final secureStorageProvider = Provider((ref) => throw UnimplementedError()); diff --git a/frontend/lib/shared/constants.dart b/frontend/lib/shared/constants.dart new file mode 100644 index 00000000..ec1fe496 --- /dev/null +++ b/frontend/lib/shared/constants.dart @@ -0,0 +1,4 @@ +class Constants { + static const String didUriKey = 'didpay:did.uri'; + static const String verifiableCredentialKey = 'didpay:verifiableCredential'; +} diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index cf3aa9dd..3153db14 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -42,7 +42,7 @@ packages: source: hosted version: "1.1.1" collection: - dependency: transitive + dependency: "direct main" description: name: collection sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a @@ -189,6 +189,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.9" + http: + dependency: "direct main" + description: + name: http + sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" intl: dependency: "direct main" description: diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index 9ce2f88a..a6f2a1b6 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -18,9 +18,11 @@ dependencies: path: packages/web5_flutter ref: main + collection: ^1.18.0 flutter_hooks: ^0.20.3 flutter_secure_storage: ^9.0.0 hooks_riverpod: ^2.4.9 + http: ^1.1.2 intl: ^0.18.1 webview_flutter: ^4.4.2 diff --git a/frontend/test/features/app/app_tabs_test.dart b/frontend/test/features/app/app_tabs_test.dart index 3f5d91f7..e0424560 100644 --- a/frontend/test/features/app/app_tabs_test.dart +++ b/frontend/test/features/app/app_tabs_test.dart @@ -6,7 +6,7 @@ import 'package:flutter_test/flutter_test.dart'; import '../../helpers/widget_helpers.dart'; void main() { - testWidgets('should start on CounterPage', (WidgetTester tester) async { + testWidgets('should start on HomePage', (WidgetTester tester) async { await tester.pumpWidget( WidgetHelpers.testableWidget(child: const AppTabs()), ); @@ -14,7 +14,8 @@ void main() { expect(find.byType(HomePage), findsOneWidget); }); - testWidgets('should show TodosPage when tapped', (WidgetTester tester) async { + testWidgets('should show AccountPage when tapped', + (WidgetTester tester) async { await tester.pumpWidget( WidgetHelpers.testableWidget(child: const AppTabs()), ); diff --git a/frontend/test/features/app/app_test.dart b/frontend/test/features/app/app_test.dart index 652c14ba..84bcf3f9 100644 --- a/frontend/test/features/app/app_test.dart +++ b/frontend/test/features/app/app_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_starter/features/app/app.dart'; -import 'package:flutter_starter/features/app/app_tabs.dart'; +import 'package:flutter_starter/features/onboarding/onboarding_welcome_page.dart'; import 'package:flutter_test/flutter_test.dart'; import '../../helpers/widget_helpers.dart'; @@ -7,9 +7,9 @@ import '../../helpers/widget_helpers.dart'; void main() { testWidgets('should show AppTabs', (WidgetTester tester) async { await tester.pumpWidget( - WidgetHelpers.testableWidget(child: const App()), + WidgetHelpers.testableWidget(child: const App(onboarding: true)), ); - expect(find.byType(AppTabs), findsOneWidget); + expect(find.byType(OnboardingWelcomePage), findsOneWidget); }); }