diff --git a/cypress/e2e/create-wallet.cy.ts b/cypress/e2e/create-wallet.cy.ts index fb652109eb..3c9a754b77 100644 --- a/cypress/e2e/create-wallet.cy.ts +++ b/cypress/e2e/create-wallet.cy.ts @@ -10,6 +10,7 @@ describe('Create wallet', () => { it('Should have generated a mnemonic', () => { cy.findByTestId('generated-mnemonic') + .should('be.visible') .invoke('text') .then(text => { generatedMnemonic = text diff --git a/cypress/e2e/scenario-transaction.cy.ts b/cypress/e2e/scenario-transaction.cy.ts index 143cb1ba80..770d3e958c 100644 --- a/cypress/e2e/scenario-transaction.cy.ts +++ b/cypress/e2e/scenario-transaction.cy.ts @@ -8,12 +8,14 @@ describe('Scenario : from mnemonic', () => { before(function () { cy.visit('/account/oasis1qq5t7f2gecsjsdxmp5zxtwgck6pzpjmkvc657z6l') + cy.contains('Loading account') cy.contains('Loading account').should('not.exist') cy.findByTestId('account-balance-total').then($div => { senderBalanceBefore = parseBalance($div.text()) }) cy.visit('/account/oasis1qz0k5q8vjqvu4s4nwxyj406ylnflkc4vrcjghuwk') + cy.contains('Loading account') cy.contains('Loading account').should('not.exist') cy.findByTestId('account-balance-total').then($div => { recipientBalanceBefore = parseBalance($div.text()) @@ -48,6 +50,7 @@ describe('Scenario : from mnemonic', () => { .should('be.eq', senderBalanceBefore - 10) cy.visit('/account/oasis1qz0k5q8vjqvu4s4nwxyj406ylnflkc4vrcjghuwk') + cy.contains('Loading account') cy.contains('Loading account').should('not.exist') cy.findByTestId('account-balance-total') .invoke('text') @@ -62,12 +65,14 @@ describe('Scenario : from private key', () => { before(function () { cy.visit('/account/oasis1qz0k5q8vjqvu4s4nwxyj406ylnflkc4vrcjghuwk') + cy.contains('Loading account') cy.contains('Loading account').should('not.exist') cy.findByTestId('account-balance-total').then($div => { senderBalanceBefore = parseBalance($div.text()) }) cy.visit('/account/oasis1qq5t7f2gecsjsdxmp5zxtwgck6pzpjmkvc657z6l') + cy.contains('Loading account') cy.contains('Loading account').should('not.exist') cy.findByTestId('account-balance-total').then($div => { recipientBalanceBefore = parseBalance($div.text()) @@ -100,6 +105,7 @@ describe('Scenario : from private key', () => { .should('be.eq', senderBalanceBefore - 10) cy.visit('/account/oasis1qq5t7f2gecsjsdxmp5zxtwgck6pzpjmkvc657z6l') + cy.contains('Loading account') cy.contains('Loading account').should('not.exist') cy.findByTestId('account-balance-total') .invoke('text') diff --git a/extension/src/popup/popup.tsx b/extension/src/popup/popup.tsx index 7ad74da623..25e1655d40 100644 --- a/extension/src/popup/popup.tsx +++ b/extension/src/popup/popup.tsx @@ -1,5 +1,5 @@ import React from 'react' -import ReactDOM from 'react-dom' +import { createRoot } from 'react-dom/client' import { Provider } from 'react-redux' import { HelmetProvider } from 'react-helmet-async' import { Store } from 'webext-redux' @@ -12,11 +12,12 @@ import 'locales/i18n' import 'sanitize.css/sanitize.css' import 'styles/main.css' -const MOUNT_NODE = document.getElementById('root') as HTMLElement +const container = document.getElementById('root') as HTMLElement +const root = createRoot(container!) const store = new Store() store.ready().then(() => { - ReactDOM.render( + root.render( @@ -28,7 +29,6 @@ store.ready().then(() => { , - MOUNT_NODE, ) }) diff --git a/package.json b/package.json index 4758548604..6d05dec481 100644 --- a/package.json +++ b/package.json @@ -73,15 +73,15 @@ "i18next": "21.9.2", "i18next-browser-languagedetector": "6.1.5", "qrcode.react": "3.1.0", - "react": "17.0.2", + "react": "18.2.0", "react-app-polyfill": "3.0.0", "react-data-table-component": "6.11.8", - "react-dom": "17.0.2", + "react-dom": "18.2.0", "react-helmet-async": "1.3.0", "react-i18next": "11.18.6", "react-redux": "7.2.9", "react-router-dom": "6.4.1", - "react-test-renderer": "17.0.2", + "react-test-renderer": "18.2.0", "redux-saga": "1.2.1", "styled-components": "5.3.6", "tweetnacl": "1.0.3", @@ -98,7 +98,7 @@ "@semantic-release/git": "10.0.1", "@testing-library/cypress": "8.0.3", "@testing-library/jest-dom": "5.16.5", - "@testing-library/react": "12.1.5", + "@testing-library/react": "13.4.0", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "14.4.3", "@types/body-scroll-lock": "3.1.0", @@ -108,10 +108,10 @@ "@types/node-fetch": "3.0.3", "@types/qrcode.react": "1.0.2", "@types/react": "17.0.50", - "@types/react-dom": "17.0.17", + "@types/react-dom": "18.0.6", "@types/react-redux": "7.1.24", "@types/react-router-dom": "5.3.3", - "@types/react-test-renderer": "17.0.2", + "@types/react-test-renderer": "18.0.0", "@types/rimraf": "3.0.2", "@types/shelljs": "0.8.11", "@types/styled-components": "5.1.26", @@ -162,6 +162,7 @@ }, "resolutions": { "@ledgerhq/hw-transport": "^6.27.6", + "@testing-library/dom": "8.18.1", "@typescript-eslint/eslint-plugin": "5.38.1", "eslint-plugin-react": "7.31.8" }, diff --git a/src/app/components/FatalErrorHandler/__tests__/index.test.tsx b/src/app/components/FatalErrorHandler/__tests__/index.test.tsx index 583fd1477a..e73779ba6b 100644 --- a/src/app/components/FatalErrorHandler/__tests__/index.test.tsx +++ b/src/app/components/FatalErrorHandler/__tests__/index.test.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react' +import { act, render, screen } from '@testing-library/react' import { fatalErrorActions } from 'app/state/fatalerror' import * as React from 'react' import { Provider } from 'react-redux' @@ -31,7 +31,9 @@ describe('', () => { it('should display the error', async () => { renderComponent(store) - store.dispatch(fatalErrorActions.setError({ message: 'dummy-message' })) + act(() => { + store.dispatch(fatalErrorActions.setError({ message: 'dummy-message' })) + }) expect(await screen.findByTestId('fatalerror-stacktrace')).toHaveTextContent('dummy-message') }) diff --git a/src/app/components/Toolbar/Features/NetworkSelector/__tests__/index.test.tsx b/src/app/components/Toolbar/Features/NetworkSelector/__tests__/index.test.tsx index 45af2e74fe..e24c5728fc 100644 --- a/src/app/components/Toolbar/Features/NetworkSelector/__tests__/index.test.tsx +++ b/src/app/components/Toolbar/Features/NetworkSelector/__tests__/index.test.tsx @@ -1,5 +1,4 @@ -import { screen } from '@testing-library/dom' -import { render } from '@testing-library/react' +import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { networkActions } from 'app/state/network' import * as React from 'react' @@ -34,7 +33,7 @@ describe('', () => { await userEvent.click(screen.getByTestId('network-selector')) expect(await screen.findByText('toolbar.networks.testnet')).toBeInTheDocument() - screen.getByText('toolbar.networks.testnet').click() + await userEvent.click(screen.getByText('toolbar.networks.testnet')) expect(dispatchSpy).toHaveBeenCalledWith({ payload: 'testnet', diff --git a/src/app/pages/AccountPage/__tests__/index.test.tsx b/src/app/pages/AccountPage/__tests__/index.test.tsx index 761202f041..abddc5f847 100644 --- a/src/app/pages/AccountPage/__tests__/index.test.tsx +++ b/src/app/pages/AccountPage/__tests__/index.test.tsx @@ -26,7 +26,7 @@ const renderPage = (store: any, initialEntries: LocationDescriptor[]) => - } /> + } /> diff --git a/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/__tests__/index.test.tsx b/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/__tests__/index.test.tsx index 20791ed189..2f462b2a8e 100644 --- a/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/__tests__/index.test.tsx +++ b/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/__tests__/index.test.tsx @@ -1,4 +1,4 @@ -import { cleanup, render, screen } from '@testing-library/react' +import { act, cleanup, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { importAccountsActions } from 'app/state/importaccounts' import { ImportAccountsStep } from 'app/state/importaccounts/types' @@ -47,20 +47,22 @@ describe('', () => { it('should list the accounts when done', () => { const component = renderComponent(store) - store.dispatch( - importAccountsActions.accountsListed([ - { - address: 'oasis1qzyqaxestzlum26e2vdgvkerm6d9qgdp7gh2pxqe', - balance: { available: '0', validator: { escrow: '0', escrow_debonding: '0' } }, - path: [44, 474, 0], - publicKey: '00', - selected: false, - type: WalletType.Mnemonic, - }, - ]), - ) + act(() => { + store.dispatch( + importAccountsActions.accountsListed([ + { + address: 'oasis1qzyqaxestzlum26e2vdgvkerm6d9qgdp7gh2pxqe', + balance: { available: '0', validator: { escrow: '0', escrow_debonding: '0' } }, + path: [44, 474, 0], + publicKey: '00', + selected: false, + type: WalletType.Mnemonic, + }, + ]), + ) - store.dispatch(importAccountsActions.setStep(ImportAccountsStep.Done)) + store.dispatch(importAccountsActions.setStep(ImportAccountsStep.Done)) + }) expect(component.getByText('oasis1qzyq...7gh2pxqe')).toBeInTheDocument() }) @@ -69,35 +71,38 @@ describe('', () => { jest.mocked(useDispatch).mockImplementation(() => dispatchFn) renderComponent(store) - store.dispatch( - importAccountsActions.accountsListed([ - { - address: 'oasis1qzyqaxestzlum26e2vdgvkerm6d9qgdp7gh2pxqe', - balance: { available: '0', validator: { escrow: '0', escrow_debonding: '0' } }, - path: [44, 474, 0], - publicKey: '00', - selected: false, - type: WalletType.Mnemonic, - }, - { - address: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', - balance: { available: '0', validator: { escrow: '0', escrow_debonding: '0' } }, - path: [44, 474, 1], - publicKey: '00', - selected: false, - type: WalletType.Mnemonic, - }, - ]), - ) + act(() => { + store.dispatch( + importAccountsActions.accountsListed([ + { + address: 'oasis1qzyqaxestzlum26e2vdgvkerm6d9qgdp7gh2pxqe', + balance: { available: '0', validator: { escrow: '0', escrow_debonding: '0' } }, + path: [44, 474, 0], + publicKey: '00', + selected: false, + type: WalletType.Mnemonic, + }, + { + address: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', + balance: { available: '0', validator: { escrow: '0', escrow_debonding: '0' } }, + path: [44, 474, 1], + publicKey: '00', + selected: false, + type: WalletType.Mnemonic, + }, + ]), + ) - store.dispatch(importAccountsActions.setStep(ImportAccountsStep.Done)) + store.dispatch(importAccountsActions.setStep(ImportAccountsStep.Done)) + }) await userEvent.click(screen.getByText('oasis1qzyq...7gh2pxqe')) expect(dispatchFn).toHaveBeenLastCalledWith({ payload: 0, type: importAccountsActions.toggleAccount.type, }) - store.dispatch(importAccountsActions.toggleAccount(0)) - + act(() => { + store.dispatch(importAccountsActions.toggleAccount(0)) + }) await userEvent.click(screen.getByTestId('ledger-open-accounts')) expect(dispatchFn).toHaveBeenLastCalledWith( expect.objectContaining({ type: walletActions.openWalletsFromLedger.type }), diff --git a/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/index.tsx b/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/index.tsx index a6a1c0201b..7f4a65db30 100644 --- a/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/index.tsx +++ b/src/app/pages/OpenWalletPage/Features/ImportAccountsSelectionModal/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react' +import React from 'react' import { useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' import { AlertBox } from 'app/components/AlertBox' @@ -61,13 +61,6 @@ export function ImportAccountsSelectionModal(props: ImportAccountsSelectionModal : walletActions.openWalletFromMnemonic(), ) } - - useEffect(() => { - return () => { - dispatch(importAccountsActions.clear()) - } - }, [dispatch]) - const cancelDisabled = importAccounts.step === ImportAccountsStep.Done || error ? false : true const confirmDisabled = importAccounts.step !== ImportAccountsStep.Done || selectedAccounts.length === 0 diff --git a/src/app/pages/StakingPage/Features/CommissionBounds/__tests__/index.test.tsx b/src/app/pages/StakingPage/Features/CommissionBounds/__tests__/index.test.tsx index f57a4ebd65..6d44630706 100644 --- a/src/app/pages/StakingPage/Features/CommissionBounds/__tests__/index.test.tsx +++ b/src/app/pages/StakingPage/Features/CommissionBounds/__tests__/index.test.tsx @@ -1,4 +1,4 @@ -import { render } from '@testing-library/react' +import { act, render } from '@testing-library/react' import { networkActions } from 'app/state/network' import { NetworkState } from 'app/state/network/types' import { CommissionBound as ICommissionBounds } from 'app/state/staking/types' @@ -42,7 +42,9 @@ describe('', () => { it('should match snapshot with active bounds', () => { store = configureAppStore() const component = renderComponent(store, [{ epochStart: 0, lower: 0.1, upper: 0.2, epochEnd: 100 }]) - store.dispatch(networkActions.networkSelected({ epoch: 50 } as NetworkState)) + act(() => { + store.dispatch(networkActions.networkSelected({ epoch: 50 } as NetworkState)) + }) expect(component.baseElement).toMatchSnapshot() }) }) diff --git a/src/app/pages/StakingPage/Features/DelegationList/__tests__/ActiveDelegationList.test.tsx b/src/app/pages/StakingPage/Features/DelegationList/__tests__/ActiveDelegationList.test.tsx index 22dcc9bd9f..eabba8d800 100644 --- a/src/app/pages/StakingPage/Features/DelegationList/__tests__/ActiveDelegationList.test.tsx +++ b/src/app/pages/StakingPage/Features/DelegationList/__tests__/ActiveDelegationList.test.tsx @@ -1,5 +1,5 @@ import userEvent from '@testing-library/user-event' -import { render, screen, waitFor } from '@testing-library/react' +import { act, render, screen, waitFor } from '@testing-library/react' import { Provider } from 'react-redux' import { ActiveDelegationList } from '../ActiveDelegationList' @@ -22,27 +22,29 @@ describe('', () => { it('should match snapshot', () => { const component = renderComponent(store) - store.dispatch( - stakingActions.updateDelegations({ - delegations: [ - { - amount: 100n.toString(), - shares: 100n.toString(), - validatorAddress: 'test-validator', - validator: { - current_rate: 0.07, - address: 'test-validator', - rank: 1, - status: 'active', - name: 'test-validator', - nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', - escrow: 1000n.toString(), + act(() => { + store.dispatch( + stakingActions.updateDelegations({ + delegations: [ + { + amount: 100n.toString(), + shares: 100n.toString(), + validatorAddress: 'test-validator', + validator: { + current_rate: 0.07, + address: 'test-validator', + rank: 1, + status: 'active', + name: 'test-validator', + nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', + escrow: 1000n.toString(), + }, }, - }, - ], - debondingDelegations: [], - }), - ) + ], + debondingDelegations: [], + }), + ) + }) expect(component.baseElement).toMatchSnapshot() @@ -52,31 +54,33 @@ describe('', () => { it('should expand and display the delegation on click', async () => { renderComponent(store) - store.dispatch( - stakingActions.updateDelegations({ - delegations: [ - { - amount: 100n.toString(), - shares: 100n.toString(), - validatorAddress: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', - validator: { - address: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', - rank: 1, - status: 'active', - name: 'test-validator1', - nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', - escrow: 1000n.toString(), + act(() => { + store.dispatch( + stakingActions.updateDelegations({ + delegations: [ + { + amount: 100n.toString(), + shares: 100n.toString(), + validatorAddress: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', + validator: { + address: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', + rank: 1, + status: 'active', + name: 'test-validator1', + nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', + escrow: 1000n.toString(), + }, }, - }, - { - amount: 50n.toString(), - shares: 50n.toString(), - validatorAddress: 'oasis1qq2vzcvxn0js5unsch5me2xz4kr43vcasv0d5eq4', - }, - ], - debondingDelegations: [], - }), - ) + { + amount: 50n.toString(), + shares: 50n.toString(), + validatorAddress: 'oasis1qq2vzcvxn0js5unsch5me2xz4kr43vcasv0d5eq4', + }, + ], + debondingDelegations: [], + }), + ) + }) let row = screen.getByText(/test-validator1/) expect(row).toBeVisible() diff --git a/src/app/pages/StakingPage/Features/DelegationList/__tests__/DebondingDelegationList.test.tsx b/src/app/pages/StakingPage/Features/DelegationList/__tests__/DebondingDelegationList.test.tsx index 9459c81dc7..755bf1b80e 100644 --- a/src/app/pages/StakingPage/Features/DelegationList/__tests__/DebondingDelegationList.test.tsx +++ b/src/app/pages/StakingPage/Features/DelegationList/__tests__/DebondingDelegationList.test.tsx @@ -1,5 +1,5 @@ import userEvent from '@testing-library/user-event' -import { screen, waitFor } from '@testing-library/react' +import { act, screen, waitFor } from '@testing-library/react' import * as React from 'react' import { render } from '@testing-library/react' @@ -24,62 +24,66 @@ describe('', () => { it('should match snapshot', () => { const component = renderComponent(store) - store.dispatch( - stakingActions.updateDelegations({ - delegations: [], - debondingDelegations: [ - { - epoch: 100, - amount: 100n.toString(), - shares: 100n.toString(), - validatorAddress: 'test-validator', - validator: { - current_rate: 0.1, - address: 'test-validator', - rank: 1, - status: 'active', - name: 'test-validator', - nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', - escrow: 1000n.toString(), + act(() => { + store.dispatch( + stakingActions.updateDelegations({ + delegations: [], + debondingDelegations: [ + { + epoch: 100, + amount: 100n.toString(), + shares: 100n.toString(), + validatorAddress: 'test-validator', + validator: { + current_rate: 0.1, + address: 'test-validator', + rank: 1, + status: 'active', + name: 'test-validator', + nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', + escrow: 1000n.toString(), + }, }, - }, - ], - }), - ) + ], + }), + ) + }) expect(component.baseElement).toMatchSnapshot() }) it('should expand and display the delegation on click', async () => { renderComponent(store) - store.dispatch( - stakingActions.updateDelegations({ - delegations: [], - debondingDelegations: [ - { - epoch: 100, - amount: 100n.toString(), - shares: 100n.toString(), - validatorAddress: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', - validator: { - address: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', - current_rate: 0, - rank: 1, - status: 'active', - name: 'test-validator1', - nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', - escrow: 1000n.toString(), + act(() => { + store.dispatch( + stakingActions.updateDelegations({ + delegations: [], + debondingDelegations: [ + { + epoch: 100, + amount: 100n.toString(), + shares: 100n.toString(), + validatorAddress: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', + validator: { + address: 'oasis1qqv25adrld8jjquzxzg769689lgf9jxvwgjs8tha', + current_rate: 0, + rank: 1, + status: 'active', + name: 'test-validator1', + nodeAddress: 'oasis1qq7pgk9v8l3hu2aenjtflezy5vajc2cz3y4d96rj', + escrow: 1000n.toString(), + }, }, - }, - { - amount: 50n.toString(), - shares: 50n.toString(), - validatorAddress: 'oasis1qq2vzcvxn0js5unsch5me2xz4kr43vcasv0d5eq4', - epoch: 100, - }, - ], - }), - ) + { + amount: 50n.toString(), + shares: 50n.toString(), + validatorAddress: 'oasis1qq2vzcvxn0js5unsch5me2xz4kr43vcasv0d5eq4', + epoch: 100, + }, + ], + }), + ) + }) let row = screen.getByText(/test-validator1/) expect(row).toBeVisible() diff --git a/src/app/pages/StakingPage/Features/ValidatorList/__tests__/index.test.tsx b/src/app/pages/StakingPage/Features/ValidatorList/__tests__/index.test.tsx index 651f2f9ba3..b8dcfe4a9c 100644 --- a/src/app/pages/StakingPage/Features/ValidatorList/__tests__/index.test.tsx +++ b/src/app/pages/StakingPage/Features/ValidatorList/__tests__/index.test.tsx @@ -1,5 +1,5 @@ import { NodeInternal } from '@oasisprotocol/client/dist/client' -import { render, screen, waitFor } from '@testing-library/react' +import { act, render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { stakingActions } from 'app/state/staking' import { Validator } from 'app/state/staking/types' @@ -75,37 +75,43 @@ describe('', () => { it('empty should match snapshot', () => { const component = renderComponent(store) - store.dispatch( - stakingActions.updateValidators({ - timestamp: new Date('2022').getTime(), - network: 'mainnet', - list: [], - }), - ) + act(() => { + store.dispatch( + stakingActions.updateValidators({ + timestamp: new Date('2022').getTime(), + network: 'mainnet', + list: [], + }), + ) + }) expect(component.container.firstChild).toMatchSnapshot() }) it('list should match snapshot', () => { const component = renderComponent(store) - store.dispatch( - stakingActions.updateValidators({ - timestamp: new Date('2022').getTime(), - network: 'mainnet', - list: [activeValidator, inactiveValidator, unknownValidator], - }), - ) + act(() => { + store.dispatch( + stakingActions.updateValidators({ + timestamp: new Date('2022').getTime(), + network: 'mainnet', + list: [activeValidator, inactiveValidator, unknownValidator], + }), + ) + }) expect(component.container.firstChild).toMatchSnapshot() }) it('should display validator details on click', async () => { renderComponent(store) - store.dispatch( - stakingActions.updateValidators({ - timestamp: new Date('2022').getTime(), - network: 'mainnet', - list: [activeValidator], - }), - ) + act(() => { + store.dispatch( + stakingActions.updateValidators({ + timestamp: new Date('2022').getTime(), + network: 'mainnet', + list: [activeValidator], + }), + ) + }) let row = screen.getByText(/test-validator/) expect(row).toBeVisible() @@ -121,13 +127,15 @@ describe('', () => { it('should only display the details of a single validator', async () => { renderComponent(store) - store.dispatch( - stakingActions.updateValidators({ - timestamp: new Date('2022').getTime(), - network: 'mainnet', - list: [activeValidator, inactiveValidator], - }), - ) + act(() => { + store.dispatch( + stakingActions.updateValidators({ + timestamp: new Date('2022').getTime(), + network: 'mainnet', + list: [activeValidator, inactiveValidator], + }), + ) + }) let row = screen.getByText(/test-validator1/) expect(row).toBeVisible() diff --git a/src/app/state/wallet/saga.test.ts b/src/app/state/wallet/saga.test.ts index 989d026b24..d3bd4459a3 100644 --- a/src/app/state/wallet/saga.test.ts +++ b/src/app/state/wallet/saga.test.ts @@ -7,6 +7,7 @@ import { walletActions } from '.' import { transactionActions } from '../transaction' import { getBalance, rootWalletSaga, walletSaga } from './saga' import { AddWalletPayload, WalletType } from './types' +import { importAccountsActions } from '../importaccounts' describe('Wallet Sagas', () => { const validPrivateKeyHex = @@ -47,6 +48,7 @@ describe('Wallet Sagas', () => { .withState(state) .dispatch(walletActions.openWalletFromMnemonic()) .fork(walletSaga) + .put(importAccountsActions.clear()) .put( walletActions.addWallet({ address: 'oasis1qq2vzcvxn0js5unsch5me2xz4kr43vcasv0d5eq4', @@ -91,6 +93,7 @@ describe('Wallet Sagas', () => { .withState(state) .dispatch(walletActions.openWalletsFromLedger()) .fork(walletSaga) + .put(importAccountsActions.clear()) .put.actionType(walletActions.selectWallet.type) .silentRun(50) }) diff --git a/src/app/state/wallet/saga.ts b/src/app/state/wallet/saga.ts index e14bcc3f37..a6f9bab5c1 100644 --- a/src/app/state/wallet/saga.ts +++ b/src/app/state/wallet/saga.ts @@ -5,6 +5,7 @@ import { call, delay, fork, put, select, take, takeEvery } from 'typed-redux-sag import { selectSelectedAccounts } from 'app/state/importaccounts/selectors' import { walletActions } from '.' +import { importAccountsActions } from '../importaccounts' import { ImportAccountsListAccount } from '../importaccounts/types' import { getOasisNic } from '../network/saga' import { transactionActions } from '../transaction' @@ -57,6 +58,7 @@ function* getWalletByAddress(address: string) { */ export function* openWalletsFromLedger() { const accounts: ImportAccountsListAccount[] = yield* select(selectSelectedAccounts) + yield* put(importAccountsActions.clear()) for (const account of accounts) { yield* put( walletActions.addWallet({ @@ -92,6 +94,7 @@ export function* openWalletFromPrivateKey({ payload: privateKey }: PayloadAction export function* openWalletFromMnemonic() { const accounts: ImportAccountsListAccount[] = yield* select(selectSelectedAccounts) + yield* put(importAccountsActions.clear()) for (const account of accounts) { yield* put( walletActions.addWallet({ diff --git a/src/index.tsx b/src/index.tsx index 5e03a1d16c..bac8b1ad83 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -9,7 +9,7 @@ import 'react-app-polyfill/ie11' import 'react-app-polyfill/stable' import * as React from 'react' -import * as ReactDOM from 'react-dom' +import { createRoot } from 'react-dom/client' import { Provider } from 'react-redux' // Use consistent styling @@ -31,9 +31,10 @@ import './locales/i18n' import './styles/main.css' const store = configureAppStore() -const MOUNT_NODE = document.getElementById('root') as HTMLElement +const container = document.getElementById('root') as HTMLElement +const root = createRoot(container!) -ReactDOM.render( +root.render( @@ -45,5 +46,4 @@ ReactDOM.render( , - MOUNT_NODE, ) diff --git a/src/locales/__tests__/strict-translation-keys.test.tsx b/src/locales/__tests__/strict-translation-keys.test.tsx index 548de93bec..c258610a43 100644 --- a/src/locales/__tests__/strict-translation-keys.test.tsx +++ b/src/locales/__tests__/strict-translation-keys.test.tsx @@ -21,16 +21,24 @@ describe('type-only test', () => { function Component() { const { t } = useTranslation() return ( -
- {/* @ts-expect-error Expect typescript to detect incorrect key */} - {t('menu.does_not_exist')} - {/* @ts-expect-error Expect typescript to detect incorrect key */} - {t('menu.does_not_exist', 'Default')} - {/* @ts-expect-error Expect typescript to detect incorrect key */} - - {/* @ts-expect-error Expect typescript to detect incorrect key */} - -
+ <> +
+ {/* @ts-expect-error Expect typescript to detect incorrect key */} + {t('menu.does_not_exist')} +
+
+ {/* @ts-expect-error Expect typescript to detect incorrect key */} + {t('menu.does_not_exist', 'Default')} +
+
+ {/* @ts-expect-error Expect typescript to detect incorrect key */} + +
+
+ {/* @ts-expect-error Expect typescript to detect incorrect key */} + +
+ ) } expect().toBeDefined() diff --git a/src/utils/__tests__/loadable.test.tsx b/src/utils/__tests__/loadable.test.tsx index 6322b727ea..5d571fbc7c 100644 --- a/src/utils/__tests__/loadable.test.tsx +++ b/src/utils/__tests__/loadable.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { render } from '@testing-library/react' +import { render, screen } from '@testing-library/react' import { lazyLoad } from 'utils/loadable' const LoadingIndicator = () =>
Loading
@@ -42,10 +42,8 @@ describe('loadable', () => { }) it('should render LazyComponent after waiting for it to load', async () => { - const { - container: { firstChild }, - } = render() - LazyComponentWithExportedFunction({}) - expect(firstChild).toMatchSnapshot() + const component = render() + expect(await screen.findByText(/lazy-loaded/)).toBeInTheDocument() + expect(component.container.firstChild).toMatchSnapshot() }) }) diff --git a/yarn.lock b/yarn.lock index 691a4d9bcd..4810f12833 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3533,31 +3533,17 @@ "@babel/runtime" "^7.14.6" "@testing-library/dom" "^8.1.0" -"@testing-library/dom@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.0.0.tgz#2bb994393c566aae021db86dd263ba06e8b71b38" - integrity sha512-Ym375MTOpfszlagRnTMO+FOfTt6gRrWiDOWmEnWLu9OvwCPOWtK6i5pBHmZ07wUJiQ7wWz0t8+ZBK2wFo2tlew== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/runtime" "^7.12.5" - "@types/aria-query" "^4.2.0" - aria-query "^4.2.2" - chalk "^4.1.0" - dom-accessibility-api "^0.5.6" - lz-string "^1.4.4" - pretty-format "^27.0.2" - -"@testing-library/dom@^8.1.0": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.1.0.tgz#f8358b1883844ea569ba76b7e94582168df5370d" - integrity sha512-kmW9alndr19qd6DABzQ978zKQ+J65gU2Rzkl8hriIetPnwpesRaK4//jEQyYh8fEALmGhomD/LBQqt+o+DL95Q== +"@testing-library/dom@8.18.1", "@testing-library/dom@^8.1.0", "@testing-library/dom@^8.5.0": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.18.1.tgz#80f91be02bc171fe5a3a7003f88207be31ac2cf3" + integrity sha512-oEvsm2B/WtcHKE+IcEeeCqNU/ltFGaVyGbpcm4g/2ytuT49jrlH9x5qRKL/H3A6yfM4YAbSbC0ceT5+9CEXnLg== dependencies: "@babel/code-frame" "^7.10.4" "@babel/runtime" "^7.12.5" "@types/aria-query" "^4.2.0" - aria-query "^4.2.2" + aria-query "^5.0.0" chalk "^4.1.0" - dom-accessibility-api "^0.5.6" + dom-accessibility-api "^0.5.9" lz-string "^1.4.4" pretty-format "^27.0.2" @@ -3584,14 +3570,14 @@ "@babel/runtime" "^7.12.5" react-error-boundary "^3.1.0" -"@testing-library/react@12.1.5": - version "12.1.5" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.5.tgz#bb248f72f02a5ac9d949dea07279095fa577963b" - integrity sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg== +"@testing-library/react@13.4.0": + version "13.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.4.0.tgz#6a31e3bf5951615593ad984e96b9e5e2d9380966" + integrity sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw== dependencies: "@babel/runtime" "^7.12.5" - "@testing-library/dom" "^8.0.0" - "@types/react-dom" "<18.0.0" + "@testing-library/dom" "^8.5.0" + "@types/react-dom" "^18.0.0" "@testing-library/user-event@14.4.3": version "14.4.3" @@ -3863,12 +3849,12 @@ dependencies: "@types/react" "*" -"@types/react-dom@17.0.17", "@types/react-dom@<18.0.0": - version "17.0.17" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.17.tgz#2e3743277a793a96a99f1bf87614598289da68a1" - integrity sha512-VjnqEmqGnasQKV0CWLevqMTXBYG9GbwuE6x3VetERLh0cq2LTptFE73MrQi2S7GkKXCf2GgwItB/melLnxfnsg== +"@types/react-dom@18.0.6", "@types/react-dom@^18.0.0": + version "18.0.6" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.6.tgz#36652900024842b74607a17786b6662dd1e103a1" + integrity sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA== dependencies: - "@types/react" "^17" + "@types/react" "*" "@types/react-redux@7.1.24", "@types/react-redux@^7.1.20": version "7.1.24" @@ -3897,12 +3883,12 @@ "@types/history" "^4.7.11" "@types/react" "*" -"@types/react-test-renderer@17.0.2": - version "17.0.2" - resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.2.tgz#5f800a39b12ac8d2a2149e7e1885215bcf4edbbf" - integrity sha512-+F1KONQTBHDBBhbHuT2GNydeMpPuviduXIVJRB7Y4nma4NR5DrTJfMMZ+jbhEHbpwL+Uqhs1WXh4KHiyrtYTPg== +"@types/react-test-renderer@18.0.0": + version "18.0.0" + resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-18.0.0.tgz#7b7f69ca98821ea5501b21ba24ea7b6139da2243" + integrity sha512-C7/5FBJ3g3sqUahguGi03O79b8afNeSD6T8/GU50oQrJCU0bVCCGQHaGKUbg2Ce8VQEEqTw8/HiS6lXHHdgkdQ== dependencies: - "@types/react" "^17" + "@types/react" "*" "@types/react@*": version "17.0.3" @@ -3922,15 +3908,6 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@^17": - version "17.0.45" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.45.tgz#9b3d5b661fd26365fefef0e766a1c6c30ccf7b3f" - integrity sha512-YfhQ22Lah2e3CHPsb93tRwIGNiSwkuz1/blk4e6QrWS0jQzCSNbGLtOEYhPg02W0yGTTmpajp7dCTbBAMN3qsg== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - "@types/retry@^0.12.0": version "0.12.0" resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz" @@ -6241,6 +6218,11 @@ dom-accessibility-api@^0.5.6: resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9" integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw== +dom-accessibility-api@^0.5.9: + version "0.5.14" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56" + integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg== + dom-serializer@^1.0.1: version "1.3.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" @@ -11712,14 +11694,13 @@ react-data-table-component@6.11.8: lodash.orderby "^4.6.0" shortid "^2.2.16" -react-dom@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== +react-dom@18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" + scheduler "^0.23.0" react-error-boundary@^3.1.0: version "3.1.4" @@ -11757,20 +11738,20 @@ react-i18next@11.18.6: "@babel/runtime" "^7.14.5" html-parse-stringify "^3.0.1" -"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1, react-is@^17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +react-is@^17.0.1, react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== react-redux@7.2.9: version "7.2.9" @@ -11804,31 +11785,29 @@ react-router@6.4.1: dependencies: "@remix-run/router" "1.0.1" -react-shallow-renderer@^16.13.1: - version "16.14.1" - resolved "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz" - integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg== +react-shallow-renderer@^16.15.0: + version "16.15.0" + resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457" + integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA== dependencies: object-assign "^4.1.1" - react-is "^16.12.0 || ^17.0.0" + react-is "^16.12.0 || ^17.0.0 || ^18.0.0" -react-test-renderer@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz" - integrity sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ== +react-test-renderer@18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-18.2.0.tgz#1dd912bd908ff26da5b9fca4fd1c489b9523d37e" + integrity sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA== dependencies: - object-assign "^4.1.1" - react-is "^17.0.2" - react-shallow-renderer "^16.13.1" - scheduler "^0.20.2" + react-is "^18.2.0" + react-shallow-renderer "^16.15.0" + scheduler "^0.23.0" -react@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +react@18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" read-cmd-shim@^3.0.0: version "3.0.1" @@ -12339,13 +12318,12 @@ saxes@^6.0.0: dependencies: xmlchars "^2.2.0" -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" semantic-release@19.0.5: version "19.0.5"