diff --git a/integration_test/add_tokens_test.dart b/integration_test/add_tokens_test.dart index a745e5d13..5e7352043 100644 --- a/integration_test/add_tokens_test.dart +++ b/integration_test/add_tokens_test.dart @@ -59,7 +59,7 @@ void main() { await _addDaypasswordToken(tester); expect(find.byType(DayPasswordTokenWidget), findsOneWidget); await _createFolder(tester); - await tester.pump(const Duration(milliseconds: 100)); + await tester.pump(const Duration(milliseconds: 200)); expect(find.byType(TokenFolderWidget), findsOneWidget); expect(find.text('Folder'), findsOneWidget); expect(find.byType(TokenWidgetBase).hitTestable(), findsNWidgets(3)); diff --git a/integration_test/copy_to_clipboard_test.dart b/integration_test/copy_to_clipboard_test.dart index b343400f9..f46885398 100644 --- a/integration_test/copy_to_clipboard_test.dart +++ b/integration_test/copy_to_clipboard_test.dart @@ -33,7 +33,7 @@ void main() { when(mockTokenFolderRepository.loadFolders()).thenAnswer((_) async => []); when(mockTokenFolderRepository.saveOrReplaceFolders(any)).thenAnswer((_) async => []); }); - testWidgets('AppTest', (tester) async { + testWidgets('Copy to Clipboard Test', (tester) async { await tester.pumpWidget(TestsAppWrapper( overrides: [ settingsProvider.overrideWith((ref) => SettingsNotifier(repository: mockSettingsRepository)), diff --git a/integration_test/rename_and_delete_test.dart b/integration_test/rename_and_delete_test.dart index 552d7bac5..1010f0467 100644 --- a/integration_test/rename_and_delete_test.dart +++ b/integration_test/rename_and_delete_test.dart @@ -37,7 +37,7 @@ void main() { when(mockTokenFolderRepository.loadFolders()).thenAnswer((_) async => []); when(mockTokenFolderRepository.saveOrReplaceFolders(any)).thenAnswer((_) async => []); }); - testWidgets('Rename Token', (tester) async { + testWidgets('Rename and Delete Token', (tester) async { await tester.pumpWidget(TestsAppWrapper( overrides: [ settingsProvider.overrideWith((ref) => SettingsNotifier(repository: mockSettingsRepository)), @@ -46,67 +46,59 @@ void main() { ], child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization), )); - await tester.pumpAndSettle(); - await pumpUntilFindNWidgets(tester, find.byType(HOTPTokenWidget), 1, const Duration(seconds: 10)); - expect(find.byType(HOTPTokenWidget), findsOneWidget); - await tester.drag(find.byType(HOTPTokenWidget), const Offset(-300, 0)); - await tester.pumpAndSettle(); - await pumpUntilFindNWidgets(tester, find.byType(EditHOTPTokenAction), 1, const Duration(seconds: 2)); - await tester.tap(find.byType(EditHOTPTokenAction)); - await tester.pumpAndSettle(); - expect(find.text('Edit Token'), findsOneWidget); - expect(find.byType(TextFormField), findsNWidgets(3)); - await tester.enterText(find.byType(TextFormField).first, 'Renamed Token'); - await tester.tap(find.text('Save')); - await tester.pumpAndSettle(); - expect(find.text('Renamed Token'), findsOneWidget); - }); - testWidgets('Rename Token again', (tester) async { - await tester.pumpWidget(TestsAppWrapper( - overrides: [ - settingsProvider.overrideWith((ref) => SettingsNotifier(repository: mockSettingsRepository)), - tokenProvider.overrideWith((ref) => TokenNotifier(repository: mockTokenRepository)), - tokenFolderProvider.overrideWith((ref) => TokenFolderNotifier(repository: mockTokenFolderRepository)), - ], - child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization), - )); - await tester.pumpAndSettle(); - await pumpUntilFindNWidgets(tester, find.byType(HOTPTokenWidget), 1, const Duration(seconds: 10)); - expect(find.byType(HOTPTokenWidget), findsOneWidget); - await tester.drag(find.byType(HOTPTokenWidget), const Offset(-300, 0)); - await tester.pumpAndSettle(); - await pumpUntilFindNWidgets(tester, find.byType(EditHOTPTokenAction), 1, const Duration(seconds: 2)); - await tester.tap(find.byType(EditHOTPTokenAction)); - await tester.pumpAndSettle(); - expect(find.text('Edit Token'), findsOneWidget); - expect(find.byType(TextFormField), findsNWidgets(3)); - await tester.enterText(find.byType(TextFormField).first, 'Renamed Token again'); - await tester.tap(find.text('Save')); - await tester.pumpAndSettle(); - expect(find.text('Renamed Token again'), findsOneWidget); - }); - testWidgets('Delete Token', (tester) async { - await tester.pumpWidget(TestsAppWrapper( - overrides: [ - settingsProvider.overrideWith((ref) => SettingsNotifier(repository: mockSettingsRepository)), - tokenProvider.overrideWith((ref) => TokenNotifier(repository: mockTokenRepository)), - tokenFolderProvider.overrideWith((ref) => TokenFolderNotifier(repository: mockTokenFolderRepository)), - ], - child: PrivacyIDEAAuthenticator(customization: ApplicationCustomization.defaultCustomization), - )); - await tester.pumpAndSettle(); - await pumpUntilFindNWidgets(tester, find.byType(HOTPTokenWidget), 1, const Duration(seconds: 10)); - expect(find.byType(HOTPTokenWidget), findsOneWidget); - await tester.drag(find.byType(HOTPTokenWidget), const Offset(-300, 0)); - await tester.pumpAndSettle(); - await pumpUntilFindNWidgets(tester, find.byType(EditHOTPTokenAction), 1, const Duration(seconds: 2)); - await tester.tap(find.byType(DefaultDeleteAction)); - await tester.pumpAndSettle(); - expect(find.text('Edit Token'), findsOneWidget); - expect(find.byType(TextFormField), findsNWidgets(3)); - await tester.enterText(find.byType(TextFormField).first, 'Renamed Token'); - await tester.tap(find.text('Save')); - await tester.pumpAndSettle(); - expect(find.text('Renamed Token'), findsOneWidget); + await _renameToken(tester); + await _renameTokenAgain(tester); + await _deleteToken(tester); }); } + +Future _renameToken(WidgetTester tester) async { + // Rename Token + await tester.pumpAndSettle(); + await pumpUntilFindNWidgets(tester, find.byType(HOTPTokenWidget), 1, const Duration(seconds: 10)); + expect(find.byType(HOTPTokenWidget), findsOneWidget); + await tester.drag(find.byType(HOTPTokenWidget), const Offset(-300, 0)); + await tester.pumpAndSettle(); + await pumpUntilFindNWidgets(tester, find.byType(EditHOTPTokenAction), 1, const Duration(seconds: 2)); + await tester.tap(find.byType(EditHOTPTokenAction)); + await tester.pumpAndSettle(); + expect(find.text('Edit Token'), findsOneWidget); + expect(find.byType(TextFormField), findsNWidgets(3)); + await tester.enterText(find.byType(TextFormField).first, 'Renamed Token'); + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + expect(find.text('Renamed Token'), findsOneWidget); +} + +Future _renameTokenAgain(WidgetTester tester) async { + await tester.pumpAndSettle(); + await pumpUntilFindNWidgets(tester, find.byType(HOTPTokenWidget), 1, const Duration(seconds: 10)); + expect(find.byType(HOTPTokenWidget), findsOneWidget); + await tester.drag(find.byType(HOTPTokenWidget), const Offset(-300, 0)); + await tester.pumpAndSettle(); + await pumpUntilFindNWidgets(tester, find.byType(EditHOTPTokenAction), 1, const Duration(seconds: 2)); + await tester.tap(find.byType(EditHOTPTokenAction)); + await tester.pumpAndSettle(); + expect(find.text('Edit Token'), findsOneWidget); + expect(find.byType(TextFormField), findsNWidgets(3)); + await tester.enterText(find.byType(TextFormField).first, 'Renamed Token'); + await tester.tap(find.text('Save')); + await tester.pumpAndSettle(); + expect(find.text('Renamed Token'), findsOneWidget); +} + +Future _deleteToken(WidgetTester tester) async { + await tester.pumpAndSettle(); + await pumpUntilFindNWidgets(tester, find.byType(HOTPTokenWidget), 1, const Duration(seconds: 10)); + expect(find.byType(HOTPTokenWidget), findsOneWidget); + await tester.drag(find.byType(HOTPTokenWidget), const Offset(-300, 0)); + await tester.pumpAndSettle(); + await pumpUntilFindNWidgets(tester, find.byType(EditHOTPTokenAction), 1, const Duration(seconds: 2)); + await tester.tap(find.byType(DefaultDeleteAction)); + await tester.pumpAndSettle(); + expect(find.text('Confirm deletion'), findsOneWidget); + expect(find.text('Delete'), findsOneWidget); + await tester.tap(find.text('Delete')); + await tester.pumpAndSettle(); + expect(find.byType(HOTPTokenWidget), findsNothing); +} diff --git a/lib/state_notifiers/token_notifier.dart b/lib/state_notifiers/token_notifier.dart index 50f089c8c..42bf2a4ac 100644 --- a/lib/state_notifiers/token_notifier.dart +++ b/lib/state_notifiers/token_notifier.dart @@ -363,11 +363,10 @@ class TokenNotifier extends StateNotifier { Logger.warning('Error while parsing RSA public key.', name: 'token_notifier.dart#rolloutPushToken', error: e, stackTrace: s); updateToken(token, (p0) => p0.copyWith(rolloutState: PushTokenRollOutState.parsingResponseFailed)); return false; - } finally { - Logger.info('Roll out successful', name: 'token_notifier.dart#rolloutPushToken'); - updateToken(token, (p0) => p0.copyWith(isRolledOut: true, rolloutState: PushTokenRollOutState.rolloutComplete)); - checkNotificationPermission(); } + Logger.info('Roll out successful', name: 'token_notifier.dart#rolloutPushToken'); + updateToken(token, (p0) => p0.copyWith(isRolledOut: true, rolloutState: PushTokenRollOutState.rolloutComplete)); + checkNotificationPermission(); return true; } else { Logger.warning('Post request on roll out failed.', diff --git a/test/unit_test/state_notifiers/token_notifier_test.dart b/test/unit_test/state_notifiers/token_notifier_test.dart index 3a467e068..036e93cee 100644 --- a/test/unit_test/state_notifiers/token_notifier_test.dart +++ b/test/unit_test/state_notifiers/token_notifier_test.dart @@ -364,6 +364,7 @@ void _testTokenNotifier() { ); final notifier = container.read(testProvider.notifier); expect(await notifier.rolloutPushToken(before.first), true); + await notifier.isLoading; final state = container.read(testProvider); expect(state, isNotNull); expect(state.tokens, after); diff --git a/test_driver/integration_test_utils.dart b/test_driver/integration_test_utils.dart deleted file mode 100644 index f2cc56e27..000000000 --- a/test_driver/integration_test_utils.dart +++ /dev/null @@ -1,73 +0,0 @@ -/* - privacyIDEA Authenticator - - Authors: Timo Sturm - Frank Merkel - Copyright (c) 2017-2023 NetKnights GmbH - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// Imports the Flutter Driver API. - -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -void addTokenRoutine(String name, String secret) { - group('Copy otp value to clipboard', () { - FlutterDriver? driver; - - // Connect to the Flutter driver before running any tests. - setUpAll(() async { - driver = await FlutterDriver.connect(); - }); - - // Close the connection to the driver after the tests have completed. - tearDownAll(() async { - if (driver != null) { - driver!.close(); - } - }); - - test('Click the "add" button', () async { - await driver!.tap(find.byType('PopupMenuButton')); - await driver!.tap(find.text('Add token')); - }); - - test('Enter name and secret', () async { - // Enter the name. - await driver!.tap(find.ancestor(of: find.text('Name'), matching: find.byType('TextFormField'))); - - await driver!.enterText(name); - - // Enter the secret. - await driver!.tap(find.ancestor(of: find.text('Secret'), matching: find.byType('TextFormField'))); - - await driver!.enterText(secret); - }); - - test('Click "add" token', () async { - await driver!.tap(find.text('Add token')); - }); - - test('Assert the token exists', () async { - await driver!.tap(find.text(name)); - }); - }); -} - -Future doLongPress(FlutterDriver driver, SerializableFinder target) async { - // Pressing 2 seconds is needed to start the 'paste' dialog on a text field. - await driver.scroll(target, 0, 0, const Duration(seconds: 2)); - return true; -} diff --git a/test_driver/run_all.dart b/test_driver/run_all.dart deleted file mode 100644 index 3e60fc671..000000000 --- a/test_driver/run_all.dart +++ /dev/null @@ -1,37 +0,0 @@ -/* - privacyIDEA Authenticator - - Authors: Timo Sturm - Frank Merkel - Copyright (c) 2017-2023 NetKnights GmbH - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import 'package:flutter_driver/driver_extension.dart'; -import 'package:privacyidea_authenticator/main_netknights.dart' as app; - -void main() { - // Override the supported locales of the application to prevent buttons having - // different text values. - - // FIXME Find a new way to do this? -// app.PrivacyIDEAAuthenticator.supportedLocales = [Locale('en', '')]; - - // This line enables the extension. - enableFlutterDriverExtension(); - - // Call the `main()` function of the app, or call `runApp` with - // any widget you are interested in testing. - app.main(); -} diff --git a/test_driver/run_all_test.dart b/test_driver/run_all_test.dart deleted file mode 100644 index 0b24dce86..000000000 --- a/test_driver/run_all_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -/* - privacyIDEA Authenticator - - Authors: Timo Sturm - Frank Merkel - Copyright (c) 2017-2023 NetKnights GmbH - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// Imports the Flutter Driver API. - -import 'test_components/add_token_test.dart'; -import 'test_components/copy_to_clipboard_test.dart'; -import 'test_components/rename_and_delete_test.dart'; - -void main() { - addTokenTest(); - renameAndDeleteTest(); -// totpTokenUpdateTest(); // FIXME This fails because of race-conditions! - copyToClipboardTest(); -} diff --git a/test_driver/test_components/add_token_test.dart b/test_driver/test_components/add_token_test.dart deleted file mode 100644 index 727c9cfb8..000000000 --- a/test_driver/test_components/add_token_test.dart +++ /dev/null @@ -1,91 +0,0 @@ -/* - privacyIDEA Authenticator - - Authors: Timo Sturm - Frank Merkel - Copyright (c) 2017-2023 NetKnights GmbH - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// Imports the Flutter Driver API. - -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -void addTokenTest() { - group('Add token manually', () { - FlutterDriver? driver; - - // Connect to the Flutter driver before running any tests. - setUpAll(() async { - driver = await FlutterDriver.connect(); - }); - - // Close the connection to the driver after the tests have completed. - tearDownAll(() async { - if (driver != null) { - driver!.close(); - } - }); - - final buttonFinder = find.byType('PopupMenuButton'); - final addTokenButton = find.text('Add token'); - - test('Click the "add" button', () async { - await driver!.tap(buttonFinder); - await driver!.tap(addTokenButton); - }); - - test('Enter name and secret', () async { - await driver!.tap(find.ancestor(of: find.text('Name'), matching: find.byType('TextFormField'))); - - await driver!.enterText('TestName'); - - await driver!.tap(find.ancestor(of: find.text('Secret'), matching: find.byType('TextFormField'))); - - await driver!.enterText('TestSecret'); - }); - - test('Change token type', () async { - await driver!.tap(find.text('SHA1')); - await driver!.tap(find.text('SHA512')); - - await driver!.tap(find.text('6')); - await driver!.tap(find.text('8')); - }); - - test('Click "add" token', () async { - await driver!.tap(find.text('Add token')); - }); - - test('Assert the token exists', () async { - await driver!.tap(find.text('TestName')); - await driver!.tap(find.text('3058 7488')); - }); - - test('Clean up', () async { - await driver!.scroll(find.text('TestName'), -500, 0, const Duration(milliseconds: 100)); - - // Delete the token. - await driver!.tap(find.text('Delete')); - - // Wait for the dialog to open. - await driver!.waitFor(find.text('Confirm deletion')); - - await driver!.tap(find.text('Delete')); - - await driver!.waitForAbsent(find.text('TestName')); - }); - }); -} diff --git a/test_driver/test_components/copy_to_clipboard_test.dart b/test_driver/test_components/copy_to_clipboard_test.dart deleted file mode 100644 index f86c4fcdc..000000000 --- a/test_driver/test_components/copy_to_clipboard_test.dart +++ /dev/null @@ -1,77 +0,0 @@ -/* - privacyIDEA Authenticator - - Authors: Timo Sturm - Frank Merkel - Copyright (c) 2017-2023 NetKnights GmbH - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// Imports the Flutter Driver API. - -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -import '../integration_test_utils.dart'; - -void copyToClipboardTest() { - group('Copy otp value to clipboard', () { - FlutterDriver? driver; - - // Connect to the Flutter driver before running any tests. - setUpAll(() async { - driver = await FlutterDriver.connect(); - }); - - // Close the connection to the driver after the tests have completed. - tearDownAll(() async { - if (driver != null) { - driver!.close(); - } - }); - - String tokenName = 'TokenName'; - String secret = 'TokenSecret'; - addTokenRoutine(tokenName, secret); - - test('Copy otp value', () async { - await doLongPress(driver!, find.text(tokenName)); - }); - - test('Clean up', () async { - await driver!.scroll(find.text('TokenName'), -500, 0, const Duration(milliseconds: 100)); - - // Delete the token. - await driver!.tap(find.text('Delete')); - - // Wait for the dialog to open. - await driver!.waitFor(find.text('Confirm deletion')); - - await driver!.tap(find.text('Delete')); - - await driver!.waitForAbsent(find.text('TestName')); - }); - - test('Verify value is in clipboard', () async { - await driver!.tap(find.byType('PopupMenuButton')); - await driver!.tap(find.text('Add token')); - - await doLongPress(driver!, find.ancestor(of: find.text('Name'), matching: find.byType('TextFormField'))); - - await driver!.tap(find.text('Paste')); - - await driver!.waitFor(find.text('591668')); - }); - }); -} diff --git a/test_driver/test_components/rename_and_delete_test.dart b/test_driver/test_components/rename_and_delete_test.dart deleted file mode 100644 index 2648735b9..000000000 --- a/test_driver/test_components/rename_and_delete_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -/* - privacyIDEA Authenticator - - Authors: Timo Sturm - Frank Merkel - Copyright (c) 2017-2023 NetKnights GmbH - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// Imports the Flutter Driver API. - -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -import '../integration_test_utils.dart'; - -void renameAndDeleteTest() { - group('Rename and delete', () { - FlutterDriver? driver; - - // Connect to the Flutter driver before running any tests. - setUpAll(() async { - driver = await FlutterDriver.connect(); - }); - - // Close the connection to the driver after the tests have completed. - tearDownAll(() async { - if (driver != null) { - driver!.close(); - } - }); - - String tokenName = 'TokenName'; - String secret = 'TokenSecret'; - addTokenRoutine(tokenName, secret); - - test('Assert renaming works', () async { - await driver!.scroll(find.text(tokenName), -500, 0, const Duration(milliseconds: 100)); - - await driver!.tap(find.text('Rename')); - - // Wait for the dialog to open. - await driver!.waitFor(find.text('Rename token')); - - await driver!.enterText('NewTestName'); - await driver!.tap(find.text('Rename')); - - // Assert new name is shown. - await driver!.tap(find.text('NewTestName')); - }); - - test('Assert renaming works again', () async { - await driver!.scroll(find.text('NewTestName'), -500, 0, const Duration(milliseconds: 100)); - - await driver!.tap(find.text('Rename')); - - // Wait for the dialog to open. - await driver!.waitFor(find.text('Rename token')); - - await driver!.enterText('OldTestName'); - await driver!.tap(find.text('Rename')); - - // Assert new name is shown. - await driver!.tap(find.text('OldTestName')); - }); - - test('Assert delete works', () async { - await driver!.scroll(find.text('OldTestName'), -500, 0, const Duration(milliseconds: 100)); - - // Delete the token. - await driver!.tap(find.text('Delete')); - - // Wait for the dialog to open. - await driver!.waitFor(find.text('Confirm deletion')); - - await driver!.tap(find.text('Delete')); - - await driver!.waitForAbsent(find.text('OldTestName')); - }); - }); -} diff --git a/test_driver/test_components/totp_token_test.dart b/test_driver/test_components/totp_token_test.dart deleted file mode 100644 index b7e65d8f0..000000000 --- a/test_driver/test_components/totp_token_test.dart +++ /dev/null @@ -1,127 +0,0 @@ -/* - privacyIDEA Authenticator - - Authors: Timo Sturm - Frank Merkel - Copyright (c) 2017-2023 NetKnights GmbH - - Licensed under the Apache License, Version 2.0 (the 'License'); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an 'AS IS' BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// Imports the Flutter Driver API. -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:privacyidea_authenticator/model/tokens/totp_token.dart'; -import 'package:privacyidea_authenticator/utils/crypto_utils.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; -import 'package:privacyidea_authenticator/utils/logger.dart'; -import 'package:privacyidea_authenticator/utils/utils.dart'; -import 'package:test/test.dart'; - -void totpTokenUpdateTest() { - group('TOTP token update', () { - FlutterDriver? driver; - - // Connect to the Flutter driver before running any tests. - setUpAll(() async { - driver = await FlutterDriver.connect(); - }); - - // Close the connection to the driver after the tests have completed. - tearDownAll(() async { - if (driver != null) { - driver!.close(); - } - }); - - final buttonFinder = find.byType('PopupMenuButton'); - final addTokenButton = find.text('Add token'); - - test('Click the "add" button', () async { - await driver!.tap(buttonFinder); - await driver!.tap(addTokenButton); - }); - - test('Enter name and secret', () async { - await driver!.tap(find.ancestor(of: find.text('Name'), matching: find.byType('TextFormField'))); - - await driver!.enterText('TOTPTestName'); - - await driver!.tap(find.ancestor(of: find.text('Secret'), matching: find.byType('TextFormField'))); - - await driver!.enterText('TestSecret'); - }); - - test('Change algorithm', () async { - await driver!.tap(find.text('HOTP')); - await driver!.tap(find.text('TOTP')); - }); - - test('Click "add" token', () async { - await driver!.tap(find.text('Add token')); - }); - - test('Assert otp value gets updated', () async { - // The opt value of this token is the same as the one of the added token. - TOTPToken token = TOTPToken( - label: '', - issuer: '', - id: '', - algorithm: Algorithms.SHA1, - digits: 6, - secret: encodeSecretAs(utf8.encode('TestSecret') as Uint8List, Encodings.base32), - period: 30, - ); - - // We have to run this without waiting for all animations to stop - // (the animation loops in this widget) - await driver!.runUnsynchronized(() async { - String rawValue = token.otpValue.padLeft(6, '0'); - String value = insertCharAt(rawValue, ' ', rawValue.length ~/ 2); - Logger.info('1. Value: $value'); - - await driver!.tap(find.text(value)); - }); - - await driver!.runUnsynchronized(() async { - // Wait until update is due. - await Future.delayed(const Duration(seconds: 32)); - - String rawValue = token.otpValue.padLeft(6, '0'); - String value = insertCharAt(rawValue, ' ', rawValue.length ~/ 2); - - Logger.info('2. Value: $value'); - - await driver!.waitFor(find.text(value), timeout: const Duration(seconds: 40)); - }); - }, timeout: const Timeout(Duration(seconds: 60))); - - test('Clean up', () async { - await driver!.runUnsynchronized(() async { - await driver!.scroll(find.text('TOTPTestName'), -500, 0, const Duration(milliseconds: 100)); - - // Delete the token. - await driver!.tap(find.text('Delete')); - - // Wait for the dialog to open. - await driver!.waitFor(find.text('Confirm deletion')); - - await driver!.tap(find.text('Delete')); - - await driver!.waitForAbsent(find.text('TOTPTestName')); - }); - }); - }); -}