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

Improve Error Handling Logic in Enter Seed Phrase Screen #22252

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from

Conversation

Parveshdhull
Copy link
Member

@Parveshdhull Parveshdhull commented Mar 6, 2025

fixes #22013
fixes issue 6 in #21970

Originally reported here - #21947 (review)

Video:

signal-2025-03-06-181020.mp4

Affected Area:

All screens that take seed phrase as input

  • On-boarding account creation without keycard
  • On-boarding account creation with keycard
  • Keycard migration
  • Keycard backup flow
  • Wallet create account

status: ready

@status-im-auto
Copy link
Member

status-im-auto commented Mar 6, 2025

Jenkins Builds

Click to see older builds (31)
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 6c9dcee #1 2025-03-06 12:30:30 ~27 min android-e2e 🤖apk 📲
✔️ 6c9dcee #1 2025-03-06 12:30:40 ~27 min tests 📄log
✔️ 6c9dcee #1 2025-03-06 12:35:49 ~33 min android 🤖apk 📲
✔️ 6c9dcee #1 2025-03-06 13:08:32 ~1 hr 5 min ios 📱ipa 📲
da58d9a #2 2025-03-10 08:43:04 ~2 min tests 📄log
✔️ da58d9a #2 2025-03-10 08:48:20 ~8 min android-e2e 🤖apk 📲
✔️ da58d9a #2 2025-03-10 08:48:51 ~8 min android 🤖apk 📲
6ed4fdf #3 2025-03-10 08:53:25 ~4 min ios 📄log
✔️ 6ed4fdf #3 2025-03-10 08:54:13 ~4 min tests 📄log
✔️ 6ed4fdf #3 2025-03-10 08:56:05 ~6 min android-e2e 🤖apk 📲
✔️ 6ed4fdf #3 2025-03-10 08:57:34 ~8 min android 🤖apk 📲
0ac6316 #4 2025-03-10 09:00:17 ~2 min tests 📄log
✔️ 0ac6316 #4 2025-03-10 09:05:47 ~7 min android-e2e 🤖apk 📲
✔️ 0ac6316 #4 2025-03-10 09:06:19 ~8 min android 🤖apk 📲
✔️ 0ac6316 #4 2025-03-10 09:08:35 ~10 min ios 📱ipa 📲
✔️ e0c0ae6 #6 2025-03-10 09:22:14 ~4 min tests 📄log
✔️ e0c0ae6 #6 2025-03-10 09:24:32 ~6 min android-e2e 🤖apk 📲
✔️ e0c0ae6 #6 2025-03-10 09:25:03 ~7 min android 🤖apk 📲
✔️ e0c0ae6 #6 2025-03-10 09:28:17 ~10 min ios 📱ipa 📲
✔️ c266132 #7 2025-03-10 10:09:11 ~4 min tests 📄log
✔️ c266132 #7 2025-03-10 10:11:08 ~6 min android-e2e 🤖apk 📲
✔️ c266132 #7 2025-03-10 10:12:49 ~8 min android 🤖apk 📲
✔️ c266132 #7 2025-03-10 10:14:10 ~9 min ios 📱ipa 📲
✔️ 4146ee8 #8 2025-03-11 05:49:50 ~4 min tests 📄log
✔️ 4146ee8 #8 2025-03-11 05:51:40 ~6 min android-e2e 🤖apk 📲
✔️ 4146ee8 #8 2025-03-11 05:53:19 ~8 min android 🤖apk 📲
✔️ 4146ee8 #8 2025-03-11 05:55:37 ~10 min ios 📱ipa 📲
8a6cfa8 #9 2025-03-11 10:04:55 ~2 min tests 📄log
✔️ 8a6cfa8 #9 2025-03-11 10:09:44 ~7 min android-e2e 🤖apk 📲
✔️ 8a6cfa8 #9 2025-03-11 10:10:18 ~8 min android 🤖apk 📲
✔️ 8a6cfa8 #9 2025-03-11 10:13:17 ~11 min ios 📱ipa 📲
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 21cd6a6 #10 2025-03-11 10:21:26 ~4 min tests 📄log
✔️ 21cd6a6 #10 2025-03-11 10:25:13 ~8 min android-e2e 🤖apk 📲
✔️ 21cd6a6 #10 2025-03-11 10:25:48 ~8 min android 🤖apk 📲
✔️ 21cd6a6 #10 2025-03-11 10:28:29 ~11 min ios 📱ipa 📲
✔️ 55d2298 #11 2025-03-11 16:05:36 ~4 min tests 📄log
✔️ 55d2298 #11 2025-03-11 16:09:06 ~7 min android-e2e 🤖apk 📲
✔️ 55d2298 #11 2025-03-11 16:09:37 ~8 min android 🤖apk 📲
✔️ 55d2298 #11 2025-03-11 16:11:02 ~9 min ios 📱ipa 📲

@flexsurfer
Copy link
Member

hey @Parveshdhull im not sure if it relevant but in create profile (keycard) flow there is a button
image

also i think this check should be conditional, in some flows we expect phrase from profile on device
image

@Parveshdhull
Copy link
Member Author

Thank you very much @flexsurfer for checking the PR.

in create profile (keycard) flow there is a button
I will fix it.

also i think this check should be conditional, in some flows we expect phrase from profile on device

Thank you, I will make it conditional

@Parveshdhull Parveshdhull marked this pull request as draft March 6, 2025 13:04
@flexsurfer
Copy link
Member

thank you . this is the issue #22013

@Parveshdhull Parveshdhull force-pushed the fix/recovery-phrase-error branch from 6c9dcee to da58d9a Compare March 10, 2025 08:39
@Parveshdhull Parveshdhull changed the title Display error message when attempting to link an already linked account Improve Error Handling Logic in Enter Seed Phrase Screen Mar 10, 2025
@Parveshdhull Parveshdhull force-pushed the fix/recovery-phrase-error branch 3 times, most recently from 0ac6316 to dd5d37d Compare March 10, 2025 09:16
@Parveshdhull Parveshdhull marked this pull request as ready for review March 10, 2025 09:17
@Parveshdhull Parveshdhull force-pushed the fix/recovery-phrase-error branch from dd5d37d to e0c0ae6 Compare March 10, 2025 09:17
@Parveshdhull
Copy link
Member Author

@flexsurfer @ilmotta PR is ready for review.

Copy link
Member

@flexsurfer flexsurfer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you , left a few comments

Copy link
Member

@flexsurfer flexsurfer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you, good job

@pavloburykh pavloburykh self-assigned this Mar 10, 2025
@status-im-auto
Copy link
Member

71% of end-end tests have passed

Total executed tests: 14
Failed tests: 4
Expected to fail tests: 0
Passed tests: 10
IDs of failed tests: 741840,727231,741839,741841 

Failed tests (4)

Click to expand
  • Rerun failed tests

  • Class TestWalletCollectibles:

    1. test_wallet_send_collectible, id: 741840

    Device 1: Tap on found: Button
    Device 1: Find `CollectibleItemElement` by `xpath`: `//*[@content-desc='collectible-list-item']//*[contains(@text,'BVL')]/../..`

    critical/wallet/test_collectibles.py:104: in test_wallet_send_collectible
        self.wallet_view.get_collectible_element('BVL').click()
    ../views/base_element.py:89: in click
        element = self.find_element()
    ../views/base_element.py:78: in find_element
        raise NoSuchElementException(
     Device 1: CollectibleItemElement by xpath: `//*[@content-desc='collectible-list-item']//*[contains(@text,'BVL')]/../..` is not found on the screen; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception
    



    2. test_wallet_collectibles_balance, id: 741839

    # STEP: Check BVL collectible info and image
    # STEP: Check Glitch Punks collectible info and image

    critical/wallet/test_collectibles.py:94: in test_wallet_collectibles_balance
        self.errors.verify_no_errors()
    base_test_case.py:179: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Device 1: Collectible 'BVL' is not displayed
    E    Device 1: Collectible 'Glitch Punks' is not displayed
    



    3. test_wallet_collectible_send_from_expanded_info_view, id: 741841

    Device 1: Find Button by accessibility id: collectibles-tab
    Device 1: Tap on found: Button

    critical/wallet/test_collectibles.py:150: in test_wallet_collectible_send_from_expanded_info_view
        self.wallet_view.get_collectible_element('Glitch Punks').wait_for_element().click()
    ../views/base_element.py:120: in wait_for_element
        raise TimeoutException(
     Device `1`: `CollectibleItemElement` by` xpath`: `//*[@content-desc='collectible-list-item']//*[contains(@text,'Glitch Punks')]/../..` is not found on the screen after wait_for_element
    



    Class TestWalletOneDevice:

    1. test_wallet_add_remove_regular_account, id: 727231

    # STEP: Adding new regular account
    Device 1: Find Button by accessibility id: add-account

    critical/wallet/test_wallet_mainnet.py:350: in test_wallet_add_remove_regular_account
        self.wallet_view.add_regular_account(account_name=new_account_name)
    ../views/wallet_view.py:245: in add_regular_account
        self.add_account_button.click()
    ../views/base_element.py:91: in click
        element.click()
    ../../../../status-app-prs@tmp/venv/lib/python3.10/site-packages/selenium/webdriver/remote/webelement.py:94: in click
        self._execute(Command.CLICK_ELEMENT)
    ../../../../status-app-prs@tmp/venv/lib/python3.10/site-packages/selenium/webdriver/remote/webelement.py:395: in _execute
        return self._parent.execute(command, params)
    ../../../../status-app-prs@tmp/venv/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py:345: in execute
        self.error_handler.check_response(response)
    ../../../../status-app-prs@tmp/venv/lib/python3.10/site-packages/appium/webdriver/errorhandler.py:122: in check_response
        raise exception_class(msg=message, stacktrace=format_stacktrace(stacktrace))
     The element 'By.accessibilityId: add-account' is not linked to the same object in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
    E   Stacktrace:
    E   io.appium.uiautomator2.common.exceptions.StaleElementReferenceException: The element 'By.accessibilityId: add-account' is not linked to the same object in DOM anymore
    E   	at io.appium.uiautomator2.model.ElementsCache.restore(ElementsCache.java:122)
    E   	at io.appium.uiautomator2.model.ElementsCache.get(ElementsCache.java:153)
    E   	at io.appium.uiautomator2.handler.Click.safeHandle(Click.java:36)
    E   	at io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:59)
    E   	at io.appium.uiautomator2.server.AppiumServlet.handleRequest(AppiumServlet.java:277)
    E   	at io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:271)
    E   	at io.appium.uiautomator2.http.ServerHandler.channelRead(ServerHandler.java:77)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
    E   	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
    E   	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
    E   	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
    E   	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)
    E   	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
    E   	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
    E   	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
    E   	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
    E   	at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:266)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
    E   	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:345)
    E   	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)
    E   	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)
    E   	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
    E   	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
    E   	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:611)
    E   	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:552)
    E   	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:466)
    E   	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438)
    E   	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
    E   	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
    E   	at java.lang.Thread.run(Thread.java:1012)
    



    Passed tests (10)

    Click to expand

    Class TestCommunityMultipleDeviceMerged:

    1. test_community_message_edit, id: 702843
    Device sessions

    Class TestCommunityOneDeviceMerged:

    1. test_community_copy_and_paste_message_in_chat_input, id: 702742
    Device sessions

    2. test_restore_multiaccount_with_waku_backup_remove_profile_switch, id: 703133
    Device sessions

    Class TestWalletMultipleDevice:

    1. test_wallet_send_asset_from_drawer, id: 727230
    2. test_wallet_send_eth, id: 727229

    Class TestOneToOneChatMultipleSharedDevicesNewUi:

    1. test_1_1_chat_non_latin_messages_stack_update_profile_photo, id: 702745
    Device sessions

    Class TestWalletOneDevice:

    1. test_wallet_swap_flow_mainnet, id: 741555
    2. test_wallet_balance_mainnet, id: 740490
    3. test_wallet_bridge_flow_mainnet, id: 741612
    4. test_wallet_send_flow_mainnet, id: 741554

    @@ -227,10 +230,12 @@

    (defn view
    []
    (let [{:keys [on-success]} (rf/sub [:get-screen-params])]
    (let [{:keys [on-success on-unmount]} (rf/sub [:get-screen-params])]
    Copy link
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    This looks like a smell @Parveshdhull. Fundamentally we shouldn't couple the event and subscription layers with the components lifecycles directly. The subs are a bit more tied, but not really, because re-frame does the heavy lifting based on reactions.

    I don't know if what I'm going to suggest is a good fit, but sometimes, instead of passing opaque callbacks all around, we can pass open/transparent data, which the consumer can contextualize and decide what to do. The tradeoff of this choice might be that the code may not be as general (since a callback can do absolutely anything) but the code can end up being easier to inspect/debug.

    What are your thoughts on this pattern @ulisesmac @clauxx? Do you see a better way?

    Copy link
    Member Author

    @Parveshdhull Parveshdhull Mar 11, 2025

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Hi, Are you suggesting that, instead of passing on-unmount, I pass the onboarding-flow? parameter and then call (rf/dispatch [:onboarding/clear-navigated-to-enter-seed-phrase-from-screen]) on on-unmount when it is true?

    Copy link
    Member Author

    @Parveshdhull Parveshdhull Mar 11, 2025

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Or alternatively, I can remove cleanup call on-unmount and cleanup this state while opening this screen?

    Copy link
    Member Author

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Another solution, instead of passing on-unmount or onboarding-flow?, is to create an additional wrapper view specifically for onboarding. This approach aligns with the DX task - https://www.notion.so/Explicit-is-better-than-implicit-1a78f96fb65c80e4967bfb43f2e09280

    Copy link
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    @ilmotta I think your suggestion is great, and also what @Parveshdhull said about passing onboarding-flow? as param solves it.

    I also don't like to pass callbacks because of their opaqueness, although sometimes it's needed.

    Copy link
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    @Parveshdhull your suggestion to cleanup on mount if it works is usually my preferred choice of cleanup strategy because it's guaranteed any state would converge to the correct state at all times. Cleaning up on exit points tends to be fragile.

    As @ulisesmac said above, I also prefer a more data-driven approach or what you suggest with a wrapper.

    Another solution, instead of passing on-unmount or onboarding-flow?, is to create an additional wrapper view specifically for onboarding.

    This can work well too. If I understood the Notion reference, basically general parts should receive general inputs and the conditional logic should be handled by a more concrete parent/wrapper function or component. If that's the case, makes sense 👍🏼

    @@ -149,21 +139,34 @@
    error-in-words? (or (not last-partial-word-valid?)
    (not butlast-words-valid?))
    upper-case? (boolean (re-find #"[A-Z]" @seed-phrase))
    error (rf/sub [:enter-seed-phrase/error])
    Copy link
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    What is the rationale to prefer the state in the app-db instead of a local state? The local state wouldn't need to cater for unmounting situations. If the error is mostly limited to this component, and also prop drilling wouldn't be an issue, a local state can be better.

    Copy link
    Member Author

    @Parveshdhull Parveshdhull Mar 11, 2025

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Hi @ilmotta,

    Once the seed phrase is validated, we dispatch the on-success function. This function further validates based on the flow. For example:

    • In the account creation flow, the key-uid of the entered seed phrase should not be present in the profiles.
    • In the backup keycard flow, the key-uid of the entered seed phrase should match the key-uid of the current profile.

    Since the validations are happening outside of this screen, it seems simpler to store the error state in the app-db. I could alternatively pass the set-error function, but we’re not supposed to call functions from events. Therefore, I need to create an effect and pass this function to that effect.

    Copy link
    Member Author

    @Parveshdhull Parveshdhull Mar 11, 2025

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Since the validations are happening outside of this screen,

    By the way, I also tried moving the flow-based validation into the screen itself, but it seemed more noisy to me (passing unnecessary data based on the flow, if-else statements, etc.). This approach seems cleaner to me.

    #22252 (comment)

    Copy link
    Member Author

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    UPD: Renamed error to global-error

    Copy link
    Contributor

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    If you tried and you prefer this way I trust your decision! Thanks @Parveshdhull

    @pavloburykh
    Copy link
    Contributor

    Hey @Parveshdhull! Thanks for the PR. I see there are couple unresolved review comments above. Should I wait for approval or PR is ready for testing?

    @Parveshdhull
    Copy link
    Member Author

    Hi @pavloburykh, Thank you very much for taking the PR for testing

    Should I wait for approval or PR is ready for testing?

    Yes, lets wait for @ilmotta's approval.

    @pavloburykh
    Copy link
    Contributor

    Yes, lets wait for @ilmotta's approval.

    Sounds good @Parveshdhull

    Meanwhile, I have a questions and small UI issues:

    QUEStTION:

    According to designs in case of validation error instead of Continue button we should show Enter another recovery phrase button which clears recovery phrase so user can enter it from scratch. Should we implement it in scope of this PR or there is a sepatate issue on this?

    Actual result:

    photo_2025-03-11 11 25 59
    photo_2025-03-11 11 26 01

    Expected result:

    Keycard – Figma 2025-03-11 11-25-29

    @pavloburykh
    Copy link
    Contributor

    ISSUE 1 Validation error has wrong padding in some places

    Actual result:

    Android 12, Samsung Galaxy A 52

    photo_2025-03-11 11 28 20

    IOS 17.6.1, iPhone 15

    photo_2025-03-11 11 29 34

    @Parveshdhull
    Copy link
    Member Author

    Parveshdhull commented Mar 11, 2025

    Thank you @pavloburykh for reporting these issues. Should be fixed now.

    I also updated the validation error message for the keycard migration flow. It was similar to the backup flow, but not exactly the same.

    UPD: Oops I forget to change on-press for "Enter another recovery phrase" (fixed)

    @pavloburykh
    Copy link
    Contributor

    Thank you @Parveshdhull! Both issues are fixed.
    There is a minor problem of validation error background is cut on the right side (see screenshots below). But it can be hadled separately as low priority. It's up to you.

    Same on IOS and Android.

    photo_2025-03-11 17 13 34

    @Parveshdhull
    Copy link
    Member Author

    Parveshdhull commented Mar 11, 2025

    Thank you @pavloburykh should be fixed now.

    Same on IOS and Android.

    It's weird, I don't see the blurred background (with or without cutoff) on my Android & Emulator 🤔

    image

    Copy link
    Contributor

    @ilmotta ilmotta left a comment

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Thank you for engaging in my review feedback @Parveshdhull. Code looks good 💯

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    Status: IN TESTING
    Development

    Successfully merging this pull request may close these issues.

    User can proceed with an another seed phrase during keycard backup
    6 participants