Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(cat-voices): integration tests start automating onboarding #1435

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ Wireframes
Wmissing
Wnullable
Woverlength
Writedown
xcassets
xcconfig
xcfilelist
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'package:catalyst_voices/app/view/app.dart';
import 'package:catalyst_voices/configs/bootstrap.dart';
import 'package:catalyst_voices/routes/routes.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';
import 'package:integration_test/integration_test.dart';
import 'package:patrol_finders/patrol_finders.dart';

import 'pageobject/app_bar_page.dart';
import 'pageobject/onboarding_page.dart';

void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
late final GoRouter router;

setUpAll(() async {
router = buildAppRouter();
await bootstrap(router: router);
});

setUp(() async {
await registerDependencies();
router.go(const DiscoveryRoute().location);
});

tearDown(() async {
await restartDependencies();
});

patrolWidgetTest(
'Onboarding - visitor - get started button works',
(PatrolTester $) async {
await $.pumpWidgetAndSettle(App(routerConfig: router));
await $(AppBarPage.getStartedBtn)
.tap(settleTimeout: const Duration(seconds: 10));
expect($(OnboardingPage.registrationInfoPanel), findsOneWidget);
expect($(OnboardingPage.registrationDetailsPanel), findsOneWidget);
},
);

patrolWidgetTest(
'Onboarding - visitor - get started screen looks as expected',
(PatrolTester $) async {
await $.pumpWidgetAndSettle(App(routerConfig: router));
await $(AppBarPage.getStartedBtn)
.tap(settleTimeout: const Duration(seconds: 10));
await OnboardingPage.getStartedScreenLooksAsExpected($);
},
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ import 'package:flutter/material.dart';

class AppBarPage {
static const spacesDrawerButton = Key('DrawerButton');
static const getStartedBtn = Key('GetStartedButton');

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
library dashboard_page;

import 'package:flutter/material.dart';

class CommonPage {
static const decoratorData = Key('DecoratorData');
static const decoratorIconBefore = Key('DecoratorIconBefore');
static const decoratorIconAfter = Key('DecoratorIconAfter');
static const dialogCloseButton = Key('DialogCloseButton');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
library dashboard_page;

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:patrol_finders/patrol_finders.dart';

import '../types/registration_state.dart';
import '../utils/translations_utils.dart';
import 'common_page.dart';

class OnboardingPage {
static const registrationInfoPanel = Key('RegistrationInfoPanel');
static const registrationDetailsPanel = Key('RegistrationDetailsPanel');
static const registrationInfoLearnMoreButton = Key('LearnMoreButton');
static const headerTitle = Key('HeaderTitle');
static const headerSubtitle = Key('HeaderSubtitle');
static const headerBody = Key('HeaderBody');
static const registrationInfoPictureContainer = Key('PictureContainer');
static const registrationInfoTaskPicture = Key('TaskPictureIconBox');
static const registrationDetailsTitle = Key('RegistrationDetailsTitle');
static const registrationDetailsBody = Key('RegistrationDetailsBody');

static Future<String?> infoPartHeaderTitleText(PatrolTester $) async {
return $(registrationInfoPanel).$(headerTitle).text;
}

static Future<String?> infoPartHeaderSubtitleText(PatrolTester $) async {
return $(registrationInfoPanel).$(headerSubtitle).text;
}

static Future<String?> infoPartHeaderBodyText(PatrolTester $) async {
return $(registrationInfoPanel).$(headerBody).text;
}

static Future<String?> infoPartLearnMoreButtonText(PatrolTester $) async {
final child = find.descendant(
of: $(registrationInfoPanel).$(CommonPage.decoratorData),
matching: find.byType(Text),
);
return $(child).text;
}

static Finder infoPartTaskPicture(PatrolTester $) {
final child = find.descendant(
of: $(registrationInfoPanel).$(registrationInfoPictureContainer),
matching: find.byType(IconTheme),
);
return child;
}

static String? detailsPartGetStartedTitle(PatrolTester $) {
final child = find.descendant(
of: $(registrationDetailsPanel).$(registrationDetailsTitle),
matching: find.byType(Text),
);
return $(child).text;
}

static String? detailsPartGetStartedBody(PatrolTester $) {
final child = find.descendant(
of: $(registrationDetailsPanel).$(registrationDetailsBody),
matching: find.byType(Text),
);
return $(child).text;
}

static String? detailsPartGetStartedQuestionText(PatrolTester $) {
return $(registrationDetailsPanel).$(const Key('GetStartedQuestion')).text;
}

static Future<PatrolFinder> detailsPartGetStartedCreateNewBtn(
PatrolTester $,
) async {
return $(registrationDetailsPanel)
.$(const Key('CreateAccountType.createNew'));
}

static Future<PatrolFinder> detailsPartGetStartedRecoverBtn(
PatrolTester $,
) async {
return $(registrationDetailsPanel)
.$(const Key('CreateAccountType.recover'));
}

static Future<void> getStartedScreenLooksAsExpected(PatrolTester $) async {
await registrationInfoPanelLooksAsExpected($, RegistrationState.getStarted);
await registrationDetailsPanelLooksAsExpected(
$,
RegistrationState.getStarted,
);
}

static Future<void> registrationInfoPanelLooksAsExpected(
PatrolTester $,
RegistrationState step,
) async {
switch (step) {
case RegistrationState.getStarted:
expect(await infoPartHeaderTitleText($), T.get('Get Started'));
expect(await infoPartLearnMoreButtonText($), T.get('Learn More'));
expect(infoPartTaskPicture($), findsOneWidget);
break;
case RegistrationState.checkYourKeychain:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.createKeychain:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.keychainCreated:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.keychainRestoreInfo:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.keychainRestoreInput:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.keychainRestoreStart:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.keychainRestoreSuccess:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.mnemonicInput:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.mnemonicVerified:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.mnemonicWritedown:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.passwordInfo:
// TODO: Handle this case.
throw UnimplementedError();
case RegistrationState.passwordInput:
// TODO: Handle this case.
throw UnimplementedError();
}
}

static Future<void> registrationDetailsPanelLooksAsExpected(
PatrolTester $, RegistrationState getStarted,) async {
expect(
detailsPartGetStartedTitle($),
T.get('Welcome to Catalyst'),
);
expect(
detailsPartGetStartedBody($), isNotEmpty,
);
expect(
detailsPartGetStartedQuestionText($),
T.get('What do you want to do?'),
);
expect(
await detailsPartGetStartedCreateNewBtn($),
findsOneWidget,
);
expect(
await detailsPartGetStartedRecoverBtn($),
findsOneWidget,
);
expect(
$(CommonPage.dialogCloseButton),
findsOneWidget,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
enum RegistrationState {
checkYourKeychain,
createKeychain,
getStarted,
keychainCreated,
keychainRestoreInfo,
keychainRestoreInput,
keychainRestoreStart,
keychainRestoreSuccess,
mnemonicInput,
mnemonicVerified,
mnemonicWritedown,
passwordInfo,
passwordInput;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//wrapper that we should adapt to read actual i18n translations we use in the app
//it will also support different locales once we have it
//right now this class is here so we can easily replace this implementation and know where
class T {
static String get(String key, {String? locale}) {
return key;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class GetStartedPanel extends StatelessWidget {
),
const SizedBox(height: 32),
Text(
key: const Key('GetStartedQuestion'),
context.l10n.accountCreationGetStatedWhatNext,
style: theme.textTheme.titleSmall?.copyWith(
color: theme.colors.textOnPrimaryLevel0,
Expand All @@ -40,7 +41,7 @@ class GetStartedPanel extends StatelessWidget {
children: CreateAccountType.values
.map<Widget>((type) {
return RegistrationTile(
key: ValueKey(type),
key: Key(type.toString()),
icon: type._icon,
title: type._getTitle(context.l10n),
subtitle: type._getSubtitle(context.l10n),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class RegistrationDetailsPanel extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocSelector<RegistrationCubit, RegistrationState, RegistrationStep>(
key: const Key('RegistrationDetailsPanel'),
selector: (state) => state.step,
builder: (context, state) {
return switch (state) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class RegistrationInfoPanel extends StatelessWidget {
);

return InformationPanel(
key: const Key('RegistrationInfoPanel'),
title: headerStrings.title,
subtitle: headerStrings.subtitle,
body: headerStrings.body,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class InformationPanel extends StatelessWidget {
body: body,
),
const SizedBox(height: 12),
Expanded(child: Center(child: picture)),
Expanded(key: const Key('PictureContainer'), child: Center(child: picture)),
const SizedBox(height: 12),
_Footer(
progress: progress,
Expand Down Expand Up @@ -64,16 +64,19 @@ class _Header extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
key: const Key('HeaderTitle'),
title,
style: theme.textTheme.titleLarge?.copyWith(color: textColor),
),
if (subtitle != null)
Text(
key: const Key('HeaderSubtitle'),
subtitle,
style: theme.textTheme.titleMedium?.copyWith(color: textColor),
),
if (body != null)
Text(
key: const Key('HeaderBody'),
body,
style: theme.textTheme.bodyMedium?.copyWith(color: textColor),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ class RegistrationStageMessage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DefaultTextStyle(
key: const Key('RegistrationDetailsTitle'),
style: theme.textTheme.titleMedium!.copyWith(color: textColor),
child: title,
),
SizedBox(height: spacing),
DefaultTextStyle(
key: const Key('RegistrationDetailsBody'),
style: theme.textTheme.bodyMedium!.copyWith(color: textColor),
child: subtitle,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class VoicesLearnMoreButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return VoicesTextButton(
key: const Key('LearnMoreButton'),
trailing: VoicesAssets.icons.externalLink.buildIcon(),
onTap: onTap,
child: Text(context.l10n.learnMore),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,17 @@ class AffixDecorator extends StatelessWidget {
children: [
if (prefix != null) ...[
IconTheme(
key: const Key('DecoratorIconBefore'),
data: iconTheme ?? IconTheme.of(context),
child: prefix,
),
SizedBox(width: gap),
],
Flexible(child: child),
Flexible(key: const Key('DecoratorData'),child: child,),
if (suffix != null) ...[
SizedBox(width: gap),
IconTheme(
key: const Key('DecoratorIconAfter'),
data: iconTheme ?? IconTheme.of(context),
child: suffix,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class _DialogCloseButton extends StatelessWidget {
);

return Align(
key: const Key('DialogCloseButton'),
alignment: Alignment.topRight,
child: IconButtonTheme(
data: const IconButtonThemeData(style: buttonStyle),
Expand Down
Loading