mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-26 10:33:15 +03:00
cleanup
This commit is contained in:
parent
ec232f2c9c
commit
605e70c7c9
@ -1,35 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:yubico_authenticator/core/state.dart';
|
||||
import 'package:yubico_authenticator/oath/views/account_list.dart';
|
||||
import 'package:yubico_authenticator/oath/views/oath_screen.dart';
|
||||
|
||||
import 'oath_test_util.dart';
|
||||
import 'test_util.dart';
|
||||
|
||||
Future<void> addDelay(int ms) async {
|
||||
await Future<void>.delayed(Duration(milliseconds: ms));
|
||||
}
|
||||
|
||||
String generateIssuer(int index) {
|
||||
return 'issuer_${index.toString().padLeft(4, '0')}';
|
||||
}
|
||||
|
||||
String generateName(int index) {
|
||||
return 'name_${index.toString().padLeft(4, '0')}';
|
||||
}
|
||||
|
||||
String base32(int i) {
|
||||
var m = (i % 32);
|
||||
return m < 26 ? String.fromCharCode(65 + m) : '${2 + m - 26}';
|
||||
}
|
||||
|
||||
/// generates 16 chars Base32 string
|
||||
String generateSecret(int index) {
|
||||
return List.generate(16, (_) => base32(index)).toString();
|
||||
}
|
||||
|
||||
void main() {
|
||||
var binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
@ -37,24 +12,24 @@ void main() {
|
||||
var startupParams = {};
|
||||
|
||||
if (isAndroid) {
|
||||
// default android parameters
|
||||
/// default android parameters
|
||||
startupParams = {'dlg.beta.enabled': false, 'delay.startup': 5};
|
||||
testWidgets('Android app boot', (WidgetTester tester) async {
|
||||
// delay first start
|
||||
/// delay first start
|
||||
await tester.startUp(startupParams);
|
||||
// remove delay.startup
|
||||
|
||||
/// remove delay.startup
|
||||
startupParams = {'dlg.beta.enabled': false};
|
||||
});
|
||||
}
|
||||
|
||||
group('OATH UI tests', () {
|
||||
// Validates that expected UI is present
|
||||
group('OATH UI validation', () {
|
||||
testWidgets('Menu items exist', (WidgetTester tester) async {
|
||||
await tester.startUp(startupParams);
|
||||
await tester.tapDeviceButton();
|
||||
expect(find.byKey(OathDeviceMenu.addAccountKey), findsOneWidget);
|
||||
expect(find.byKey(OathDeviceMenu.setManagePasswordKey), findsOneWidget);
|
||||
expect(find.byKey(OathDeviceMenu.resetKey), findsOneWidget);
|
||||
expect(find.byKey(deviceMenuAddAccountKey), findsOneWidget);
|
||||
expect(find.byKey(deviceMenuSetManagePasswordKey), findsOneWidget);
|
||||
expect(find.byKey(deviceMenuResetOathKey), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
@ -82,7 +57,7 @@ void main() {
|
||||
await tester.addAccount(testAccount, quiet: false);
|
||||
});
|
||||
|
||||
// deletes accounts created in previous test
|
||||
/// deletes accounts created in previous test
|
||||
testWidgets('Delete account', (WidgetTester tester) async {
|
||||
await tester.startUp(startupParams);
|
||||
|
||||
@ -97,14 +72,14 @@ void main() {
|
||||
expect(await tester.findAccount(testAccount), isNull);
|
||||
});
|
||||
|
||||
// adds an account, renames, verifies
|
||||
/// adds an account, renames, verifies
|
||||
testWidgets('Rename account', (WidgetTester tester) async {
|
||||
await tester.startUp(startupParams);
|
||||
|
||||
var testAccount =
|
||||
const Account(issuer: 'IssuerToRename', name: 'NameToRename');
|
||||
|
||||
// delete account if it exists
|
||||
/// delete account if it exists
|
||||
await tester.deleteAccount(testAccount);
|
||||
await tester.deleteAccount(
|
||||
const Account(issuer: 'RenamedIssuer', name: 'RenamedName'));
|
||||
@ -115,8 +90,8 @@ void main() {
|
||||
});
|
||||
|
||||
group('OATH Password Quick tests', () {
|
||||
// note that the password groups should be run as whole
|
||||
// this is quick test as we cannot restart android app during 1 testrun
|
||||
/// note that the password groups should be run as whole
|
||||
/// this is quick test as we cannot restart android app during 1 testrun
|
||||
testWidgets('OATH: set oath password', (WidgetTester tester) async {
|
||||
await tester.startUp(startupParams);
|
||||
await tester.setOathPassword('aaa111');
|
||||
@ -124,189 +99,14 @@ void main() {
|
||||
|
||||
/// note - we cannot 'restart' the app to [unlockOathApp]
|
||||
|
||||
/// testWidgets('OATH: replace oath password', (WidgetTester tester) async {
|
||||
/// await tester.startUp(startupParams);
|
||||
/// await tester.replaceOathPassword('aaa111', 'bbb222');
|
||||
/// });
|
||||
|
||||
testWidgets('OATH: remove oath password', (WidgetTester tester) async {
|
||||
await tester.startUp(startupParams);
|
||||
await tester.removeOathPassword('aaa111');
|
||||
});
|
||||
});
|
||||
|
||||
group('OATH Password tests', skip: true, () {
|
||||
/*
|
||||
These tests verify that all oath options are verified to function correctly by:
|
||||
1. setting firsPassword and verifying it
|
||||
2. logging in and changing to secondPassword and verifying it
|
||||
3. changing to thirdPassword
|
||||
4. removing thirdPassword
|
||||
*/
|
||||
testWidgets('OATH: set firstPassword', (WidgetTester tester) async {
|
||||
await tester.startUp();
|
||||
|
||||
var firstPassword = 'aaa111';
|
||||
|
||||
await tester.tapSetOrManagePassword();
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('new oath password')), firstPassword);
|
||||
await tester.pump();
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('confirm oath password')), firstPassword);
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.text('Save'));
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 1000));
|
||||
});
|
||||
testWidgets('OATH: verify firstPassword', (WidgetTester tester) async {
|
||||
await tester.startUp();
|
||||
|
||||
var firstPassword = 'aaa111';
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('oath password')), firstPassword);
|
||||
await tester.pump();
|
||||
|
||||
/// TODO: verification of state here: see that list of accounts is shown
|
||||
await tester.pump(const Duration(milliseconds: 1000));
|
||||
});
|
||||
testWidgets('OATH: set secondPassword', (WidgetTester tester) async {
|
||||
await tester.startUp();
|
||||
|
||||
var firstPassword = 'aaa111';
|
||||
var secondPassword = 'bbb222';
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('oath password')), firstPassword);
|
||||
await tester.pump();
|
||||
await tester.tap(find.byKey(const Key('oath unlock')));
|
||||
|
||||
await tester.tapSetOrManagePassword();
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('current oath password')), firstPassword);
|
||||
await tester.pump();
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('new oath password')), secondPassword);
|
||||
|
||||
await tester.pump();
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('confirm oath password')), secondPassword);
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.text('Save'));
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 1000));
|
||||
});
|
||||
testWidgets('OATH: set thirdPassword', (WidgetTester tester) async {
|
||||
await tester.startUp();
|
||||
|
||||
var secondPassword = 'bbb222';
|
||||
var thirdPassword = 'ccc333';
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('oath password')), secondPassword);
|
||||
await tester.pump();
|
||||
await tester.tap(find.byKey(const Key('oath unlock')));
|
||||
|
||||
await tester.tapSetOrManagePassword();
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('current oath password')), secondPassword);
|
||||
await tester.pump();
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('new oath password')), thirdPassword);
|
||||
await tester.pump();
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('confirm oath password')), thirdPassword);
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.text('Save'));
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 1000));
|
||||
|
||||
/// TODO: verification of state here: see that list of accounts is shown
|
||||
});
|
||||
|
||||
testWidgets('OATH: remove thirdPassword', (WidgetTester tester) async {
|
||||
await tester.startUp();
|
||||
|
||||
var thirdPassword = 'ccc333';
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('oath password')), thirdPassword);
|
||||
await tester.pump();
|
||||
await tester.tap(find.byKey(const Key('oath unlock')));
|
||||
|
||||
await tester.tapSetOrManagePassword();
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('current oath password')), thirdPassword);
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.text('Remove password'));
|
||||
|
||||
/// TODO: verification of state here: see that list of accounts is shown
|
||||
await tester.pump(const Duration(milliseconds: 1000));
|
||||
});
|
||||
});
|
||||
group('TOTP tests', skip: true, () {
|
||||
/*
|
||||
Tests will verify all TOTP functionality, not yet though:
|
||||
1. Add 32 TOTP accounts
|
||||
*/
|
||||
testWidgets('TOTP: Add 32 accounts', skip: true,
|
||||
(WidgetTester tester) async {
|
||||
await tester.startUp();
|
||||
|
||||
for (var i = 0; i < 32; i++) {
|
||||
await tester.tapAddAccount();
|
||||
|
||||
var issuer = generateIssuer(i);
|
||||
var name = generateName(i);
|
||||
var secret = generateSecret(i);
|
||||
|
||||
await tester.enterText(find.byKey(const Key('issuer')), issuer);
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
await tester.enterText(find.byKey(const Key('name')), name);
|
||||
await tester.pump(const Duration(milliseconds: 40));
|
||||
await tester.enterText(find.byKey(const Key('secret')), secret);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.tap(find.byKey(const Key('save_btn')));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
expect(find.byType(OathScreen), findsOneWidget);
|
||||
|
||||
await tester.enterText(
|
||||
find.byKey(const Key('search_accounts')), issuer);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byType(AccountList),
|
||||
matching: find.textContaining(issuer)),
|
||||
findsOneWidget);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
}
|
||||
await tester.pump(const Duration(milliseconds: 3000));
|
||||
/*
|
||||
TODO:
|
||||
await tester.tap(find.byType(FloatingActionButton));
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
await tester.tap(find.text('Reset OATH'));
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
await tester.tap(find.text('Reset'));
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
*/
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -6,17 +6,11 @@ import 'package:yubico_authenticator/oath/views/account_view.dart';
|
||||
|
||||
import 'test_util.dart';
|
||||
|
||||
class OathDeviceMenu {
|
||||
static const addAccountKey = Key('add oath account');
|
||||
static const setManagePasswordKey = Key('set or manage oath password');
|
||||
static const resetKey = Key('reset oath app');
|
||||
}
|
||||
|
||||
// when connecting YubiKey with OATH password
|
||||
/// when connecting YubiKey with OATH password
|
||||
const passwordValidateEditKey = Key('oath password');
|
||||
const unlockOathBtnKey = Key('oath unlock');
|
||||
|
||||
// when setting or changing existing YubiKey OATH password
|
||||
/// when setting or changing existing YubiKey OATH password
|
||||
const newOathPasswordEntryKey = Key('new oath password');
|
||||
const currentOathPasswordEntryKey = Key('current oath password');
|
||||
const confirmOathPasswordEditKey = Key('confirm oath password');
|
||||
@ -29,6 +23,10 @@ const renameAccountBtnSaveKey = Key('oath.dlg.rename_account.btn.save');
|
||||
const renameAccountEditIssuerKey = Key('oath.dlg.rename_account.edit.issuer');
|
||||
const renameAccountEditNameKey = Key('oath.dlg.rename_account.edit.name');
|
||||
|
||||
const deviceMenuAddAccountKey = Key('add oath account');
|
||||
const deviceMenuSetManagePasswordKey = Key('set or manage oath password');
|
||||
const deviceMenuResetOathKey = Key('reset oath app');
|
||||
|
||||
class Account {
|
||||
final String? issuer;
|
||||
final String name;
|
||||
@ -48,14 +46,14 @@ extension OathFunctions on WidgetTester {
|
||||
/// Opens the device menu and taps the "Add account" menu item
|
||||
Future<void> tapAddAccount() async {
|
||||
await tapDeviceButton();
|
||||
await tap(find.byKey(OathDeviceMenu.addAccountKey).hitTestable());
|
||||
await tap(find.byKey(deviceMenuAddAccountKey).hitTestable());
|
||||
await longWait();
|
||||
}
|
||||
|
||||
/// Opens the device menu and taps the "Set/Manage password" menu item
|
||||
Future<void> tapSetOrManagePassword() async {
|
||||
await tapDeviceButton();
|
||||
await tap(find.byKey(OathDeviceMenu.setManagePasswordKey));
|
||||
await tap(find.byKey(deviceMenuSetManagePasswordKey));
|
||||
await longWait();
|
||||
}
|
||||
|
||||
@ -69,8 +67,8 @@ extension OathFunctions on WidgetTester {
|
||||
await tapAddAccount();
|
||||
|
||||
if (isAndroid) {
|
||||
// on android a QR Scanner starts
|
||||
// we want to do a manual addition
|
||||
/// on android a QR Scanner starts
|
||||
/// we want to do a manual addition
|
||||
var manualEntryBtn = find.byKey(qrScannerEnterManuallyKey).hitTestable();
|
||||
if (manualEntryBtn.evaluate().isEmpty) {
|
||||
printToConsole('Allow camera permission');
|
||||
@ -107,8 +105,8 @@ extension OathFunctions on WidgetTester {
|
||||
}
|
||||
|
||||
Finder findAccountList() {
|
||||
// cannot use hitTestable because Toasts block the Account list
|
||||
var accountList = find.byType(AccountList).hitTestable(at: Alignment.topCenter);
|
||||
var accountList =
|
||||
find.byType(AccountList).hitTestable(at: Alignment.topCenter);
|
||||
expect(accountList, findsOneWidget);
|
||||
return accountList;
|
||||
}
|
||||
@ -118,7 +116,7 @@ extension OathFunctions on WidgetTester {
|
||||
}
|
||||
|
||||
Future<AccountView?> findAccount(Account a, {bool quiet = true}) async {
|
||||
// find an AccountView with issuer/name in the account list
|
||||
/// find an AccountView with issuer/name in the account list
|
||||
var matchingAccounts = find.descendant(
|
||||
of: findAccountList(),
|
||||
matching: find.byWidgetPredicate(
|
||||
@ -138,7 +136,7 @@ extension OathFunctions on WidgetTester {
|
||||
}
|
||||
});
|
||||
|
||||
// return the AccountView if there is only one found
|
||||
/// return the AccountView if there is only one found
|
||||
var evaluated = matchingAccounts.evaluate();
|
||||
return evaluated.isEmpty
|
||||
? null
|
||||
@ -159,7 +157,7 @@ extension OathFunctions on WidgetTester {
|
||||
}
|
||||
|
||||
Future<void> deleteAccount(Account a, {bool quiet = true}) async {
|
||||
// only delete account if it exists
|
||||
/// only delete account if it exists
|
||||
var accountView = await findAccount(a);
|
||||
if (accountView == null) {
|
||||
testLog(quiet, 'Account to delete does not exist: $a');
|
||||
@ -172,13 +170,13 @@ extension OathFunctions on WidgetTester {
|
||||
await tap(deleteIconButton);
|
||||
await longWait();
|
||||
|
||||
// TODO check dialog shows correct information about account
|
||||
/// TODO check dialog shows correct information about account
|
||||
var deleteButton = find.byKey(deleteAccountBtnKey).hitTestable();
|
||||
expect(deleteButton, findsOneWidget);
|
||||
await tap(deleteButton);
|
||||
await longWait();
|
||||
|
||||
// try to find account
|
||||
/// try to find account
|
||||
var deletedAccountView = await findAccount(a);
|
||||
expect(deletedAccountView, isNull);
|
||||
if (deletedAccountView == null) {
|
||||
@ -204,7 +202,7 @@ extension OathFunctions on WidgetTester {
|
||||
await tap(renameIconButton);
|
||||
await longWait();
|
||||
|
||||
// fill new info
|
||||
/// fill new info
|
||||
var issuerTextField = find.byKey(renameAccountEditIssuerKey).hitTestable();
|
||||
await tap(issuerTextField);
|
||||
await enterText(issuerTextField, newIssuer ?? '');
|
||||
@ -218,14 +216,14 @@ extension OathFunctions on WidgetTester {
|
||||
await tap(saveButton);
|
||||
await longWait();
|
||||
|
||||
// now the account dialog is shown
|
||||
// TODO verify it shows correct issuer and name
|
||||
/// now the account dialog is shown
|
||||
/// TODO verify it shows correct issuer and name
|
||||
|
||||
// close the account dialog by tapping out of it
|
||||
/// close the account dialog by tapping out of it
|
||||
await tapAt(const Offset(10, 10));
|
||||
await longWait();
|
||||
|
||||
// verify accounts in the list
|
||||
/// verify accounts in the list
|
||||
var renamedAccount = Account(issuer: newIssuer, name: newName);
|
||||
var renamedAccountView = await findAccount(renamedAccount);
|
||||
await shortWait();
|
||||
@ -254,7 +252,32 @@ extension OathFunctions on WidgetTester {
|
||||
await tap(find.byKey(oathPasswordSaveBntKey));
|
||||
await longWait();
|
||||
|
||||
// after tapping Save, the dialog is closed and the save button does not exist
|
||||
/// after tapping Save, the dialog is closed and the save button does not exist
|
||||
expect(find.byKey(oathPasswordSaveBntKey).hitTestable(), findsNothing);
|
||||
}
|
||||
|
||||
Future<void> replaceOathPassword(
|
||||
String currentPassword, String newPassword) async {
|
||||
await tapSetOrManagePassword();
|
||||
|
||||
await shortWait();
|
||||
|
||||
var currentPasswordEntry = find.byKey(currentOathPasswordEntryKey);
|
||||
await tap(currentPasswordEntry);
|
||||
await enterText(currentPasswordEntry, currentPassword);
|
||||
await shortWait();
|
||||
var newPasswordEntry = find.byKey(newOathPasswordEntryKey);
|
||||
await tap(newPasswordEntry);
|
||||
await enterText(newPasswordEntry, newPassword);
|
||||
await shortWait();
|
||||
var confirmPasswordEntry = find.byKey(confirmOathPasswordEditKey);
|
||||
await tap(confirmPasswordEntry);
|
||||
await enterText(confirmPasswordEntry, newPassword);
|
||||
await shortWait();
|
||||
|
||||
await tap(find.byKey(oathPasswordSaveBntKey));
|
||||
await longWait();
|
||||
|
||||
expect(find.byKey(oathPasswordSaveBntKey).hitTestable(), findsNothing);
|
||||
}
|
||||
|
||||
@ -267,7 +290,6 @@ extension OathFunctions on WidgetTester {
|
||||
await tap(unlockButton);
|
||||
await longWait();
|
||||
|
||||
// after unlocking, the unlock button is not hittable
|
||||
expect(find.byKey(unlockOathBtnKey).hitTestable(), findsNothing);
|
||||
}
|
||||
|
||||
@ -283,8 +305,6 @@ extension OathFunctions on WidgetTester {
|
||||
await tap(find.byKey(oathPasswordRemoveBntKey));
|
||||
await longWait();
|
||||
|
||||
// after tapping Save, the dialog is closed and the save button does not exist
|
||||
expect(find.byKey(oathPasswordRemoveBntKey).hitTestable(), findsNothing);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ const veryLongWaitS = 10; // seconds
|
||||
|
||||
extension AppWidgetTester on WidgetTester {
|
||||
|
||||
/// pumping
|
||||
Future<void> shortestWait() async {
|
||||
await pump(const Duration(milliseconds: shortestWaitMs));
|
||||
}
|
||||
@ -48,7 +47,7 @@ extension AppWidgetTester on WidgetTester {
|
||||
if (isAndroid) {
|
||||
return AndroidTestUtils.startUp(this, startUpParams);
|
||||
} else {
|
||||
// desktop
|
||||
/// desktop
|
||||
return await pumpWidget(
|
||||
await getAuthenticatorApp(), const Duration(milliseconds: 2000));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user