Repository: joinmarket-webui/joinmarket-webui
Pull request #202 (2022-04-01 09:14:35)

ui: enhance error message on bad request errors
Tiny, tiny PR to get item "Improve wording of error message when trying to send to an 'invalid' address" off the list #66

When sending non-collaborative transactions with an invalid recipient, the api responds with `400 Bad Request` and an error message of `Invalid request format`. 
`InvalidRequestFormat` error is thrown on all assertion errors.. see [wallep_rpc.py#L548](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/fd5871bb2d89e96efe344040b4576627e84fc644/jmclient/jmclient/wallet_rpc.py#L548), but  `Invalid request format` is not really useful for the user and it might not be clear what to do.
As this is an ubiquitous error message, and address validation is avoided on the client side, to give at least a hint about what might be wrong, the message is appended with "Please verify your inputs carefully." so as to know that the error might be related to the given inputs.

The only data sent when initiating a non-collaborative transactions is `mixdepth`, `destination` and `amount_sats` so this error is most definitely raised on invalid addresses. However, the appended message tries to be neutral and advice the user recheck all inputs.
(If there is a problem with the amount, `409 Conflict` with `Transaction failed` is raised)


Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 09130ba..e3c7597 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,14 +14,14 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        node-version: [16]
+        node-version: ['16.11.0']
 
     steps:
       - name: Checkout
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
       # Setup Node
       - name: Setup (Node.js ${{ matrix.node-version }})
-        uses: actions/setup-node@v1
+        uses: actions/setup-node@v3
         with:
           node-version: ${{ matrix.node-version }}
       # Install
diff --git a/.npmrc b/.npmrc
index b4d0cc1..fd341ed 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,1 +1,2 @@
 git-tag-version = false
+engine-strict = true
diff --git a/package.json b/package.json
index faefb03..333250d 100644
--- a/package.json
+++ b/package.json
@@ -6,8 +6,8 @@
   "repository": "git@github.com:joinmarket-webui/joinmarket-webui.git",
   "license": "MIT",
   "engines": {
-    "node": ">=16.0.0",
-    "npm": ">=7.0.0"
+    "node": ">=16.11.0",
+    "npm": ">=8.0.0"
   },
   "homepage": ".",
   "devDependencies": {
diff --git a/src/components/App.jsx b/src/components/App.jsx
index 8420813..f659cff 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -31,6 +31,8 @@ export default function App() {
   const settings = useSettings()
   const websocketState = useWebsocketState()
 
+  const devMode = process.env.NODE_ENV === 'development'
+
   const startWallet = useCallback(
     (name, token) => {
       setSession({ name, token })
@@ -89,7 +91,7 @@ export default function App() {
           <Routes>
             <Route element={<Layout />}>
               <Route exact path="/" element={<Wallets startWallet={startWallet} stopWallet={stopWallet} />} />
-              <Route path="create-wallet" element={<CreateWallet startWallet={startWallet} />} />
+              <Route path="create-wallet" element={<CreateWallet startWallet={startWallet} devMode={devMode} />} />
               {currentWallet && (
                 <>
                   <Route path="send" element={<Send />} />
diff --git a/src/components/CreateWallet.css b/src/components/CreateWallet.css
new file mode 100644
index 0000000..8102e4b
--- /dev/null
+++ b/src/components/CreateWallet.css
@@ -0,0 +1,14 @@
+.create-wallet form input {
+  height: 3.5rem;
+  width: 100%;
+}
+
+.create-wallet button {
+  height: 3rem;
+  width: 100%;
+}
+
+.seedword-index-backup {
+  width: 5ch;
+  justify-content: right;
+}
diff --git a/src/components/CreateWallet.jsx b/src/components/CreateWallet.jsx
index 8ed0727..3c58f37 100644
--- a/src/components/CreateWallet.jsx
+++ b/src/components/CreateWallet.jsx
@@ -8,6 +8,35 @@ import ToggleSwitch from './ToggleSwitch'
 import { serialize, walletDisplayName } from '../utils'
 import { useServiceInfo } from '../context/ServiceInfoContext'
 import * as Api from '../libs/JmWalletApi'
+import './CreateWallet.css'
+
+const PreventLeavingPageByMistake = () => {
+  // prompt users before refreshing or closing the page when this component is present.
+  // Firefox will show: "This page is asking you to confirm that you want to leave [...]"
+  // Chrome: "Leave site? Changes you made may not be saved."
+  useEffect(() => {
+    const abortCtrl = new AbortController()
+
+    window.addEventListener(
+      'beforeunload',
+      (event) => {
+        // cancel the event as stated by the standard.
+        event.preventDefault()
+
+        // Chrome requires returnValue to be set.
+        event.returnValue = ''
+
+        // return something to trigger a dialog
+        return ''
+      },
+      { signal: abortCtrl.signal }
+    )
+
+    return () => abortCtrl.abort()
+  }, [])
+
+  return <></>
+}
 
 const WalletCreationForm = ({ createWallet, isCreating }) => {
   const { t } = useTranslation()
@@ -28,6 +57,7 @@ const WalletCreationForm = ({ createWallet, isCreating }) => {
 
   return (
     <>
+      {isCreating && <PreventLeavingPageByMistake />}
       <rb.Form onSubmit={onSubmit} validated={validated} noValidate>
         <rb.Form.Group className="mb-4" controlId="walletName">
           <rb.Form.Label>{t('create_wallet.label_wallet_name')}</rb.Form.Label>
@@ -102,11 +132,13 @@ const SeedWordInput = ({ number, targetWord, isValid, setIsValid }) => {
   )
 }
 
-const BackupConfirmation = ({ createdWallet, walletConfirmed, parentStepSetter }) => {
+const BackupConfirmation = ({ createdWallet, walletConfirmed, parentStepSetter, devMode }) => {
+  const seedphrase = createdWallet.seedphrase.split(' ')
+
   const { t } = useTranslation()
   const [seedBackup, setSeedBackup] = useState(false)
-  let seedphrase = createdWallet.seedphrase.split(' ')
   const [seedWordConfirmations, setSeedWordConfirmations] = useState(new Array(seedphrase.length).fill(false))
+  const [showSkipButton] = useState(devMode)
 
   useEffect(() => {
     setSeedBackup(seedWordConfirmations.every((wordConfirmed) => wordConfirmed))
@@ -152,9 +184,13 @@ const BackupConfirmation = ({ createdWallet, walletConfirmed, parentStepSetter }
       </rb.Form>
       {seedBackup && <div className="text-center text-success">{t('create_wallet.feedback_seed_confirmed')}</div>}
 
-      <div className="d-flex mt-4 mb-4 gap-3">
+      <rb.Button variant="dark" onClick={() => walletConfirmed()} disabled={!seedBackup}>
+        {t('create_wallet.confirmation_button_fund_wallet')}
+      </rb.Button>
+
+      <div className="d-flex mt-4 mb-4 gap-4">
         <rb.Button
-          variant="dark"
+          variant="outline-dark"
           disabled={seedBackup}
           onClick={() => {
             parentStepSetter()
@@ -163,19 +199,17 @@ const BackupConfirmation = ({ createdWallet, walletConfirmed, parentStepSetter }
           {t('create_wallet.back_button')}
         </rb.Button>
 
-        <rb.Button variant="dark" onClick={() => walletConfirmed()} disabled={!seedBackup}>
-          {t('create_wallet.confirmation_button_fund_wallet')}
-        </rb.Button>
+        {showSkipButton && (
+          <rb.Button variant="outline-dark" onClick={() => walletConfirmed()} disabled={seedBackup}>
+            {t('create_wallet.skip_button')}
+          </rb.Button>
+        )}
       </div>
-
-      <rb.Button variant="outline-dark" onClick={() => walletConfirmed()} disabled={seedBackup}>
-        {t('create_wallet.skip_button')}
-      </rb.Button>
     </div>
   )
 }
 
-const WalletCreationConfirmation = ({ createdWallet, walletConfirmed }) => {
+const WalletCreationConfirmation = ({ createdWallet, walletConfirmed, devMode }) => {
   const { t } = useTranslation()
   const [userConfirmed, setUserConfirmed] = useState(false)
   const [revealSensitiveInfo, setRevealSensitiveInfo] = useState(false)
@@ -189,54 +223,56 @@ const WalletCreationConfirmation = ({ createdWallet, walletConfirmed }) => {
     setStep(0)
   }
 
-  if (step === 0) {
-    return (
-      <div>
-        <div className="mb-4">
-          <div>{t('create_wallet.confirmation_label_wallet_name')}</div>
-          <div className="fs-4">{walletDisplayName(createdWallet.name)}</div>
-        </div>
-        <div className="mb-4">
-          <Seedphrase seedphrase={createdWallet.seedphrase} isBlurred={!revealSensitiveInfo} />
-        </div>
-        <div className="mb-4">
-          <div>{t('create_wallet.confirmation_label_password')}</div>
-          <div className={`fs-4${revealSensitiveInfo ? '' : ' blurred-text'}`}>
-            {!revealSensitiveInfo ? 'randomrandom' : createdWallet.password}
+  return (
+    <>
+      <PreventLeavingPageByMistake />
+      {step === 0 ? (
+        <div>
+          <div className="mb-4">
+            <div>{t('create_wallet.confirmation_label_wallet_name')}</div>
+            <div className="fs-4">{walletDisplayName(createdWallet.name)}</div>
           </div>
+          <div className="mb-4">
+            <Seedphrase seedphrase={createdWallet.seedphrase} isBlurred={!revealSensitiveInfo} />
+          </div>
+          <div className="mb-4">
+            <div>{t('create_wallet.confirmation_label_password')}</div>
+            <div className={`fs-4${revealSensitiveInfo ? '' : ' blurred-text'}`}>
+              {!revealSensitiveInfo ? 'randomrandom' : createdWallet.password}
+            </div>
+          </div>
+          <div className="mb-2">
+            <ToggleSwitch
+              label={t('create_wallet.confirmation_toggle_reveal_info')}
+              onToggle={(isToggled) => {
+                setRevealSensitiveInfo(isToggled)
+                setSensitiveInfoWasRevealed(true)
+              }}
+            />
+          </div>
+          <div className="mb-4">
+            <ToggleSwitch
+              label={t('create_wallet.confirmation_toggle_info_written_down')}
+              onToggle={(isToggled) => setUserConfirmed(isToggled)}
+            />
+          </div>
+          <rb.Button variant="dark" disabled={!sensitiveInfoWasRevealed || !userConfirmed} onClick={() => setStep(1)}>
+            {t('create_wallet.next_button')}
+          </rb.Button>
         </div>
-        <div className="mb-2">
-          <ToggleSwitch
-            label={t('create_wallet.confirmation_toggle_reveal_info')}
-            onToggle={(isToggled) => {
-              setRevealSensitiveInfo(isToggled)
-              setSensitiveInfoWasRevealed(true)
-            }}
-          />
-        </div>
-        <div className="mb-4">
-          <ToggleSwitch
-            label={t('create_wallet.confirmation_toggle_info_written_down')}
-            onToggle={(isToggled) => setUserConfirmed(isToggled)}
-          />
-        </div>
-        <rb.Button variant="dark" disabled={!sensitiveInfoWasRevealed || !userConfirmed} onClick={() => setStep(1)}>
-          {t('create_wallet.next_button')}
-        </rb.Button>
-      </div>
-    )
-  } else {
-    return (
-      <BackupConfirmation
-        parentStepSetter={childStepSetter}
-        createdWallet={createdWallet}
-        walletConfirmed={walletConfirmed}
-      />
-    )
-  }
+      ) : (
+        <BackupConfirmation
+          parentStepSetter={childStepSetter}
+          createdWallet={createdWallet}
+          walletConfirmed={walletConfirmed}
+          devMode={devMode}
+        />
+      )}
+    </>
+  )
 }
 
-export default function CreateWallet({ startWallet }) {
+export default function CreateWallet({ startWallet, devMode = false }) {
   const { t } = useTranslation()
   const serviceInfo = useServiceInfo()
   const navigate = useNavigate()
@@ -291,7 +327,9 @@ export default function CreateWallet({ startWallet }) {
       )}
       {alert && <rb.Alert variant={alert.variant}>{alert.message}</rb.Alert>}
       {canCreate && <WalletCreationForm createWallet={createWallet} isCreating={isCreating} />}
-      {isCreated && <WalletCreationConfirmation createdWallet={createdWallet} walletConfirmed={walletConfirmed} />}
+      {isCreated && (
+        <WalletCreationConfirmation createdWallet={createdWallet} walletConfirmed={walletConfirmed} devMode={devMode} />
+      )}
       {!canCreate && !isCreated && (
         <rb.Alert variant="warning">
           <Trans i18nKey="create_wallet.alert_other_wallet_unlocked">
diff --git a/src/components/Seedphrase.css b/src/components/Seedphrase.css
new file mode 100644
index 0000000..8ad770d
--- /dev/null
+++ b/src/components/Seedphrase.css
@@ -0,0 +1,16 @@
+.seedphrase {
+  gap: 0.3rem;
+}
+
+.seedword-index {
+  width: 2ch;
+}
+
+.seedphrase > div {
+  background-color: rgba(244, 244, 244, 1);
+  width: 9rem;
+}
+
+:root[data-theme='dark'] .seedphrase > div {
+  background-color: var(--bs-gray-800);
+}
diff --git a/src/components/Seedphrase.jsx b/src/components/Seedphrase.jsx
index a342b83..c372aad 100644
--- a/src/components/Seedphrase.jsx
+++ b/src/components/Seedphrase.jsx
@@ -1,4 +1,5 @@
 import React from 'react'
+import './Seedphrase.css'
 
 export default function Seedphrase({ seedphrase, isBlurred = true }) {
   return (
diff --git a/src/components/Send.jsx b/src/components/Send.jsx
index 5f6f58d..1002786 100644
--- a/src/components/Send.jsx
+++ b/src/components/Send.jsx
@@ -121,6 +121,15 @@ const CollaboratorsSelector = ({ numCollaborators, setNumCollaborators, minNumCo
   )
 }
 
+const enhanceDirectPaymentErrorMessageIfNecessary = async (httpStatus, errorMessage, onBadRequest) => {
+  const tryEnhanceMessage = httpStatus === 400
+  if (tryEnhanceMessage) {
+    return onBadRequest(errorMessage)
+  }
+
+  return errorMessage
+}
+
 const enhanceTakerErrorMessageIfNecessary = async (
   requestContext,
   httpStatus,
@@ -254,13 +263,13 @@ export default function Send() {
   }, [wallet, setWalletInfo, t])
 
   const sendPayment = async (account, destination, amount_sats) => {
-    const { name: walletName, token } = wallet
+    const requestContext = { walletName: wallet.name, token: wallet.token }
 
     setAlert(null)
     setIsSending(true)
     let success = false
     try {
-      const res = await Api.postDirectSend({ walletName, token }, { mixdepth: account, destination, amount_sats })
+      const res = await Api.postDirectSend(requestContext, { mixdepth: account, destination, amount_sats })
       if (res.ok) {
         const {
           txinfo: { outputs },
@@ -273,7 +282,13 @@ export default function Send() {
         success = true
       } else {
         const { message } = await res.json()
-        setAlert({ variant: 'danger', message })
+
+        const displayMessage = await enhanceDirectPaymentErrorMessageIfNecessary(
+          res.status,
+          message,
+          (errorMessage) => `${errorMessage} ${t('send.direct_payment_error_message_bad_request')}`
+        )
+        setAlert({ variant: 'danger', message: displayMessage })
       }
     } catch (e) {
       setAlert({ variant: 'danger', message: e.message })
diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json
index 8b62103..b5d3357 100644
--- a/src/i18n/locales/en/translation.json
+++ b/src/i18n/locales/en/translation.json
@@ -154,6 +154,7 @@
     "description_num_collaborators": "A higher number is better for privacy, but also increases the fee.",
     "error_invalid_num_collaborators": "Please use between {{ minNumCollaborators }} and {{ maxNumCollaborators }} collaborators.",
     "taker_error_message_max_fees_config_missing": "Config variables 'max_cj_fee_rel' and 'max_cj_fee_abs' must be set in your joinmarket.cfg in order to send collaborative transactions. Consider adding them to your config manually.",
+    "direct_payment_error_message_bad_request": "Please verify your inputs carefully.",
     "error_loading_wallet_failed": "Loading wallet failed.",
     "error_loading_min_makers_failed": "Loading config value 'minimum_makers' failed.",
     "alert_payment_successful": "Payment successful: Sent {{ amount }} sats to {{ address }}.",
diff --git a/src/index.css b/src/index.css
index db46bb0..d5bce91 100644
--- a/src/index.css
+++ b/src/index.css
@@ -357,24 +357,7 @@ main {
   }
 }
 
-/* Wallet Creation Styles */
-
-.seedphrase {
-  gap: 0.3rem;
-}
-
-.seedphrase > div {
-  background-color: rgba(244, 244, 244, 1);
-  width: 8rem;
-}
-
-.seedword-index {
-  width: 2ch;
-}
-
-.seedword-index-backup {
-  width: 5ch;
-}
+/* Blurred Text Styles */
 
 .blurred-text {
   color: transparent;
@@ -386,20 +369,6 @@ main {
   text-shadow: 0 0 15px var(--bs-gray-400);
 }
 
-:root[data-theme='dark'] .seedphrase > div {
-  background-color: var(--bs-gray-800);
-}
-
-.create-wallet form input {
-  height: 3.5rem;
-  width: 100%;
-}
-
-.create-wallet button {
-  height: 3rem;
-  width: 100%;
-}
-
 /* Send, Receive, Earn Styles */
 
 .earn form input:not([type='checkbox']) {


Test patch:
diff --git a/src/components/CreateWallet.test.jsx b/src/components/CreateWallet.test.jsx
new file mode 100644
index 0000000..01c358c
--- /dev/null
+++ b/src/components/CreateWallet.test.jsx
@@ -0,0 +1,162 @@
+import React from 'react'
+import user from '@testing-library/user-event'
+import { render, screen, waitFor, waitForElementToBeRemoved } from '../testUtils'
+import { act } from 'react-dom/test-utils'
+
+import * as apiMock from '../libs/JmWalletApi'
+
+import CreateWallet from './CreateWallet'
+
+jest.mock('../libs/JmWalletApi', () => ({
+  ...jest.requireActual('../libs/JmWalletApi'),
+  getSession: jest.fn(),
+  postWalletCreate: jest.fn(),
+}))
+
+const NOOP = () => {}
+
+describe('<CreateWallet />', () => {
+  const setup = (props) => {
+    const startWallet = props?.startWallet || NOOP
+    const devMode = props?.devMode || false
+    render(<CreateWallet startWallet={startWallet} devMode={devMode} />)
+  }
+
+  beforeEach(() => {
+    const neverResolvingPromise = new Promise(() => {})
+    apiMock.getSession.mockReturnValue(neverResolvingPromise)
+  })
+
+  it('should render without errors', () => {
+    act(setup)
+
+    expect(screen.getByText('create_wallet.title')).toBeInTheDocument()
+    expect(screen.getByLabelText('create_wallet.label_wallet_name')).toBeInTheDocument()
+    expect(screen.getByPlaceholderText('create_wallet.placeholder_wallet_name')).toBeInTheDocument()
+    expect(screen.getByLabelText('create_wallet.label_password')).toBeInTheDocument()
+    expect(screen.getByPlaceholderText('create_wallet.placeholder_password')).toBeInTheDocument()
+    expect(screen.getByText('create_wallet.button_create')).toBeInTheDocument()
+  })
+
+  it('should show validation messages to user if form is invalid', () => {
+    act(setup)
+
+    expect(screen.getByText('create_wallet.button_create')).toBeInTheDocument()
+
+    act(() => {
+      // click on the "create" button without filling the form
+      const createWalletButton = screen.getByText('create_wallet.button_create')
+      user.click(createWalletButton)
+    })
+
+    expect(screen.getByText('create_wallet.feedback_invalid_wallet_name')).toBeVisible()
+    expect(screen.getByText('create_wallet.feedback_invalid_password')).toBeVisible()
+  })
+
+  it('should advance to WalletCreationConfirmation after wallet is created', async () => {
+    const walletName = 'wallet'
+
+    apiMock.postWalletCreate.mockResolvedValueOnce({
+      ok: true,
+      json: () =>
+        Promise.resolve({
+          walletname: `${walletName}.jmdat`,
+          token: 'ANY_TOKEN',
+          seedphrase: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
+        }),
+    })
+
+    act(setup)
+
+    expect(screen.getByText('create_wallet.button_create')).toBeInTheDocument()
+    expect(screen.queryByText('create_wallet.title_wallet_created')).not.toBeInTheDocument()
+
+    await act(async () => {
+      user.type(screen.getByPlaceholderText('create_wallet.placeholder_wallet_name'), walletName)
+      user.type(screen.getByPlaceholderText('create_wallet.placeholder_password'), 'password')
+      const createWalletButton = screen.getByText('create_wallet.button_create')
+      user.click(createWalletButton)
+
+      await waitFor(() => screen.findByText(/create_wallet.button_creating/))
+    })
+
+    expect(screen.queryByText('create_wallet.button_create')).not.toBeInTheDocument()
+    expect(screen.getByText('create_wallet.title_wallet_created')).toBeInTheDocument()
+  })
+
+  it('should verify that "skip" button is NOT visible when not in development mode', async () => {
+    const walletName = 'wallet'
+
+    apiMock.postWalletCreate.mockResolvedValueOnce({
+      ok: true,
+      json: () =>
+        Promise.resolve({
+          walletname: `${walletName}.jmdat`,
+          token: 'ANY_TOKEN',
+          seedphrase: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
+        }),
+    })
+
+    act(() => setup({ devMode: false }))
+
+    await act(async () => {
+      user.type(screen.getByPlaceholderText('create_wallet.placeholder_wallet_name'), walletName)
+      user.type(screen.getByPlaceholderText('create_wallet.placeholder_password'), 'password')
+      const createWalletButton = screen.getByText('create_wallet.button_create')
+      user.click(createWalletButton)
+
+      await waitFor(() => screen.findByText(/create_wallet.button_creating/))
+
+      const revealToggle = screen.getByText('create_wallet.confirmation_toggle_reveal_info')
+      user.click(revealToggle)
+
+      const confirmToggle = screen.getByText('create_wallet.confirmation_toggle_info_written_down')
+      user.click(confirmToggle)
+
+      const nextButton = screen.getByText('create_wallet.next_button')
+      user.click(nextButton)
+    })
+
+    expect(screen.queryByText('create_wallet.skip_button')).not.toBeInTheDocument()
+    expect(screen.getByText('create_wallet.back_button')).toBeInTheDocument()
+    expect(screen.getByText('create_wallet.confirmation_button_fund_wallet')).toBeDisabled()
+  })
+
+  it('should verify that "skip" button IS visible in development mode', async () => {
+    const walletName = 'wallet'
+
+    apiMock.postWalletCreate.mockResolvedValueOnce({
+      ok: true,
+      json: () =>
+        Promise.resolve({
+          walletname: `${walletName}.jmdat`,
+          token: 'ANY_TOKEN',
+          seedphrase: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
+        }),
+    })
+
+    act(() => setup({ devMode: true }))
+
+    await act(async () => {
+      user.type(screen.getByPlaceholderText('create_wallet.placeholder_wallet_name'), walletName)
+      user.type(screen.getByPlaceholderText('create_wallet.placeholder_password'), 'password')
+      const createWalletButton = screen.getByText('create_wallet.button_create')
+      user.click(createWalletButton)
+
+      await waitFor(() => screen.findByText(/create_wallet.button_creating/))
+
+      const revealToggle = screen.getByText('create_wallet.confirmation_toggle_reveal_info')
+      user.click(revealToggle)
+
+      const confirmToggle = screen.getByText('create_wallet.confirmation_toggle_info_written_down')
+      user.click(confirmToggle)
+
+      const nextButton = screen.getByText('create_wallet.next_button')
+      user.click(nextButton)
+    })
+
+    expect(screen.getByText('create_wallet.skip_button')).toBeInTheDocument()
+    expect(screen.getByText('create_wallet.back_button')).toBeInTheDocument()
+    expect(screen.getByText('create_wallet.confirmation_button_fund_wallet')).toBeDisabled()
+  })
+})