mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-19 05:58:50 +02:00
* fix: Generic fixes * fix: Modify hasSufficientFundsForRent to work for spl transactions * feat: Integrate seed verification into integration tests * fix: Adjust workflow file * chore: Remove previous working directory * fix: Revert change * chore: Remove step to setup kvm, already existing in new setup * chore: Remove a couple of steps from workflow * chore: Try switching test commands * fix: Switch back to flutter drive * fix: Flutter error when running tests with Flutter drive * feat: Add screenshots to individual test pages and modify integration test script to add a watch dog to prevent infinite running on CI * feat: Implement transaction success info robot and fix issue with send flow test * fix: Improve integration testing for exchange flow and clean up logic and resulting errors * fix: Handle duplicate words for seeds and test restore through seeds * fix: Optimize implementation for transactions history test * Skip seed verification when in debug and when not in CI flow * chore: Remove print statements and add TODOs * fix: Upgrade version for upload action * fix: Add missing secrets to testing workflow file * fix tests not working in latest main [skip slack] # Conflicts: # lib/src/screens/wallet_keys/wallet_keys_page.dart * add zano seed [skip slack] [run tests] * disable exchange_flow_test.dart [run tests] [skip slack] * Run tests on linux always (since nobody ever used [run tests]) * fix tests after ui updates * [skip slack] tests update * Fixing tests WIP * Fix create wallet integraiton test flow * Update and fix Exchange flow test flow * Switch printV to printToConsole * Adjustments to the the flows on Send and Exchange * feat: Modify Exchange and send tests to fit new flow * fix: - Pause screenshots for now, results in a super large json response file - Fix delay on send bottomsheet because of pumpAndSettle animation - Fix issue with integration test runner script * fix(integration-tests): Fix issues relating to send flow integration tests. This change: - Handles the slider during the send confirmation flow during the send integration test - Adds the missing seeds for the restore flow to the relevant workflow files * feat: Enhance Send flow Automation Integration Test Flow This change: - Updates test wallet address in CommonTestConstants. - Modifies startAppFlow to accept a dynamic key. - Improves waitForSendPage and checkIfSendPageIsVisible methods for better page visibility handling. - Adds validateWalletBalance method to ensure sufficient funds before sending. - Enhances transaction success flow handling in SendPageRobot. * refactor: Update SendPageRobot for improved transaction state handling This change: - Adds support for the TransactionCommitted state in the SendPageRobot. - Removes the handleSendResult method to streamline the send flow. - Enhances checks for successful transaction completion by verifying navigation to the DashboardPage. - Improves visibility handling for the contact addition dialog in the transaction success flow. * chore: Update automated integration test workflow This change: - Updates apkl file naming to use sanitized branch names for better consistency. - Adds a step to output system environment information to aid in troubleshooting. - Enhances KVM setup with checks to see if device exists and there is proper permission. - Adjusts working directory references for Android emulator setup. * chore: Enhance automated integration test workflow This change: - Adds cleanup steps for existing emulator processes to ensure fresh environment. - Updates APK file naming to use sanitized branch names for consistency. - Enhances debug output for APK file creation and searching, improving visibility during the workflow. * chore: Modify apk file renaming step in workflow * chore: Enhance automated integration test workflow This change: - Increases timeout for integration tests to 60 minutes. - Adds a timeout of 90 minutes for the automated integration test job. - Improves KVM setup with detailed checks and outputs for existing device, permissions, and functionality. - Adds system resource checks to provide information on memory, disk space, and CPU cores during the workflow. - Implements error handling for the integration test runner to ensure graceful failure reporting. * chore: Enhance AVD configuration and emulator management in integration test workflow * refactor: Improve transaction history flow tests and item visibility checks This change: - Enhances the scrolling logic in the CommonTestCases to check for item visibility before scrolling. - Adds error handling and logging for transaction history checks in TransactionsPageRobot. - Adds comprehensive item checks and scrolling for more reliable tests. * refactor: Modify integration test runner for improved error handling and logging This change: - Implements error handling and logging throughout the integration test runner. - Introduces a cleanup function for data directories and signal handling. - Enhances test execution with retry logic and detailed duration tracking. - Provides a comprehensive summary of test results, including passed and failed tests with their durations. * refactor: Update error handling in transaction history flow tests * refactor: Remove manual emulator startup logic from integration test workflow This change simplifies the automated integration test workflow by removing the manual emulator startup process, which was previously included to handle cases where no emulator was running. The workflow now focuses on checking the emulator status and gathering device information without attempting to start an emulator manually. * refactor: Enhance integration test workflow and error handling * feat: Add emulator readiness checks and enhance send flow tests This change: - Modifies the send flow test to send $1 worth of any of the wallet currencies - Set up switching between test wallet in case there's zero balance in any of the wallets when the test is run - Add a mini script to check emulator readiness for the tests * fix: More CI workflow errors for the tests * refactor: Update emulator readiness checks and error handling in CI workflow * fix: Readiness check successful but broken pipe when accessing settings service, plus some syntax errors in the workflow * refactor: Enhance integration tests with improved visibility checks and timing adjustments This change: - Adds visibility checks for widgets before interaction in various test flows. - Introduces consistent pump and settle durations to ensure UI stability during tests. - Refines scrolling logic to confirm wallet types are visible before selection. - Updates tap actions to include warnings for missed taps, improving test reliability. * fix: Issues with confirm seeds and keys Automated test * fix: Add missing await for tap calls * fix: Temporarily disable CI workflow and minor cleanup to testflows * fix: Add missing keys to CI workflow * chore: Temporarily disable Automation CI * chore: Cleanup --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
339 lines
11 KiB
Dart
339 lines
11 KiB
Dart
import 'package:cake_wallet/generated/i18n.dart';
|
|
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
|
import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker.dart';
|
|
import 'package:cw_core/crypto_currency.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import '../components/common_test_cases.dart';
|
|
import '../components/common_test_constants.dart';
|
|
import 'auth_page_robot.dart';
|
|
|
|
class ExchangePageRobot {
|
|
ExchangePageRobot(this.tester)
|
|
: commonTestCases = CommonTestCases(tester),
|
|
authPageRobot = AuthPageRobot(tester);
|
|
|
|
WidgetTester tester;
|
|
AuthPageRobot authPageRobot;
|
|
CommonTestCases commonTestCases;
|
|
|
|
Future<void> isExchangePage() async {
|
|
await commonTestCases.isSpecificPage<ExchangePage>();
|
|
await commonTestCases.takeScreenshots('exchange_page');
|
|
await commonTestCases.defaultSleepTime();
|
|
}
|
|
|
|
void hasResetButton() {
|
|
commonTestCases.hasText(S.current.reset);
|
|
}
|
|
|
|
void displaysPresentProviderPicker() {
|
|
commonTestCases.hasType<PresentProviderPicker>();
|
|
}
|
|
|
|
Future<void> displayBothExchangeCards() async {
|
|
final ExchangePage exchangeCard = tester.widget<ExchangePage>(
|
|
find.byType(ExchangePage),
|
|
);
|
|
|
|
final depositKey = exchangeCard.depositKey;
|
|
final receiveKey = exchangeCard.receiveKey;
|
|
|
|
final depositExchangeCard = find.byKey(depositKey);
|
|
expect(depositExchangeCard, findsOneWidget);
|
|
|
|
final receiveExchangeCard = find.byKey(receiveKey);
|
|
expect(receiveExchangeCard, findsOneWidget);
|
|
}
|
|
|
|
void confirmRightComponentsDisplayOnDepositExchangeCards() {
|
|
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
|
final exchangeViewModel = exchangePage.exchangeViewModel;
|
|
final depositCardPrefix = 'deposit_exchange_card';
|
|
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_title_key');
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_currency_picker_button_key');
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_selected_currency_text_key');
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_amount_textfield_key');
|
|
|
|
exchangePage.depositKey.currentState!.changeLimits(min: '0.1');
|
|
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_min_limit_text_key');
|
|
|
|
final initialCurrency = exchangeViewModel.depositCurrency;
|
|
if (initialCurrency.tag != null) {
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_selected_currency_tag_text_key');
|
|
}
|
|
|
|
if (exchangeViewModel.hasAllAmount) {
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_send_all_button_key');
|
|
}
|
|
|
|
if (exchangeViewModel.isMoneroWallet) {
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_address_book_button_key');
|
|
}
|
|
|
|
if (exchangeViewModel.isDepositAddressEnabled) {
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_editable_address_textfield_key');
|
|
} else {
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_non_editable_address_textfield_key');
|
|
commonTestCases.hasValueKey('${depositCardPrefix}_copy_refund_address_button_key');
|
|
}
|
|
|
|
// commonTestCases.hasValueKey('${depositCardPrefix}_max_limit_text_key');
|
|
}
|
|
|
|
void confirmRightComponentsDisplayOnReceiveExchangeCards() {
|
|
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
|
final exchangeViewModel = exchangePage.exchangeViewModel;
|
|
final receiveCardPrefix = 'receive_exchange_card';
|
|
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_title_key');
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_currency_picker_button_key');
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_selected_currency_text_key');
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_amount_textfield_key');
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_min_limit_text_key');
|
|
|
|
final initialCurrency = exchangeViewModel.receiveCurrency;
|
|
if (initialCurrency.tag != null) {
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_selected_currency_tag_text_key');
|
|
}
|
|
|
|
if (exchangeViewModel.hasAllAmount) {
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_send_all_button_key');
|
|
}
|
|
|
|
if (exchangeViewModel.isMoneroWallet) {
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_address_book_button_key');
|
|
}
|
|
|
|
commonTestCases.hasValueKey('${receiveCardPrefix}_editable_address_textfield_key');
|
|
}
|
|
|
|
Future<void> selectDepositCurrency(CryptoCurrency depositCurrency) async {
|
|
final depositPrefix = 'deposit_exchange_card';
|
|
final currencyPickerKey = '${depositPrefix}_currency_picker_button_key';
|
|
final currencyPickerDialogKey = '${depositPrefix}_currency_picker_dialog_button_key';
|
|
|
|
await commonTestCases.tapItemByKey(currencyPickerKey);
|
|
commonTestCases.hasValueKey(currencyPickerDialogKey);
|
|
|
|
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
|
final exchangeViewModel = exchangePage.exchangeViewModel;
|
|
|
|
if (depositCurrency == exchangeViewModel.depositCurrency) {
|
|
await commonTestCases.defaultSleepTime();
|
|
await commonTestCases
|
|
.tapItemByKey('picker_items_index_${depositCurrency.name}_selected_item_button_key');
|
|
return;
|
|
}
|
|
|
|
await commonTestCases.enterText(depositCurrency.name, 'search_bar_widget_key');
|
|
|
|
await commonTestCases.defaultSleepTime();
|
|
|
|
await commonTestCases.tapItemByKey('picker_items_index_${depositCurrency.name}_button_key');
|
|
}
|
|
|
|
Future<void> selectReceiveCurrency(CryptoCurrency receiveCurrency) async {
|
|
final receivePrefix = 'receive_exchange_card';
|
|
final currencyPickerKey = '${receivePrefix}_currency_picker_button_key';
|
|
final currencyPickerDialogKey = '${receivePrefix}_currency_picker_dialog_button_key';
|
|
|
|
await commonTestCases.tapItemByKey(currencyPickerKey);
|
|
commonTestCases.hasValueKey(currencyPickerDialogKey);
|
|
|
|
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
|
final exchangeViewModel = exchangePage.exchangeViewModel;
|
|
|
|
if (receiveCurrency == exchangeViewModel.receiveCurrency) {
|
|
await commonTestCases
|
|
.tapItemByKey('picker_items_index_${receiveCurrency.name}_selected_item_button_key');
|
|
return;
|
|
}
|
|
|
|
await commonTestCases.enterText(receiveCurrency.name, 'search_bar_widget_key');
|
|
|
|
await commonTestCases.defaultSleepTime();
|
|
|
|
await commonTestCases.tapItemByKey('picker_items_index_${receiveCurrency.name}_button_key');
|
|
}
|
|
|
|
Future<void> enterDepositAmount(String amount) async {
|
|
await commonTestCases.enterText(amount, 'deposit_exchange_card_amount_textfield_key');
|
|
}
|
|
|
|
Future<void> enterDepositRefundAddress({String? depositAddress}) async {
|
|
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
|
final exchangeViewModel = exchangePage.exchangeViewModel;
|
|
|
|
if (exchangeViewModel.isDepositAddressEnabled && depositAddress != null) {
|
|
await commonTestCases.enterText(
|
|
depositAddress, 'deposit_exchange_card_editable_address_textfield_key');
|
|
}
|
|
}
|
|
|
|
Future<void> enterReceiveAddress(String receiveAddress) async {
|
|
await commonTestCases.enterText(
|
|
receiveAddress,
|
|
'receive_exchange_card_editable_address_textfield_key',
|
|
);
|
|
await commonTestCases.defaultSleepTime();
|
|
}
|
|
|
|
Future<void> onExchangeButtonPressed() async {
|
|
await commonTestCases.tapItemByKey('exchange_page_exchange_button_key');
|
|
await commonTestCases.defaultSleepTime();
|
|
}
|
|
|
|
bool hasMaxLimitError() {
|
|
final maxErrorText = find.text(S.current.error_text_input_above_maximum_limit);
|
|
|
|
bool hasMaxError = maxErrorText.tryEvaluate();
|
|
|
|
return hasMaxError;
|
|
}
|
|
|
|
bool hasMinLimitError() {
|
|
final minErrorText = find.text(S.current.error_text_input_below_minimum_limit);
|
|
|
|
bool hasMinError = minErrorText.tryEvaluate();
|
|
|
|
return hasMinError;
|
|
}
|
|
|
|
bool hasTradeCreationFailureError() {
|
|
final tradeCreationFailureDialogButton =
|
|
find.byKey(ValueKey('exchange_page_trade_creation_failure_dialog_button_key'));
|
|
|
|
bool hasTradeCreationFailure = tradeCreationFailureDialogButton.tryEvaluate();
|
|
tester.printToConsole('Trade not created error: $hasTradeCreationFailure');
|
|
return hasTradeCreationFailure;
|
|
}
|
|
|
|
Future<void> onTradeCreationFailureDialogButtonPressed() async {
|
|
await commonTestCases.tapItemByKey('exchange_page_trade_creation_failure_dialog_button_key');
|
|
}
|
|
|
|
/// Handling Trade Failure Errors or errors shown through the Failure Dialog.
|
|
///
|
|
/// Simulating the user's flow and response when this error comes up.
|
|
/// Examples are:
|
|
/// - No provider can handle this trade error,
|
|
/// - Trade amount below limit error.
|
|
Future<void> _handleTradeCreationFailureErrors() async {
|
|
tester.printToConsole('Inside trade creation failure handle');
|
|
bool isTradeCreationFailure = false;
|
|
|
|
isTradeCreationFailure = hasTradeCreationFailureError();
|
|
|
|
int maxRetries = 3;
|
|
int retries = 0;
|
|
|
|
while (isTradeCreationFailure && retries < maxRetries) {
|
|
await tester.pumpAndSettle();
|
|
|
|
await onTradeCreationFailureDialogButtonPressed();
|
|
|
|
await commonTestCases.defaultSleepTime(seconds: 5);
|
|
|
|
await onExchangeButtonPressed();
|
|
|
|
await _handleAuthPage();
|
|
|
|
isTradeCreationFailure = hasTradeCreationFailureError();
|
|
retries++;
|
|
}
|
|
}
|
|
|
|
/// Handles the min limit error.
|
|
///
|
|
/// Simulates the user's flow and response when it comes up.
|
|
///
|
|
/// Has a max retry of 20 times.
|
|
Future<void> _handleMinLimitError(String initialAmount) async {
|
|
double amount;
|
|
|
|
amount = double.parse(initialAmount);
|
|
|
|
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
|
final exchangeViewModel = exchangePage.exchangeViewModel;
|
|
|
|
amount = (exchangeViewModel.limits.min ?? 0.0) + 1.0;
|
|
|
|
await enterDepositAmount(amount.toString());
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
await onExchangeButtonPressed();
|
|
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
/// Handles the max limit error.
|
|
///
|
|
/// Simulates the user's flow and response when it comes up.
|
|
///
|
|
/// Has a max retry of 20 times.
|
|
Future<void> _handleMaxLimitError(String initialAmount) async {
|
|
double amount;
|
|
|
|
amount = double.parse(initialAmount);
|
|
|
|
ExchangePage exchangePage = tester.widget(find.byType(ExchangePage));
|
|
final exchangeViewModel = exchangePage.exchangeViewModel;
|
|
|
|
amount = (exchangeViewModel.limits.max ?? 0.0) - 1.0;
|
|
|
|
await enterDepositAmount(amount.toString());
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
await onExchangeButtonPressed();
|
|
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
Future<void> handleErrors(String initialAmount) async {
|
|
await tester.pumpAndSettle();
|
|
|
|
bool isMinLimitError = hasMinLimitError();
|
|
|
|
if (isMinLimitError) {
|
|
tester.printToConsole('Has min limit error');
|
|
await _handleMinLimitError(initialAmount);
|
|
}
|
|
|
|
bool isMaxLimitError = hasMaxLimitError();
|
|
|
|
if (isMaxLimitError) {
|
|
await _handleMaxLimitError(initialAmount);
|
|
}
|
|
|
|
tester.printToConsole('No limits error, proceeding with flow');
|
|
|
|
await _handleAuthPage();
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
await _handleTradeCreationFailureErrors();
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
await commonTestCases.defaultSleepTime();
|
|
}
|
|
|
|
Future<void> _handleAuthPage() async {
|
|
final onAuthPage = authPageRobot.onAuthPage();
|
|
if (onAuthPage) {
|
|
await authPageRobot.enterPinCode(CommonTestConstants.pin);
|
|
}
|
|
|
|
final onAuthPageDesktop = authPageRobot.onAuthPageDesktop();
|
|
if (onAuthPageDesktop) {
|
|
await authPageRobot.enterPassword(CommonTestConstants.pin.join(""));
|
|
}
|
|
}
|
|
}
|