Page MenuHomePhabricator

[Cashtab] Standardize getter and setter functions for db and state
ClosedPublic

Authored by bytesofman on Feb 11 2024, 01:01.

Details

Summary

Initialize a standardized function to load data from storage and pass it to wallet context on app startup. Initialize a standardized function to update state (and localforage) when this data changes.

Implement with contactList localforage key.

We have too many getter and setter functions for the various keys. Should have one. All state and storage mgmt should be handled the same way.

This will make migration and updates to the storage schema easier. Will also make it easier to migrate the extension to use the extension storage API instead of indexedDb.

Arguably we should just store cashtabState itself as a key in localforage. Consideration for a later diff. However, hard to say this would optimize, and could complicate the validation / migration functions specific to each key.

Background

Existing functions that get and set data from localforage and wallet context have been added incrementally and diverge in quality and purpose. We should have consistent primitives here.

We only want to get items from localforage on Cashtab startup. We then set these items in state to be used by the app while the user has Cashtab open.

We periodically write to localforage as state items change to ensure they will be available to the user if the browser closes.

Test Plan

npm test

Diff Detail

Repository
rABC Bitcoin ABC
Branch
standardize-storage-and-state-objects
Lint
Lint Errors
SeverityLocationCodeMessage
Errorcashtab/src/components/Configure/__tests__/Configure.test.js:51ESLINTjest/no-focused-tests
Unit
No Test Coverage
Build Status
Buildable 27064
Build 53694: Build Diffcashtab-tests
Build 53693: arc lint + arc unit

Event Timeline

Tail of the build log:

/work/cashtab /work/abc-ci-builds/cashtab-tests
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'fake-indexeddb@5.0.2',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v16.20.2', npm: '8.19.4' }
npm WARN EBADENGINE }
npm WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
npm WARN deprecated rollup-plugin-terser@7.0.2: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
npm WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
npm WARN deprecated workbox-cacheable-response@6.6.0: workbox-background-sync@6.6.0
npm WARN deprecated domexception@4.0.0: Use your platform's native DOMException instead
npm WARN deprecated abab@2.0.6: Use your platform's native atob() and btoa() methods instead
npm WARN deprecated @babel/plugin-proposal-private-methods@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.
npm WARN deprecated @babel/plugin-proposal-private-property-in-object@7.21.11: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.
npm WARN deprecated @babel/plugin-proposal-nullish-coalescing-operator@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
npm WARN deprecated @babel/plugin-proposal-numeric-separator@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.
npm WARN deprecated @babel/plugin-proposal-class-properties@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
npm WARN deprecated @babel/plugin-proposal-optional-chaining@7.21.0: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.

added 1912 packages, and audited 1913 packages in 19s

263 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

> cashtab@1.1.8 build
> node scripts/build.js

Creating an optimized production build...
Failed to compile.

[eslint] 
src/hooks/useWallet.js
  Line 15:5:   'isValidContactList' is defined but never used       no-unused-vars
  Line 63:25:  'setContactList' is assigned a value but never used  no-unused-vars

Search for the keywords to learn more about each error.


Build cashtab-tests failed with exit code 1

Failed tests logs:

====== CashTab Unit Tests: useWallet hook Migrating legacy wallet on mainnet ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook Verify default Cashtab settings are initialized ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook processChronikWsMsg() refreshes alias prices when aliasPrices is null ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook processChronikWsMsg() refreshes alias prices when aliasPrices exists, server and cashtab prices array length do not match ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook processChronikWsMsg() does not refresh alias prices when aliasPrices exists, server and cashtab array length do match ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook Verify a processChronikWsMsg() new block event updates the `aliasServerError` state var upon a /prices/ endpoint error ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook Verify refreshAliases() updates the `aliases` state variable on a successful /address/ endpoint response ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook Verify refreshAliases() updates the `aliasServerError` state variable upon an /address/ endpoint error ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: <Configure /> Deleting a contact from Configure.js removes it from localforage and wallet context ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 14
+ Received  +  1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "alpha",
-   },
-   Object {
-     "address": "ecash:qz2708636snqhsxu8wnlka78h6fdp77ar59jrf5035",
-     "name": "beta",
-   },
-   Object {
-     "address": "ecash:qphlhe78677sz227k83hrh542qeehh8el5lcjwk72y",
-     "name": "gamma",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/components/Configure/__tests__/Configure.test.js:61:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: <Configure /> Adding a contact from Configure.js adds it to localforage and wallet context ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 14
+ Received  +  1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "alpha",
-   },
-   Object {
-     "address": "ecash:qz2708636snqhsxu8wnlka78h6fdp77ar59jrf5035",
-     "name": "beta",
-   },
-   Object {
-     "address": "ecash:qphlhe78677sz227k83hrh542qeehh8el5lcjwk72y",
-     "name": "gamma",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/components/Configure/__tests__/Configure.test.js:142:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: <Configure /> Renaming a contact from Configure.js renames it in localforage and wallet context ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 14
+ Received  +  1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "alpha",
-   },
-   Object {
-     "address": "ecash:qz2708636snqhsxu8wnlka78h6fdp77ar59jrf5035",
-     "name": "beta",
-   },
-   Object {
-     "address": "ecash:qphlhe78677sz227k83hrh542qeehh8el5lcjwk72y",
-     "name": "gamma",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/components/Configure/__tests__/Configure.test.js:230:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: <Configure /> We can add a savedWallet as a contact ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 14
+ Received  +  1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "alpha",
-   },
-   Object {
-     "address": "ecash:qz2708636snqhsxu8wnlka78h6fdp77ar59jrf5035",
-     "name": "beta",
-   },
-   Object {
-     "address": "ecash:qphlhe78677sz227k83hrh542qeehh8el5lcjwk72y",
-     "name": "gamma",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/components/Configure/__tests__/Configure.test.js:325:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 6
+ Received  + 1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "test",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:40:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist as expected defaults if localforage is empty ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: {"autoCameraOn": true, "balanceVisible": true, "fiatCurrency": "usd", "hideMessagesFromUnknownSenders": false, "sendModal": false}
Received: false

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:83:52)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: useWallet hook rendering in different localforage states XEC price is set in state on successful API fetch ======
Error: expect(received).toBe(expected) // Object.is equality

Expected: 0.00003132
Received: null

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toBe (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:118:46)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: useWallet hook rendering in different localforage states XEC price remains null in state on API error ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: useWallet hook rendering in different localforage states XEC price is set in state to fiat currency of user settings on successful API fetch ======
Error: expect(received).toBe(expected) // Object.is equality

Expected: 0.00003132
Received: null

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toBe (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:165:46)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: <App /> Renders onboarding screen if cashtab.com opened with no local storage and no wallet ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: <App /> Renders API error if called with wallet in localforage but chronik utxo calls fail ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: <App /> Loads home screen with no error if wallet is in storage and chronik calls are successful ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)
====== CashTab Unit Tests: <App /> Adding a contact to Configure.js from clicking on tx history adds it to localforage and wallet context ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: []
Received: null
    at Object.toStrictEqual (/work/cashtab/src/components/__tests__/AppIntegrations.test.js:282:32)
====== CashTab Unit Tests: <App /> Adding a contact to an existing contactList by clicking on tx history adds it to localforage and wallet context ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 4
+ Received  + 0

  Array [
    Object {
      "address": "ecash:qpmytrdsakt0axrrlswvaj069nat3p9s7cjctmjasj",
      "name": "echo",
    },
-   Object {
-     "address": "ecash:qphlhe78677sz227k83hrh542qeehh8el5lcjwk72y",
-     "name": "qphlh",
-   },
  ]

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div>
      <div
        class="ant-spin-nested-loading css-dev-only-do-not-override-1rqnfsa"
      >
        <div
          class="ant-spin-container"
        >
          <div
            class="sc-LKuAh jSXNAo"
          >
            <div
              class="sc-kZmsYB eHkWzo"
            >
              <div
                class="sc-RcBXQ gMCskf"
              >
                <div
                  class="sc-hzNEM iiFjIO"
                >
                  <div
                    class="sc-iSDuPN ccpgHi"
                  >
                    <img
                      alt="cashtab"
                      class="sc-fZwumE bcurWd"
                      src="test-file-stub"
                    />
                    <div
                      class="sc-etwtAo fHyTnr"
                    >
                      Settings
                      <svg
                        height="33px"
                        width="30px"
                      />
                    </div>
                  </div>
                  <div
                    class="sc-elJkPf geNavj"
                    data-testid="wallet-info-ctn"
                  >
                    <div
                      class="sc-dEoRIm iVOOxs"
                    >
                      <div
                        class="sc-jtggT dNidya"
                      >
                        [Burned] useWallet Mock
                      </div>
                      <a
                        href="/configure"
                      >
                        <svg
                          class="sc-jTzLTM bTdWCF"
                        />
                      </a>
                      <div>
                         
                        <button
                          aria-checked="false"
                          class="ant-switch ant-switch-small css-dev-only-do-not-override-1rqnfsa"
                          role="switch"
                          type="button"
                        >
                          <div
                            class="ant-switch-handle"
                          />
                          <span
                            class="ant-switch-inner"
                          >
                            <span
                              class="ant-switch-inner-checked"
                            >
                              <svg
                                class="sc-cSHVUG bgwEHu"
                              />
                            </span>
                            <span
                              class="ant-switch-inner-unchecked"
                            >
                              <svg
                                class="sc-kAzzGY fUTkYj"
                              />
                            </span>
                          </span>
                        </button>
                      </div>
                    </div>
                    <div
                      class="sc-ebFjAB kxaSkj"
                      data-testid="balance-xec"
                    >
                      10,000.00
                       
                      XEC
                       
                    </div>
                  </div>
                </div>
                <div
                  class="sc-lhVmIH gJoLAm"
                  data-testid="configure-ctn"
                >
                  <div
                    class="sc-gPWkxV fPJZLd"
                  >
                    <h2>
                      <span
                        aria-label="copy"
                        class="anticon anticon-copy sc-bwzfXH gJwWNq"
                        role="img"
                      >
                        <svg
                          aria-hidden="true"
                          data-icon="copy"
                          fill="currentColor"
                          focusable="false"
                          height="1em"
                          viewBox="64 64 896 896"
                          width="1em"
                        >
                          <path
                            d="M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"
                          />
                        </svg>
                      </span>
                       Backup your wallet
                    </h2>
                    <div
                      class="ant-alert ant-alert-warning ant-alert-with-description css-dev-only-do-not-override-1rqnfsa"
                      data-show="true"
                      role="alert"
                      style="margin-bottom: 12px;"
                    >
                      <span
                        aria-label="exclamation-circle"
                        class="anticon anticon-exclamation-circl...
    at toStrictEqual (/work/cashtab/src/components/__tests__/AppIntegrations.test.js:356:62)
====== CashTab Unit Tests: <App /> A user with legacy blank contactList in localstorage is migrated on startup ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 1
+ Received  + 3

- Array []
+ Array [
+   Object {},
+ ]

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div>
      <div
        class="ant-spin-nested-loading css-dev-only-do-not-override-1rqnfsa"
      >
        <div
          class="ant-spin-container"
        >
          <div
            class="sc-LKuAh jSXNAo"
          >
            <div
              class="sc-kZmsYB eHkWzo"
            >
              <div
                class="sc-RcBXQ gMCskf"
              >
                <div
                  class="sc-hzNEM iiFjIO"
                >
                  <div
                    class="sc-iSDuPN ccpgHi"
                  >
                    <img
                      alt="cashtab"
                      class="sc-fZwumE bcurWd"
                      src="test-file-stub"
                    />
                  </div>
                  <div
                    class="sc-elJkPf geNavj"
                    data-testid="wallet-info-ctn"
                  >
                    <div
                      class="sc-dEoRIm iVOOxs"
                    >
                      <div
                        class="sc-jtggT dNidya"
                      >
                        [Burned] useWallet Mock
                      </div>
                      <a
                        href="/configure"
                      >
                        <svg
                          class="sc-jTzLTM bTdWCF"
                        />
                      </a>
                      <div>
                         
                        <button
                          aria-checked="false"
                          class="ant-switch ant-switch-small css-dev-only-do-not-override-1rqnfsa"
                          role="switch"
                          type="button"
                        >
                          <div
                            class="ant-switch-handle"
                          />
                          <span
                            class="ant-switch-inner"
                          >
                            <span
                              class="ant-switch-inner-checked"
                            >
                              <svg
                                class="sc-cSHVUG bgwEHu"
                              />
                            </span>
                            <span
                              class="ant-switch-inner-unchecked"
                            >
                              <svg
                                class="sc-kAzzGY fUTkYj"
                              />
                            </span>
                          </span>
                        </button>
                      </div>
                    </div>
                    <div
                      class="sc-ebFjAB kxaSkj"
                      data-testid="balance-xec"
                    >
                      10,000.00
                       
                      XEC
                       
                    </div>
                  </div>
                </div>
                <br />
                <div
                  class="sc-lhVmIH gJoLAm"
                  data-testid="home-ctn"
                >
                  <div
                    class="sc-kPVwWT WzIzL"
                    data-testid="tx-history-ctn"
                  >
                    <div>
                      <div
                        class="sc-fYxtnH grnFXT"
                        data-testid="tx-collapse"
                      >
                        <div
                          class="ant-collapse ant-collapse-icon-position-start ant-collapse-borderless css-dev-only-do-not-override-1rqnfsa"
                        >
                          <div
                            class="ant-collapse-item ant-collapse-no-arrow"
                          >
                            <div
                              aria-disabled="false"
                              aria-expanded="false"
                              class="ant-collapse-header"
                              role="button"
                              tabindex="0"
                            >
                              <span
                                class="ant-collapse-header-text"
                              >
                                <div
                                  class="sc-jnlKLf cCxHyz"
                                >
                                  <div
                                    class="sc-Rmtcm sc-fBuWsC hjEaKK"
                                  >
                                    <svg />
                                  </div>
                                  <div
                                    class="sc-kgAjT jmWxWd"
                                    data-testid="left-txt-ctn"
                                  >
                                    <div
                                      class="sc-iELTvK iFEMbz"
                                    >
                                      <h3
                                        class="sc-TOsTZ kjYrri"
                                      >
                                        Receiv...
    at toStrictEqual (/work/cashtab/src/components/__tests__/AppIntegrations.test.js:398:62)
====== CashTab Unit Tests: <App /> Clicking "reply" on a Cashtab Msg correctly populates the SendXec to address and amount fields ======
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
    at cashtabState (/work/cashtab/src/hooks/useWallet.js:294:28)
    at cashtabBootup (/work/cashtab/src/hooks/useWallet.js:1448:9)

Each failure log is accessible here:
CashTab Unit Tests: useWallet hook Migrating legacy wallet on mainnet
CashTab Unit Tests: useWallet hook Verify default Cashtab settings are initialized
CashTab Unit Tests: useWallet hook processChronikWsMsg() refreshes alias prices when aliasPrices is null
CashTab Unit Tests: useWallet hook processChronikWsMsg() refreshes alias prices when aliasPrices exists, server and cashtab prices array length do not match
CashTab Unit Tests: useWallet hook processChronikWsMsg() does not refresh alias prices when aliasPrices exists, server and cashtab array length do match
[[https://build.bitcoinabc.org/viewLog.html?tab=buildLog&logTab=tree&filter=debug&expand=all&buildId=691915&_focus=101808&guest=1 | CashTab Unit Tests: useWallet hook Verify a processChronikWsMsg() new block event updates the aliasServerError state var upon a /prices/ endpoint error]]
[[https://build.bitcoinabc.org/viewLog.html?tab=buildLog&logTab=tree&filter=debug&expand=all&buildId=691915&_focus=101811&guest=1 | CashTab Unit Tests: useWallet hook Verify refreshAliases() updates the aliases state variable on a successful /address/ endpoint response]]
[[https://build.bitcoinabc.org/viewLog.html?tab=buildLog&logTab=tree&filter=debug&expand=all&buildId=691915&_focus=101814&guest=1 | CashTab Unit Tests: useWallet hook Verify refreshAliases() updates the aliasServerError state variable upon an /address/ endpoint error]]
CashTab Unit Tests: <Configure /> Deleting a contact from Configure.js removes it from localforage and wallet context
CashTab Unit Tests: <Configure /> Adding a contact from Configure.js adds it to localforage and wallet context
CashTab Unit Tests: <Configure /> Renaming a contact from Configure.js renames it in localforage and wallet context
CashTab Unit Tests: <Configure /> We can add a savedWallet as a contact
CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present
CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist as expected defaults if localforage is empty
CashTab Unit Tests: useWallet hook rendering in different localforage states XEC price is set in state on successful API fetch
CashTab Unit Tests: useWallet hook rendering in different localforage states XEC price remains null in state on API error
CashTab Unit Tests: useWallet hook rendering in different localforage states XEC price is set in state to fiat currency of user settings on successful API fetch
CashTab Unit Tests: <App /> Renders onboarding screen if cashtab.com opened with no local storage and no wallet
CashTab Unit Tests: <App /> Renders API error if called with wallet in localforage but chronik utxo calls fail
CashTab Unit Tests: <App /> Loads home screen with no error if wallet is in storage and chronik calls are successful
CashTab Unit Tests: <App /> Adding a contact to Configure.js from clicking on tx history adds it to localforage and wallet context
CashTab Unit Tests: <App /> Adding a contact to an existing contactList by clicking on tx history adds it to localforage and wallet context
CashTab Unit Tests: <App /> A user with legacy blank contactList in localstorage is migrated on startup
CashTab Unit Tests: <App /> Clicking "reply" on a Cashtab Msg correctly populates the SendXec to address and amount fields

Get AppIntegrations.test.js to pass, working on Configure

Failed tests logs:

====== CashTab Unit Tests: <Configure /> Deleting a contact from Configure.js removes it from localforage and wallet context ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 14
+ Received  +  1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "alpha",
-   },
-   Object {
-     "address": "ecash:qz2708636snqhsxu8wnlka78h6fdp77ar59jrf5035",
-     "name": "beta",
-   },
-   Object {
-     "address": "ecash:qphlhe78677sz227k83hrh542qeehh8el5lcjwk72y",
-     "name": "gamma",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/components/Configure/__tests__/Configure.test.js:61:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 6
+ Received  + 1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "test",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:40:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: <App /> Navigation menu routes to expected components ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:480:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performSyncWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26096:20)
    at flushSyncCallbacks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:12042:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at Object.eventWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:107:28)
    at Object.wrapEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/wrapEvent.js:6:28)
    at Object.dispatchEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:45:22)
    at Object.dispatchUIEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:22:26)
    at Mouse.up (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/mouse.js:100:30)
    at PointerHost.release (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/index.js:84:28)
    at pointerAction (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:59:47)
    at Object.pointer (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:32:9)
    at Object.asyncWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:88:22)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:145:9)
====== CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:480:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:151:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)
====== CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:480:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:165:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)

Each failure log is accessible here:
CashTab Unit Tests: <Configure /> Deleting a contact from Configure.js removes it from localforage and wallet context
CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present
CashTab Unit Tests: <App /> Navigation menu routes to expected components
CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet
CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet

working test for AppIntegrations and Configure

Failed tests logs:

====== CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 6
+ Received  + 1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "test",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:40:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7)
====== CashTab Unit Tests: <App /> Navigation menu routes to expected components ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:480:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performSyncWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26096:20)
    at flushSyncCallbacks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:12042:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at Object.eventWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:107:28)
    at Object.wrapEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/wrapEvent.js:6:28)
    at Object.dispatchEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:45:22)
    at Object.dispatchUIEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:22:26)
    at Mouse.up (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/mouse.js:100:30)
    at PointerHost.release (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/index.js:84:28)
    at pointerAction (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:59:47)
    at Object.pointer (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:32:9)
    at Object.asyncWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:88:22)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:129:9)
====== CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:480:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:135:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)
====== CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:480:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:149:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)

Each failure log is accessible here:
CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present
CashTab Unit Tests: <App /> Navigation menu routes to expected components
CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet
CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet

Failed tests logs:

====== CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present ======
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 6
+ Received  + 1

- Array [
-   Object {
-     "address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6",
-     "name": "test",
-   },
- ]
+ Array []

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:40:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:573:17)
    at processTimers (node:internal/timers:514:7)
====== CashTab Unit Tests: <App /> Navigation menu routes to expected components ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performSyncWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26096:20)
    at flushSyncCallbacks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:12042:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at Object.eventWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:107:28)
    at Object.wrapEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/wrapEvent.js:6:28)
    at Object.dispatchEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:45:22)
    at Object.dispatchUIEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:22:26)
    at Mouse.up (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/mouse.js:100:30)
    at PointerHost.release (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/index.js:84:28)
    at pointerAction (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:59:47)
    at Object.pointer (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:32:9)
    at Object.asyncWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:88:22)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:129:9)
====== CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:135:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)
====== CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet ======
TypeError: Cannot read properties of undefined (reading 'contactList')
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:38)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:149:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)

Each failure log is accessible here:
CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present
CashTab Unit Tests: <App /> Navigation menu routes to expected components
CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet
CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet

remove obsolete contactList methods, remove unrelated changes from diff

Failed tests logs:

====== CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: [{"address": "ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6", "name": "test"}]
Received: undefined

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:40:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:573:17)
    at processTimers (node:internal/timers:514:7)
====== CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist as expected defaults if localforage is empty ======
Error: expect(received).toStrictEqual(expected) // deep equality

Expected: []
Received: undefined

Ignored nodes: comments, script, style
<html>
  <head />
  <body>
    <div />
  </body>
</html>
    at toStrictEqual (/work/cashtab/src/hooks/__tests__/useWalletStorage.test.js:75:48)
    at runWithExpensiveErrorDiagnosticsDisabled (/work/cashtab/node_modules/@testing-library/dom/dist/config.js:47:12)
    at checkCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:124:77)
    at checkRealTimersCallback (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:118:16)
    at Timeout.task [as _onTimeout] (/work/cashtab/node_modules/jsdom/lib/jsdom/browser/Window.js:520:19)
    at listOnTimeout (node:internal/timers:573:17)
    at processTimers (node:internal/timers:514:7)
====== CashTab Unit Tests: <App /> Navigation menu routes to expected components ======
TypeError: Cannot destructure property 'contactList' of '((cov_69iclqte5(...).s[56]++) , cashtabState)' as it is undefined.
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:13)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performSyncWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26096:20)
    at flushSyncCallbacks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:12042:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at Object.eventWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:107:28)
    at Object.wrapEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/wrapEvent.js:6:28)
    at Object.dispatchEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:45:22)
    at Object.dispatchUIEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:22:26)
    at Mouse.up (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/mouse.js:100:30)
    at PointerHost.release (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/index.js:84:28)
    at pointerAction (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:59:47)
    at Object.pointer (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:32:9)
    at Object.asyncWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:88:22)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:129:9)
====== CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet ======
TypeError: Cannot destructure property 'contactList' of '((cov_69iclqte5(...).s[56]++) , cashtabState)' as it is undefined.
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:13)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:135:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)
====== CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet ======
TypeError: Cannot destructure property 'contactList' of '((cov_69iclqte5(...).s[56]++) , cashtabState)' as it is undefined.
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:13)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:149:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)

Each failure log is accessible here:
CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist from localforage to context if they are present
CashTab Unit Tests: useWallet hook rendering in different localforage states Cashtab loads wallet, settings, cache, and contactlist as expected defaults if localforage is empty
CashTab Unit Tests: <App /> Navigation menu routes to expected components
CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet
CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet

only keep contactList key in state for now as that is all that is used, update tests, remove debug logs, improve comments

Failed tests logs:

====== CashTab Unit Tests: <App /> Navigation menu routes to expected components ======
TypeError: Cannot destructure property 'contactList' of '((cov_69iclqte5(...).s[56]++) , cashtabState)' as it is undefined.
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:13)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performSyncWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26096:20)
    at flushSyncCallbacks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:12042:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at Object.eventWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:107:28)
    at Object.wrapEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/wrapEvent.js:6:28)
    at Object.dispatchEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:45:22)
    at Object.dispatchUIEvent (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/event/dispatchEvent.js:22:26)
    at Mouse.up (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/mouse.js:100:30)
    at PointerHost.release (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/system/pointer/index.js:84:28)
    at pointerAction (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:59:47)
    at Object.pointer (/work/cashtab/node_modules/@testing-library/user-event/dist/cjs/pointer/index.js:32:9)
    at Object.asyncWrapper (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:88:22)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:129:9)
====== CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet ======
TypeError: Cannot destructure property 'contactList' of '((cov_69iclqte5(...).s[56]++) , cashtabState)' as it is undefined.
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:13)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:135:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)
====== CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet ======
TypeError: Cannot destructure property 'contactList' of '((cov_69iclqte5(...).s[56]++) , cashtabState)' as it is undefined.
    at contactList (/work/cashtab/src/components/Configure/Configure.js:476:13)
    at renderWithHooks (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:16305:18)
    at mountIndeterminateComponent (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:20074:13)
    at beginWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:21587:16)
    at beginWork$1 (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:27426:14)
    at performUnitOfWork (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26560:12)
    at workLoopSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26466:5)
    at renderRootSync (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:26434:7)
    at recoverFromConcurrentError (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (/work/cashtab/node_modules/react-dom/cjs/react-dom.development.js:25750:22)
    at flushActQueue (/work/cashtab/node_modules/react/cjs/react.development.js:2667:24)
    at act (/work/cashtab/node_modules/react/cjs/react.development.js:2582:11)
    at /work/cashtab/node_modules/@testing-library/react/dist/act-compat.js:46:25
    at renderRoot (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:180:26)
    at render (/work/cashtab/node_modules/@testing-library/react/dist/pure.js:266:10)
    at Object.<anonymous> (/work/cashtab/src/components/__tests__/App.test.js:149:15)
    at Promise.then.completed (/work/cashtab/node_modules/jest-circus/build/utils.js:298:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/work/cashtab/node_modules/jest-circus/build/utils.js:231:10)
    at _callCircusTest (/work/cashtab/node_modules/jest-circus/build/run.js:316:40)
    at _runTest (/work/cashtab/node_modules/jest-circus/build/run.js:252:3)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:126:9)
    at _runTestsForDescribeBlock (/work/cashtab/node_modules/jest-circus/build/run.js:121:9)
    at run (/work/cashtab/node_modules/jest-circus/build/run.js:71:3)
    at runAndTransformResultsToJestFormat (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
    at jestAdapter (/work/cashtab/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
    at runTestInternal (/work/cashtab/node_modules/jest-runner/build/runTest.js:367:16)
    at runTest (/work/cashtab/node_modules/jest-runner/build/runTest.js:444:34)
    at Object.worker (/work/cashtab/node_modules/jest-runner/build/testWorker.js:106:12)

Each failure log is accessible here:
CashTab Unit Tests: <App /> Navigation menu routes to expected components
CashTab Unit Tests: <App /> Renders the App screen showing normal wallet info for a created wallet
CashTab Unit Tests: <App /> Renders the onboarding screen if the user has no wallet

introduce a constant to hold state, handle test failure

bytesofman added inline comments.
cashtab/src/hooks/useWallet.js
87 ↗(On Diff #45348)

start with just contactList key as that is the only existing localforage key implemented in this diff

emack added a subscriber: emack.

Great approach, doesn't even need migration logic since it's updating the same key in localforage. I did a manual test and the existing wallet did not lose existing contacts either.

This revision is now accepted and ready to land.Feb 19 2024, 08:22