Page MenuHomePhabricator

[Cashtab] Improve wallet select behavior
AbandonedPublicDraft

Authored by bytesofman on Fri, Jan 17, 01:53.

Details

Reviewers
None
Group Reviewers
Restricted Project
Summary

It's possible for a user to get into a long loop if wallets are switched quickly. A number of things going on.

  • Selecting a wallet updates the wallet name state, which itself triggers the update loop
  • The update loop also writes the wallet state (so un-necessary writing twice)

We patch this by only updating the wallet change in state, knowing there is already logic in place to write this change to storage after the wallet is updated.

The logic on the App screen for rendering the spinner is incorrect, it is possible for loading to be true and the spinner to not render. Fix this.

Disable keyboard input on the wallet dropdown when Cashtab is loading. This prevents the user rapidly cycling through wallets that have not loaded yet and queueing tasks.

Test Plan

npm test, change wallets as fast as you can on the test site

deployed at test site: https://cashtab-local-dev.netlify.app/

  • cashtab.com should still load fast, as we do not spinner while the stored wallet loads
  • changing wallets should lock the UI and take a few seconds
  • keyboard arrows will not select a new wallet while a wallet is loading

Diff Detail

Repository
rABC Bitcoin ABC
Branch
fix-cashtab-wallet-changing-bug
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 32139
Build 63769: Build Diffcashtab-tests
Build 63768: arc lint + arc unit

Event Timeline

Failed tests logs:

====== CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a spinner while loading the token info, then show an info screen and open agora offers ======
TestingLibraryElementError: Found multiple elements with the title: Loading.

Here are the matching elements:

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="sc-kAzzGY bFOoJn"
      title="Loading..."
    >
      <div
        class="sc-cSHVUG kakYiA"
        title="Loading"
      >
        <div />
        <div />
        <div />
        <div />
      </div>
    </div>
    <div
      class="sc-AnqlK jzmxJP"
    >
      <section
        aria-atomic="false"
        aria-label="Notifications Alt+T"
        aria-live="polite"
        aria-relevant="additions text"
        class="Toastify"
      />
      <div
        class="sc-keFjpB kpRoMq"
      >
        <div
          class="sc-jWojfa dWofVP"
        >
          <div
            class="sc-dTLGrV hVKRQa"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <div
            class="sc-hdPSEv NMixZ"
          >
            <div
              class="sc-bqjOQT bJwGKq"
            >
              <select
                class="sc-jkCMRl gBdLKu"
                data-testid="wallet-select"
                disabled=""
                id="wallets"
                name="wallets"
              >
                <option
                  class="sc-crNyjn fdrrlO"
                  value="Transaction Fixtures"
                >
                  Transaction Fixtures
                </option>
              </select>
              <div
                class="sc-lcpuFF iSIgFF"
              >
                <button
                  aria-label="Copy ecash:qqa9lv3kjd8vq7952p7rq0f6lkpqvlu0cydvxtd70g"
                  class="sc-cJSrbW kZNvLw"
                >
                  <svg
                    title="copy-paste"
                  />
                </button>
                <div
                  class="sc-eerKOB cvXwwv"
                >
                  <div
                    class="sc-emmjRN bSWkUh"
                  >
                    <input
                      checked=""
                      class="sc-gFaPwZ iPJMNd"
                      id="show-hide-balance"
                      name="show-hide-balance"
                      title="show-hide-balance"
                      type="checkbox"
                    />
                    <label
                      class="sc-cpmLhU iUeRKn"
                      for="show-hide-balance"
                    >
                      <span
                        class="sc-dymIpo hGwQkt"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-bnXvFD cpOMDW"
                      />
                    </label>
                  </div>
                </div>
              </div>
            </div>
            <div
              class="sc-cmIlrE dkSzlg"
              title="Wallet Info"
            >
              <div
                class="sc-cpHetk jEKVml"
              >
                <div
                  class="sc-nrwXf bsChRe"
                  title="Balance XEC"
                >
                  9,513.12
                   
                  XEC
                </div>
              </div>
            </div>
          </div>
          <div
            class="sc-chAAoq bzVCQv"
          >
            <div
              class="sc-jKVCRD deirAb"
            >
              <div
                class="sc-kaNhvL ixwxts"
                title="Token Info"
              >
                <div
                  class="sc-kAzzGY bFOoJn"
                  title="Loading..."
                >
                  <div
                    class="sc-cSHVUG kakYiA"
                    title="Loading"
                  >
                    <div />
                    <div />
                    <div />
                    <div />
                  </div>
                </div>
                <div
                  class="sc-bbmXgH fbVlNd"
                >
                  You do not hold this token.
                </div>
              </div>
            </div>
          </div>
        </div>
        <div
          class="sc-kVrTmx exLrES"
        >
          <div
            class="sc-fHSTwm jBcETl"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <button
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Transactions
            </span>
            <svg />
          </button>
          <button
            aria-label="Send Screen"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Send
            </span>
            <svg
              title="tx-sent"
            />
          </button>
          <button
            aria-label="Tokens"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Tokens
            </span>
            <svg
              title="Tokens"
            />
          </button>
          <button
            aria-label="Receive"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Receive
            </span>
            <svg
              title="tx-received"
            />
          </button>
          <div
            class="sc-ekkqgF dcQEnG"
            title="Show Other Screens"
          >
            <span
              class="sc-iBmynh dPVmzy"
            />
            <div
              class="sc-fKGOjr buAdOz"
              title="Other Screens"
            >
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallet Backup
                </p>
                <svg
                  title="wallet"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallets
                </p>
                <svg
                  title="wallets"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Listed NFTs
                </p>
                <svg
                  title="NFT"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Agora
                </p>
                <svg
                  title="Meme Agora"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Contacts
                </p>
                <svg
                  title="Contact List"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Airdrop
                </p>
                <svg
                  title="tx-airdrop"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Rewards
                </p>
                <svg
                  title="Cashtab Rewards"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Sign & Verify
                </p>
                <svg
                  class="sc-htpNat bPFBeM"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Settings
                </p>
                <svg
                  title="settings"
                />
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
    at Object.getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:37:19)
    at getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:20:35)
    at getMultipleElementsFoundError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:23:10)
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:55:13
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:95:19
    at Object.getByTitle (/work/cashtab/src/components/Etokens/__tests__/Token.test.js:821:23)
    at runNextTicks (node:internal/process/task_queues:60:5)
    at listOnTimeout (node:internal/timers:545:9)
    at processTimers (node:internal/timers:519:7)
====== CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a chronik query error if we are unable to fetch the token info ======
TestingLibraryElementError: Found multiple elements with the title: Loading.

Here are the matching elements:

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="sc-kAzzGY bFOoJn"
      title="Loading..."
    >
      <div
        class="sc-cSHVUG kakYiA"
        title="Loading"
      >
        <div />
        <div />
        <div />
        <div />
      </div>
    </div>
    <div
      class="sc-AnqlK jzmxJP"
    >
      <section
        aria-atomic="false"
        aria-label="Notifications Alt+T"
        aria-live="polite"
        aria-relevant="additions text"
        class="Toastify"
      />
      <div
        class="sc-keFjpB kpRoMq"
      >
        <div
          class="sc-jWojfa dWofVP"
        >
          <div
            class="sc-dTLGrV hVKRQa"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <div
            class="sc-hdPSEv NMixZ"
          >
            <div
              class="sc-bqjOQT bJwGKq"
            >
              <select
                class="sc-jkCMRl gBdLKu"
                data-testid="wallet-select"
                disabled=""
                id="wallets"
                name="wallets"
              >
                <option
                  class="sc-crNyjn fdrrlO"
                  value="Transaction Fixtures"
                >
                  Transaction Fixtures
                </option>
              </select>
              <div
                class="sc-lcpuFF iSIgFF"
              >
                <button
                  aria-label="Copy ecash:qqa9lv3kjd8vq7952p7rq0f6lkpqvlu0cydvxtd70g"
                  class="sc-cJSrbW kZNvLw"
                >
                  <svg
                    title="copy-paste"
                  />
                </button>
                <div
                  class="sc-eerKOB cvXwwv"
                >
                  <div
                    class="sc-emmjRN bSWkUh"
                  >
                    <input
                      checked=""
                      class="sc-gFaPwZ iPJMNd"
                      id="show-hide-balance"
                      name="show-hide-balance"
                      title="show-hide-balance"
                      type="checkbox"
                    />
                    <label
                      class="sc-cpmLhU iUeRKn"
                      for="show-hide-balance"
                    >
                      <span
                        class="sc-dymIpo hGwQkt"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-bnXvFD cpOMDW"
                      />
                    </label>
                  </div>
                </div>
              </div>
            </div>
            <div
              class="sc-cmIlrE dkSzlg"
              title="Wallet Info"
            >
              <div
                class="sc-cpHetk jEKVml"
              >
                <div
                  class="sc-nrwXf bsChRe"
                  title="Balance XEC"
                >
                  9,513.12
                   
                  XEC
                </div>
              </div>
            </div>
          </div>
          <div
            class="sc-chAAoq bzVCQv"
          >
            <div
              class="sc-jKVCRD deirAb"
            >
              <div
                class="sc-kaNhvL ixwxts"
                title="Token Info"
              >
                <div
                  class="sc-kAzzGY bFOoJn"
                  title="Loading..."
                >
                  <div
                    class="sc-cSHVUG kakYiA"
                    title="Loading"
                  >
                    <div />
                    <div />
                    <div />
                    <div />
                  </div>
                </div>
                <div
                  class="sc-bbmXgH fbVlNd"
                >
                  You do not hold this token.
                </div>
              </div>
            </div>
          </div>
        </div>
        <div
          class="sc-kVrTmx exLrES"
        >
          <div
            class="sc-fHSTwm jBcETl"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <button
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Transactions
            </span>
            <svg />
          </button>
          <button
            aria-label="Send Screen"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Send
            </span>
            <svg
              title="tx-sent"
            />
          </button>
          <button
            aria-label="Tokens"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Tokens
            </span>
            <svg
              title="Tokens"
            />
          </button>
          <button
            aria-label="Receive"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Receive
            </span>
            <svg
              title="tx-received"
            />
          </button>
          <div
            class="sc-ekkqgF dcQEnG"
            title="Show Other Screens"
          >
            <span
              class="sc-iBmynh dPVmzy"
            />
            <div
              class="sc-fKGOjr buAdOz"
              title="Other Screens"
            >
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallet Backup
                </p>
                <svg
                  title="wallet"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallets
                </p>
                <svg
                  title="wallets"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Listed NFTs
                </p>
                <svg
                  title="NFT"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Agora
                </p>
                <svg
                  title="Meme Agora"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Contacts
                </p>
                <svg
                  title="Contact List"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Airdrop
                </p>
                <svg
                  title="tx-airdrop"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Rewards
                </p>
                <svg
                  title="Cashtab Rewards"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Sign & Verify
                </p>
                <svg
                  class="sc-htpNat bPFBeM"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Settings
                </p>
                <svg
                  title="settings"
                />
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
    at Object.getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:37:19)
    at getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:20:35)
    at getMultipleElementsFoundError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:23:10)
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:55:13
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:95:19
    at Object.getByTitle (/work/cashtab/src/components/Etokens/__tests__/Token.test.js:867:23)
====== CashTab Unit Tests: <Token /> For an invalid tokenId, we do not query chronik, and we show an invalid tokenId notice ======
Error: expect(element).not.toBeInTheDocument()

expected document not to contain element, found <div class="sc-cSHVUG kakYiA" title="Loading"><div /><div /><div /><div /></div> instead
    at Object.toBeInTheDocument (/work/cashtab/src/components/Etokens/__tests__/Token.test.js:903:52)

Each failure log is accessible here:
CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a spinner while loading the token info, then show an info screen and open agora offers
CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a chronik query error if we are unable to fetch the token info
CashTab Unit Tests: <Token /> For an invalid tokenId, we do not query chronik, and we show an invalid tokenId notice

do not setLoading(true) on app startup but do setLoading(true) on wallet switch

Failed tests logs:

====== CashTab Unit Tests: <Token /> Renders the burn token success notification upon successful burn tx broadcast ======
Error: expect(received).toHaveProperty(path, value)

Expected path: "checked"

Expected value: true
Received value: false
    at Object.toHaveProperty (/work/cashtab/src/components/Etokens/__tests__/Token.test.js:446:56)
====== CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a spinner while loading the token info, then show an info screen and open agora offers ======
TestingLibraryElementError: Found multiple elements with the title: Loading.

Here are the matching elements:

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="sc-kAzzGY bFOoJn"
      title="Loading..."
    >
      <div
        class="sc-cSHVUG kakYiA"
        title="Loading"
      >
        <div />
        <div />
        <div />
        <div />
      </div>
    </div>
    <div
      class="sc-AnqlK jzmxJP"
    >
      <section
        aria-atomic="false"
        aria-label="Notifications Alt+T"
        aria-live="polite"
        aria-relevant="additions text"
        class="Toastify"
      />
      <div
        class="sc-keFjpB kpRoMq"
      >
        <div
          class="sc-jWojfa dWofVP"
        >
          <div
            class="sc-dTLGrV hVKRQa"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <div
            class="sc-hdPSEv NMixZ"
          >
            <div
              class="sc-bqjOQT bJwGKq"
            >
              <select
                class="sc-jkCMRl gBdLKu"
                data-testid="wallet-select"
                disabled=""
                id="wallets"
                name="wallets"
              >
                <option
                  class="sc-crNyjn fdrrlO"
                  value="Transaction Fixtures"
                >
                  Transaction Fixtures
                </option>
              </select>
              <div
                class="sc-lcpuFF iSIgFF"
              >
                <button
                  aria-label="Copy ecash:qqa9lv3kjd8vq7952p7rq0f6lkpqvlu0cydvxtd70g"
                  class="sc-cJSrbW kZNvLw"
                >
                  <svg
                    title="copy-paste"
                  />
                </button>
                <div
                  class="sc-eerKOB cvXwwv"
                >
                  <div
                    class="sc-emmjRN bSWkUh"
                  >
                    <input
                      checked=""
                      class="sc-gFaPwZ iPJMNd"
                      id="show-hide-balance"
                      name="show-hide-balance"
                      title="show-hide-balance"
                      type="checkbox"
                    />
                    <label
                      class="sc-cpmLhU iUeRKn"
                      for="show-hide-balance"
                    >
                      <span
                        class="sc-dymIpo hGwQkt"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-bnXvFD cpOMDW"
                      />
                    </label>
                  </div>
                </div>
              </div>
            </div>
            <div
              class="sc-cmIlrE dkSzlg"
              title="Wallet Info"
            >
              <div
                class="sc-cpHetk jEKVml"
              >
                <div
                  class="sc-nrwXf bsChRe"
                  title="Balance XEC"
                >
                  9,513.12
                   
                  XEC
                </div>
              </div>
            </div>
          </div>
          <div
            class="sc-chAAoq bzVCQv"
          >
            <div
              class="sc-jKVCRD deirAb"
            >
              <div
                class="sc-kaNhvL ixwxts"
                title="Token Info"
              >
                <div
                  class="sc-kAzzGY bFOoJn"
                  title="Loading..."
                >
                  <div
                    class="sc-cSHVUG kakYiA"
                    title="Loading"
                  >
                    <div />
                    <div />
                    <div />
                    <div />
                  </div>
                </div>
                <div
                  class="sc-bbmXgH fbVlNd"
                >
                  You do not hold this token.
                </div>
              </div>
            </div>
          </div>
        </div>
        <div
          class="sc-kVrTmx exLrES"
        >
          <div
            class="sc-fHSTwm jBcETl"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <button
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Transactions
            </span>
            <svg />
          </button>
          <button
            aria-label="Send Screen"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Send
            </span>
            <svg
              title="tx-sent"
            />
          </button>
          <button
            aria-label="Tokens"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Tokens
            </span>
            <svg
              title="Tokens"
            />
          </button>
          <button
            aria-label="Receive"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Receive
            </span>
            <svg
              title="tx-received"
            />
          </button>
          <div
            class="sc-ekkqgF dcQEnG"
            title="Show Other Screens"
          >
            <span
              class="sc-iBmynh dPVmzy"
            />
            <div
              class="sc-fKGOjr buAdOz"
              title="Other Screens"
            >
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallet Backup
                </p>
                <svg
                  title="wallet"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallets
                </p>
                <svg
                  title="wallets"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Listed NFTs
                </p>
                <svg
                  title="NFT"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Agora
                </p>
                <svg
                  title="Meme Agora"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Contacts
                </p>
                <svg
                  title="Contact List"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Airdrop
                </p>
                <svg
                  title="tx-airdrop"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Rewards
                </p>
                <svg
                  title="Cashtab Rewards"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Sign & Verify
                </p>
                <svg
                  class="sc-htpNat bPFBeM"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Settings
                </p>
                <svg
                  title="settings"
                />
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
    at Object.getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:37:19)
    at getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:20:35)
    at getMultipleElementsFoundError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:23:10)
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:55:13
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:95:19
    at Object.getByTitle (/work/cashtab/src/components/Etokens/__tests__/Token.test.js:821:23)
    at runNextTicks (node:internal/process/task_queues:60:5)
    at listOnTimeout (node:internal/timers:545:9)
    at processTimers (node:internal/timers:519:7)
====== CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a chronik query error if we are unable to fetch the token info ======
TestingLibraryElementError: Found multiple elements with the title: Loading.

Here are the matching elements:

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

Ignored nodes: comments, script, style
<div
  class="sc-cSHVUG kakYiA"
  title="Loading"
>
  <div />
  <div />
  <div />
  <div />
</div>

(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="sc-kAzzGY bFOoJn"
      title="Loading..."
    >
      <div
        class="sc-cSHVUG kakYiA"
        title="Loading"
      >
        <div />
        <div />
        <div />
        <div />
      </div>
    </div>
    <div
      class="sc-AnqlK jzmxJP"
    >
      <section
        aria-atomic="false"
        aria-label="Notifications Alt+T"
        aria-live="polite"
        aria-relevant="additions text"
        class="Toastify"
      />
      <div
        class="sc-keFjpB kpRoMq"
      >
        <div
          class="sc-jWojfa dWofVP"
        >
          <div
            class="sc-dTLGrV hVKRQa"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <div
            class="sc-hdPSEv NMixZ"
          >
            <div
              class="sc-bqjOQT bJwGKq"
            >
              <select
                class="sc-jkCMRl gBdLKu"
                data-testid="wallet-select"
                disabled=""
                id="wallets"
                name="wallets"
              >
                <option
                  class="sc-crNyjn fdrrlO"
                  value="Transaction Fixtures"
                >
                  Transaction Fixtures
                </option>
              </select>
              <div
                class="sc-lcpuFF iSIgFF"
              >
                <button
                  aria-label="Copy ecash:qqa9lv3kjd8vq7952p7rq0f6lkpqvlu0cydvxtd70g"
                  class="sc-cJSrbW kZNvLw"
                >
                  <svg
                    title="copy-paste"
                  />
                </button>
                <div
                  class="sc-eerKOB cvXwwv"
                >
                  <div
                    class="sc-emmjRN bSWkUh"
                  >
                    <input
                      checked=""
                      class="sc-gFaPwZ iPJMNd"
                      id="show-hide-balance"
                      name="show-hide-balance"
                      title="show-hide-balance"
                      type="checkbox"
                    />
                    <label
                      class="sc-cpmLhU iUeRKn"
                      for="show-hide-balance"
                    >
                      <span
                        class="sc-dymIpo hGwQkt"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-bnXvFD cpOMDW"
                      />
                    </label>
                  </div>
                </div>
              </div>
            </div>
            <div
              class="sc-cmIlrE dkSzlg"
              title="Wallet Info"
            >
              <div
                class="sc-cpHetk jEKVml"
              >
                <div
                  class="sc-nrwXf bsChRe"
                  title="Balance XEC"
                >
                  9,513.12
                   
                  XEC
                </div>
              </div>
            </div>
          </div>
          <div
            class="sc-chAAoq bzVCQv"
          >
            <div
              class="sc-jKVCRD deirAb"
            >
              <div
                class="sc-kaNhvL ixwxts"
                title="Token Info"
              >
                <div
                  class="sc-kAzzGY bFOoJn"
                  title="Loading..."
                >
                  <div
                    class="sc-cSHVUG kakYiA"
                    title="Loading"
                  >
                    <div />
                    <div />
                    <div />
                    <div />
                  </div>
                </div>
                <div
                  class="sc-bbmXgH fbVlNd"
                >
                  You do not hold this token.
                </div>
              </div>
            </div>
          </div>
        </div>
        <div
          class="sc-kVrTmx exLrES"
        >
          <div
            class="sc-fHSTwm jBcETl"
          >
            <img
              alt="cashtab"
              class="sc-ivVeuv evHkvQ"
              src="test-file-stub"
            />
          </div>
          <button
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Transactions
            </span>
            <svg />
          </button>
          <button
            aria-label="Send Screen"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Send
            </span>
            <svg
              title="tx-sent"
            />
          </button>
          <button
            aria-label="Tokens"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Tokens
            </span>
            <svg
              title="Tokens"
            />
          </button>
          <button
            aria-label="Receive"
            class="sc-jvEmr hqZIZM"
          >
            <span>
              Receive
            </span>
            <svg
              title="tx-received"
            />
          </button>
          <div
            class="sc-ekkqgF dcQEnG"
            title="Show Other Screens"
          >
            <span
              class="sc-iBmynh dPVmzy"
            />
            <div
              class="sc-fKGOjr buAdOz"
              title="Other Screens"
            >
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallet Backup
                </p>
                <svg
                  title="wallet"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Wallets
                </p>
                <svg
                  title="wallets"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Listed NFTs
                </p>
                <svg
                  title="NFT"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Agora
                </p>
                <svg
                  title="Meme Agora"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Contacts
                </p>
                <svg
                  title="Contact List"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Airdrop
                </p>
                <svg
                  title="tx-airdrop"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                 
                <p>
                  Rewards
                </p>
                <svg
                  title="Cashtab Rewards"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Sign & Verify
                </p>
                <svg
                  class="sc-htpNat bPFBeM"
                />
              </button>
              <button
                class="sc-hycgNl bNyILw"
              >
                <p>
                  Settings
                </p>
                <svg
                  title="settings"
                />
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
    at Object.getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:37:19)
    at getElementError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:20:35)
    at getMultipleElementsFoundError (/work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:23:10)
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:55:13
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:95:19
    at Object.getByTitle (/work/cashtab/src/components/Etokens/__tests__/Token.test.js:867:23)
====== CashTab Unit Tests: <Token /> For an invalid tokenId, we do not query chronik, and we show an invalid tokenId notice ======
Error: expect(element).not.toBeInTheDocument()

expected document not to contain element, found <div class="sc-cSHVUG kakYiA" title="Loading"><div /><div /><div /><div /></div> instead
    at Object.toBeInTheDocument (/work/cashtab/src/components/Etokens/__tests__/Token.test.js:903:52)

Each failure log is accessible here:
CashTab Unit Tests: <Token /> Renders the burn token success notification upon successful burn tx broadcast
CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a spinner while loading the token info, then show an info screen and open agora offers
CashTab Unit Tests: <Token /> For an uncached token with no balance, we show a chronik query error if we are unable to fetch the token info
CashTab Unit Tests: <Token /> For an invalid tokenId, we do not query chronik, and we show an invalid tokenId notice