From d2e5a33e6be778fc80db8cae30f24a40ed8b7901 Mon Sep 17 00:00:00 2001 From: David Rojas Date: Tue, 29 Oct 2024 20:35:24 -0400 Subject: [PATCH 1/4] Added page titles --- src/features/accounts/pages/account-page.tsx | 2 + .../pages/create-app-interface.tsx | 2 + src/features/app-lab/pages/app-lab.tsx | 2 + .../applications/pages/application-page.tsx | 2 + src/features/assets/pages/asset-page.tsx | 2 + src/features/blocks/pages/block-page.tsx | 2 + src/features/explore/pages/explore-page.tsx | 2 + src/features/fund/fund-page.tsx | 2 + src/features/groups/pages/group-page.tsx | 2 + src/features/settings/pages/settings-page.tsx | 2 + .../transaction-wizard-page.tsx | 2 + .../pages/inner-transaction-page.tsx | 2 + .../transactions/pages/transaction-page.tsx | 2 + src/utils/use-title.ts | 47 +++++++++++++++++++ 14 files changed, 73 insertions(+) create mode 100644 src/utils/use-title.ts diff --git a/src/features/accounts/pages/account-page.tsx b/src/features/accounts/pages/account-page.tsx index 5b326b0b..77178122 100644 --- a/src/features/accounts/pages/account-page.tsx +++ b/src/features/accounts/pages/account-page.tsx @@ -10,6 +10,7 @@ import { AccountDetails } from '../components/account-details' import { useCallback } from 'react' import { PageTitle } from '@/features/common/components/page-title' import { PageLoader } from '@/features/common/components/page-loader' +import { useTitle } from '@/utils/use-title' export const accountPageTitle = 'Account' export const accountInvalidAddressMessage = 'Address is invalid' @@ -29,6 +30,7 @@ export function AccountPage() { const { address } = useRequiredParam(UrlParams.Address) invariant(isAddress(address), accountInvalidAddressMessage) const [loadableAccount, refreshAccount, isStale] = useLoadableAccount(address) + useTitle() const refresh = useCallback(() => { refreshAccount() diff --git a/src/features/app-interfaces/pages/create-app-interface.tsx b/src/features/app-interfaces/pages/create-app-interface.tsx index 4debab65..9fe0574e 100644 --- a/src/features/app-interfaces/pages/create-app-interface.tsx +++ b/src/features/app-interfaces/pages/create-app-interface.tsx @@ -14,6 +14,7 @@ import { useCreateAppInterface } from '../data' import { FromAppIdCard } from '../components/create/from-app-id-card' import { FromDeploymentCard } from '../components/create/from-deployment-card' import { asError } from '@/utils/error' +import { useTitle } from '@/utils/use-title' export const createAppInterfacePageTitle = 'Create App Interface' @@ -103,6 +104,7 @@ function CreateAppInterfaceInner() { } export function CreateAppInterface() { + useTitle('Create App Interface') return ( <> diff --git a/src/features/app-lab/pages/app-lab.tsx b/src/features/app-lab/pages/app-lab.tsx index 18b5f700..ccef1d26 100644 --- a/src/features/app-lab/pages/app-lab.tsx +++ b/src/features/app-lab/pages/app-lab.tsx @@ -3,11 +3,13 @@ import { useAppInterfaces } from '@/features/app-interfaces/data' import { RenderLoadable } from '@/features/common/components/render-loadable' import { PageLoader } from '@/features/common/components/page-loader' import { AppInterfaces } from '@/features/app-interfaces/components/app-interfaces' +import { useTitle } from '@/utils/use-title' export const appLabPageTitle = 'App Lab' export function AppLab() { const [appInterfaces, refreshAppInterfaces] = useAppInterfaces() + useTitle('App Lab') return ( <> diff --git a/src/features/applications/pages/application-page.tsx b/src/features/applications/pages/application-page.tsx index b7dc80f0..eae25425 100644 --- a/src/features/applications/pages/application-page.tsx +++ b/src/features/applications/pages/application-page.tsx @@ -9,6 +9,7 @@ import { is404 } from '@/utils/error' import { useCallback } from 'react' import { PageTitle } from '@/features/common/components/page-title' import { PageLoader } from '@/features/common/components/page-loader' +import { useTitle } from '@/utils/use-title' const transformError = (e: Error) => { if (is404(e)) { @@ -31,6 +32,7 @@ export function ApplicationPage() { const applicationId = parseInt(_applicationId, 10) const [loadableApplication, refreshApplication, isStale] = useLoadableApplication(applicationId) + useTitle() const refresh = useCallback(() => { refreshApplication() diff --git a/src/features/assets/pages/asset-page.tsx b/src/features/assets/pages/asset-page.tsx index c7c3213f..baf8f567 100644 --- a/src/features/assets/pages/asset-page.tsx +++ b/src/features/assets/pages/asset-page.tsx @@ -9,6 +9,7 @@ import { useLoadableAsset } from '../data' import { useCallback } from 'react' import { PageTitle } from '@/features/common/components/page-title' import { PageLoader } from '@/features/common/components/page-loader' +import { useTitle } from '@/utils/use-title' const transformError = (e: Error) => { if (is404(e)) { @@ -31,6 +32,7 @@ export function AssetPage() { const assetId = parseInt(_assetId, 10) const [loadableAsset, refreshAsset, isStale] = useLoadableAsset(assetId) + useTitle() const refresh = useCallback(() => { refreshAsset() diff --git a/src/features/blocks/pages/block-page.tsx b/src/features/blocks/pages/block-page.tsx index 24641a3e..610f08e3 100644 --- a/src/features/blocks/pages/block-page.tsx +++ b/src/features/blocks/pages/block-page.tsx @@ -8,6 +8,7 @@ import { useLoadableBlock } from '../data' import { isInteger } from '@/utils/is-integer' import { PageTitle } from '@/features/common/components/page-title' import { PageLoader } from '@/features/common/components/page-loader' +import { useTitle } from '@/utils/use-title' const transformError = (e: Error) => { if (is404(e)) { @@ -25,6 +26,7 @@ export const blockInvalidRoundMessage = 'Round is invalid' export const blockFailedToLoadMessage = 'Block failed to load' export function BlockPage() { + useTitle() const { round: _round } = useRequiredParam(UrlParams.Round) invariant(isInteger(_round), blockInvalidRoundMessage) const round = parseInt(_round, 10) diff --git a/src/features/explore/pages/explore-page.tsx b/src/features/explore/pages/explore-page.tsx index 177fcc0e..b4bcdd20 100644 --- a/src/features/explore/pages/explore-page.tsx +++ b/src/features/explore/pages/explore-page.tsx @@ -5,11 +5,13 @@ import { LatestTransactions } from '@/features/transactions/components/latest-tr import { Switch } from '@/features/common/components/switch' import { Label } from '@/features/common/components/label' import { useLiveExplorer } from '@/features/explore/data/live-explorer' +import { useTitle } from '@/utils/use-title' export const explorePageTitle = 'Explore' export function ExplorePage() { const { showLiveUpdates, setShowLiveUpdates, latestTransactions, latestBlocks } = useLiveExplorer() + useTitle('Explore') return ( <> diff --git a/src/features/fund/fund-page.tsx b/src/features/fund/fund-page.tsx index 020cf332..8813b010 100644 --- a/src/features/fund/fund-page.tsx +++ b/src/features/fund/fund-page.tsx @@ -2,12 +2,14 @@ import { PageTitle } from '@/features/common/components/page-title' import { localnetId, useNetworkConfig } from '@/features/network/data' import { LocalnetFunding } from './components/localnet-funding' import { DispenserApiFunding } from './components/dispenser-api-funding' +import { useTitle } from '@/utils/use-title' export const fundPageTitle = 'Fund' export const fundingNotAvailableMessage = 'Funding is not available on this network.' export function FundPage() { const networkConfig = useNetworkConfig() + useTitle('Fund') const inner = networkConfig.id === localnetId ? ( diff --git a/src/features/groups/pages/group-page.tsx b/src/features/groups/pages/group-page.tsx index 3ca89c01..a826d864 100644 --- a/src/features/groups/pages/group-page.tsx +++ b/src/features/groups/pages/group-page.tsx @@ -8,6 +8,7 @@ import { invariant } from '@/utils/invariant' import { isInteger } from '@/utils/is-integer' import { PageTitle } from '@/features/common/components/page-title' import { PageLoader } from '@/features/common/components/page-loader' +import { useTitle } from '@/utils/use-title' export const groupPageTitle = 'Transaction Group' export const groupNotFoundMessage = 'Transaction group not found' @@ -28,6 +29,7 @@ export function GroupPage() { const { round: _round } = useRequiredParam(UrlParams.Round) invariant(isInteger(_round), blockInvalidRoundMessage) const { groupId } = useRequiredParam(UrlParams.GroupId) + useTitle() const round = parseInt(_round, 10) const loadableGroup = useLoadableGroup(groupId, round) diff --git a/src/features/settings/pages/settings-page.tsx b/src/features/settings/pages/settings-page.tsx index 98d9ea24..0f3299fa 100644 --- a/src/features/settings/pages/settings-page.tsx +++ b/src/features/settings/pages/settings-page.tsx @@ -1,9 +1,11 @@ +import { useTitle } from '@/utils/use-title' import { Settings } from '../components/settings' import { PageTitle } from '@/features/common/components/page-title' export const settingsPageTitle = 'Settings' export function SettingsPage() { + useTitle('Settings') return ( <> diff --git a/src/features/transaction-wizard/transaction-wizard-page.tsx b/src/features/transaction-wizard/transaction-wizard-page.tsx index 484f32b1..b6b4f428 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.tsx @@ -9,6 +9,7 @@ import { SendTransactionResults } from '@algorandfoundation/algokit-utils/types/ import { AppCallTransaction, TransactionType } from '../transactions/models' import { GroupSendResults, SendResults } from './components/group-send-results' import algosdk from 'algosdk' +import { useTitle } from '@/utils/use-title' export const transactionWizardPageTitle = 'Transaction Wizard' export const transactionTypeLabel = 'Transaction type' @@ -16,6 +17,7 @@ export const sendButtonLabel = 'Send' export function TransactionWizardPage() { const [sendResults, setSendResults] = useState(undefined) + useTitle('Transaction Wizard') const renderTransactionResults = useCallback((result: SendTransactionResults, simulateResponse?: algosdk.modelsv2.SimulateResponse) => { const sentTransactions = asTransactionFromSendResult(result) diff --git a/src/features/transactions/pages/inner-transaction-page.tsx b/src/features/transactions/pages/inner-transaction-page.tsx index 9fdbea9c..5f5c3ab9 100644 --- a/src/features/transactions/pages/inner-transaction-page.tsx +++ b/src/features/transactions/pages/inner-transaction-page.tsx @@ -10,6 +10,7 @@ import { is404 } from '@/utils/error' import { PageTitle } from '@/features/common/components/page-title' import { PageLoader } from '@/features/common/components/page-loader' import { useSplatParam } from '@/features/common/hooks/use-splat-param' +import { useTitle } from '@/utils/use-title' const transformError = (e: Error) => { if (is404(e)) { @@ -34,6 +35,7 @@ export function InnerTransactionPage() { invariant(isValidInnerTransactionId(innerTransactionId), `Invalid inner transaction id: ${innerTransactionId}`) const loadableTransaction = useLoadableInnerTransactionAtom(transactionId, innerTransactionId) + useTitle() return ( <> diff --git a/src/features/transactions/pages/transaction-page.tsx b/src/features/transactions/pages/transaction-page.tsx index 611801c6..b2fd3ac7 100644 --- a/src/features/transactions/pages/transaction-page.tsx +++ b/src/features/transactions/pages/transaction-page.tsx @@ -8,6 +8,7 @@ import { useLoadableTransactionAtom } from '../data' import { isTransactionId } from '@/utils/is-transaction-id' import { PageTitle } from '@/features/common/components/page-title' import { PageLoader } from '@/features/common/components/page-loader' +import { useTitle } from '@/utils/use-title' const transformError = (e: Error) => { if (is404(e)) { @@ -28,6 +29,7 @@ export function TransactionPage() { const { transactionId } = useRequiredParam(UrlParams.TransactionId) invariant(isTransactionId(transactionId), transactionInvalidIdMessage) const loadableTransaction = useLoadableTransactionAtom(transactionId) + useTitle() return ( <> diff --git a/src/utils/use-title.ts b/src/utils/use-title.ts new file mode 100644 index 00000000..c45e158c --- /dev/null +++ b/src/utils/use-title.ts @@ -0,0 +1,47 @@ +import { useEffect } from 'react' +import { useParams } from 'react-router-dom' + +const setTitle = (title: string) => { + document.title = title +} + +export const useTitle = (customString?: string) => { + const urlParams = useParams() + useEffect(() => { + const currentTitle = document.title + let pageTitle = `Lora` + if (customString) { + pageTitle += ` ${customString}` + } + if (urlParams.transactionId) { + pageTitle += ` - TxnId:${urlParams.transactionId}` + } + if (urlParams.transactionId && urlParams['*']) { + pageTitle += `, Inner:${urlParams['*']}` + } + if (urlParams.round) { + pageTitle += ` - Block:${urlParams.round}` + } + if (urlParams?.groupId) { + pageTitle += ` - Group:${urlParams.groupId}` + } + if (urlParams?.address) { + pageTitle += ` - Addr:${urlParams.address}` + } + if (urlParams?.applicationId) { + pageTitle += ` - AppId:${urlParams.applicationId}` + } + if (urlParams?.assetId) { + pageTitle += ` - AssetId:${urlParams.assetId}` + } + if (urlParams?.networkId) { + pageTitle += ` - ${urlParams.networkId}` + } + + setTitle(pageTitle) + + return () => { + setTitle(currentTitle) + } + }, [customString, urlParams]) +} From 9cc620018117caa586cfedda761159308005d9ec Mon Sep 17 00:00:00 2001 From: David Rojas Date: Wed, 30 Oct 2024 18:19:57 -0400 Subject: [PATCH 2/4] Fixed broken pages tests due to useTitle hook --- .../pages/create-app-interface.test.tsx | 5 +++++ src/features/explore/pages/explore-page.test.tsx | 11 +++++++++-- src/features/fund/fund-page.test.tsx | 8 +++++++- src/features/settings/pages/settings-page.test.tsx | 4 +++- .../transaction-wizard-page.test.tsx | 3 +++ src/utils/use-title.ts | 1 + 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/features/app-interfaces/pages/create-app-interface.test.tsx b/src/features/app-interfaces/pages/create-app-interface.test.tsx index 2f825b82..c4a7ff88 100644 --- a/src/features/app-interfaces/pages/create-app-interface.test.tsx +++ b/src/features/app-interfaces/pages/create-app-interface.test.tsx @@ -9,6 +9,7 @@ import { useWallet } from '@txnlab/use-wallet' import SampleSixAppSpec from '@/tests/test-app-specs/sample-six.arc32.json' import { Arc32AppSpec } from '../data/types' import { selectOption } from '@/tests/utils/select-option' +import { useParams } from 'react-router-dom' describe('create-app-interface', () => { const localnet = algorandFixture() @@ -19,6 +20,7 @@ describe('create-app-interface', () => { describe('when a wallet is connected', () => { beforeEach(async () => { + vi.mocked(useParams).mockReturnValue({}) await setWalletAddressAndSigner(localnet) }) @@ -38,6 +40,7 @@ describe('create-app-interface', () => { it('can deploy an app with template parameters', () => { const appSpec = SampleSixAppSpec as Arc32AppSpec + vi.mocked(useParams).mockReturnValue({}) return executeComponentTest( () => { return render() @@ -106,6 +109,8 @@ describe('create-app-interface', () => { describe('when a wallet is not connected', () => { beforeEach(async () => { const original = await vi.importActual<{ useWallet: () => ReturnType }>('@txnlab/use-wallet') + vi.mocked(useParams).mockReturnValue({}) + vi.mocked(useWallet).mockImplementation(() => { return { ...original.useWallet(), diff --git a/src/features/explore/pages/explore-page.test.tsx b/src/features/explore/pages/explore-page.test.tsx index 928f050e..8139c788 100644 --- a/src/features/explore/pages/explore-page.test.tsx +++ b/src/features/explore/pages/explore-page.test.tsx @@ -1,7 +1,7 @@ import { executeComponentTest } from '@/tests/test-component' import { getAllByRole, getByRole, queryAllByRole, render, waitFor } from '@/tests/testing-library' import { Atom, createStore } from 'jotai' -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi } from 'vitest' import { ExplorePage } from './explore-page' import { latestBlocksTitle } from '@/features/blocks/components/latest-blocks' import { latestTransactionsTitle } from '@/features/transactions/components/latest-transactions' @@ -16,12 +16,14 @@ import { randomNumberBetween } from '@makerx/ts-dossier' import { ellipseId } from '@/utils/ellipse-id' import { ellipseAddress } from '@/utils/ellipse-address' import { createReadOnlyAtomAndTimestamp, createTimestamp } from '@/features/common/data' +import { useParams } from 'react-router-dom' describe('explore-page', () => { describe('when no blocks are available', () => { const myStore = createStore() - it('no latest blocks are displayed', () => { + it.only('no latest blocks are displayed', () => { + vi.mocked(useParams).mockReturnValue({ round: '1234' }) return executeComponentTest( () => render(, undefined, myStore), async (component) => { @@ -36,6 +38,7 @@ describe('explore-page', () => { }) it('no latest transactions are displayed', () => { + vi.mocked(useParams).mockReturnValue({ round: '1234' }) return executeComponentTest( () => render(, undefined, myStore), async (component) => { @@ -64,6 +67,7 @@ describe('explore-page', () => { myStore.set(syncedRoundAtom, block.round) it('the processed blocks are displayed', () => { + vi.mocked(useParams).mockReturnValue({ round: '1234' }) return executeComponentTest( () => render(, undefined, myStore), async (component) => { @@ -83,6 +87,7 @@ describe('explore-page', () => { }) it('the available transactions are displayed', () => { + vi.mocked(useParams).mockReturnValue({ round: '1234' }) return executeComponentTest( () => render(, undefined, myStore), async (component) => { @@ -130,6 +135,7 @@ describe('explore-page', () => { myStore.set(transactionResultsAtom, data.transactions) myStore.set(blockResultsAtom, data.blocks) myStore.set(syncedRoundAtom, data.syncedRound) + vi.mocked(useParams).mockReturnValue({ round: '1234' }) return executeComponentTest( () => render(, undefined, myStore), @@ -156,6 +162,7 @@ describe('explore-page', () => { myStore.set(blockResultsAtom, data.blocks) myStore.set(syncedRoundAtom, data.syncedRound) + vi.mocked(useParams).mockReturnValue({ round: '1234' }) return executeComponentTest( () => render(, undefined, myStore), async (component) => { diff --git a/src/features/fund/fund-page.test.tsx b/src/features/fund/fund-page.test.tsx index 405aa07f..d008f5a9 100644 --- a/src/features/fund/fund-page.test.tsx +++ b/src/features/fund/fund-page.test.tsx @@ -9,14 +9,16 @@ import { dispenserApiLoginButtonLabel } from './components/dispenser-api-logged- import { Auth0Provider, useAuth0 } from '@auth0/auth0-react' import * as dispenserApi from './data/dispenser-api' import { algos } from '@algorandfoundation/algokit-utils' +import { useParams } from 'react-router-dom' describe('fund-page', () => { describe('when on localnet', () => { - it('should render the localnet funding controls', () => { + it.only('should render the localnet funding controls', () => { renderHook(async () => { const setSelectedNetwork = useSetSelectedNetwork() await setSelectedNetwork(localnetId) }) + vi.mocked(useParams).mockReturnValue({}) return executeComponentTest( () => render(), @@ -36,6 +38,7 @@ describe('fund-page', () => { const setSelectedNetwork = useSetSelectedNetwork() await setSelectedNetwork(mainnetId) }) + vi.mocked(useParams).mockReturnValue({}) return executeComponentTest( () => render(), @@ -70,6 +73,7 @@ describe('fund-page', () => { const setSelectedNetwork = useSetSelectedNetwork() await setSelectedNetwork(testnetId) }) + vi.mocked(useParams).mockReturnValue({}) return executeComponentTest( () => @@ -91,6 +95,7 @@ describe('fund-page', () => { const setSelectedNetwork = useSetSelectedNetwork() await setSelectedNetwork(testnetId) }) + vi.mocked(useParams).mockReturnValue({}) vi.mocked(useAuth0).mockImplementation(() => { return { @@ -126,6 +131,7 @@ describe('fund-page', () => { const setSelectedNetwork = useSetSelectedNetwork() await setSelectedNetwork(fnetId) }) + vi.mocked(useParams).mockReturnValue({}) return executeComponentTest( () => render(), diff --git a/src/features/settings/pages/settings-page.test.tsx b/src/features/settings/pages/settings-page.test.tsx index 28d63e97..313a2bd9 100644 --- a/src/features/settings/pages/settings-page.test.tsx +++ b/src/features/settings/pages/settings-page.test.tsx @@ -1,13 +1,15 @@ -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi } from 'vitest' import { executeComponentTest } from '@/tests/test-component' import { findByRole, render, waitFor } from '@/tests/testing-library' import { SettingsPage } from '@/features/settings/pages/settings-page' import { tableAssertion } from '@/tests/assertions/table-assertion' import { createNetworkConfigDialogLabel, networkConfigsTableLabel } from '@/features/network/components/network-configs-table' +import { useParams } from 'react-router-dom' describe('settings-page', () => { describe('when viewing', () => { it('the network table should be visible', () => { + vi.mocked(useParams).mockReturnValue({}) return executeComponentTest( () => render(), async (component) => { diff --git a/src/features/transaction-wizard/transaction-wizard-page.test.tsx b/src/features/transaction-wizard/transaction-wizard-page.test.tsx index 2eff97d9..11130899 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.test.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.test.tsx @@ -9,6 +9,7 @@ import { selectOption } from '@/tests/utils/select-option' import { setWalletAddressAndSigner } from '@/tests/utils/set-wallet-address-and-signer' import { addTransactionLabel } from './components/transactions-builder' import { groupSendResultsLabel } from './components/group-send-results' +import { useParams } from 'react-router-dom' describe('transaction-wizard-page', () => { const localnet = algorandFixture() @@ -28,6 +29,7 @@ describe('transaction-wizard-page', () => { isReady: true, } }) + vi.mocked(useParams).mockReturnValue({}) }) it('transaction cannot be sent', () => { @@ -48,6 +50,7 @@ describe('transaction-wizard-page', () => { describe('when a wallet is connected', () => { beforeEach(async () => { await setWalletAddressAndSigner(localnet) + vi.mocked(useParams).mockReturnValue({}) }) describe('and a payment transaction is being sent', () => { diff --git a/src/utils/use-title.ts b/src/utils/use-title.ts index c45e158c..df586343 100644 --- a/src/utils/use-title.ts +++ b/src/utils/use-title.ts @@ -7,6 +7,7 @@ const setTitle = (title: string) => { export const useTitle = (customString?: string) => { const urlParams = useParams() + useEffect(() => { const currentTitle = document.title let pageTitle = `Lora` From 67632f44a58fca45b7b008615d8a4a531eb691fe Mon Sep 17 00:00:00 2001 From: David Rojas Date: Wed, 30 Oct 2024 21:00:51 -0400 Subject: [PATCH 3/4] Addressed PR Comments --- src/utils/use-title.ts | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/utils/use-title.ts b/src/utils/use-title.ts index df586343..3918c9e7 100644 --- a/src/utils/use-title.ts +++ b/src/utils/use-title.ts @@ -1,48 +1,47 @@ import { useEffect } from 'react' import { useParams } from 'react-router-dom' +const TRUNCATE_LENGTH = 10 + const setTitle = (title: string) => { document.title = title } -export const useTitle = (customString?: string) => { +export const useTitle = (pagePrefix?: string) => { const urlParams = useParams() useEffect(() => { const currentTitle = document.title - let pageTitle = `Lora` - if (customString) { - pageTitle += ` ${customString}` - } + const pageTitleParams: string[] = [] if (urlParams.transactionId) { - pageTitle += ` - TxnId:${urlParams.transactionId}` + pageTitleParams.push(`Txn:${urlParams.transactionId.slice(0, TRUNCATE_LENGTH)}`) } if (urlParams.transactionId && urlParams['*']) { - pageTitle += `, Inner:${urlParams['*']}` + pageTitleParams.push(`Inner:${urlParams['*']}`) } if (urlParams.round) { - pageTitle += ` - Block:${urlParams.round}` + pageTitleParams.push(`Block:${urlParams.round}`) } if (urlParams?.groupId) { - pageTitle += ` - Group:${urlParams.groupId}` + pageTitleParams.push(`Group:${urlParams.groupId.slice(0, TRUNCATE_LENGTH)}`) } if (urlParams?.address) { - pageTitle += ` - Addr:${urlParams.address}` + pageTitleParams.push(`Acct:${urlParams.address.slice(0, TRUNCATE_LENGTH)}`) } if (urlParams?.applicationId) { - pageTitle += ` - AppId:${urlParams.applicationId}` + pageTitleParams.push(`App:${urlParams.applicationId}`) } if (urlParams?.assetId) { - pageTitle += ` - AssetId:${urlParams.assetId}` + pageTitleParams.push(`Asset:${urlParams.assetId}`) } if (urlParams?.networkId) { - pageTitle += ` - ${urlParams.networkId}` + pageTitleParams.push(urlParams.networkId) } - + const pageTitle = `Lora${pagePrefix ? ` ${pagePrefix}` : ''} ${pageTitleParams.join(' ')}` setTitle(pageTitle) return () => { setTitle(currentTitle) } - }, [customString, urlParams]) + }, [pagePrefix, urlParams]) } From 7d05f12d9b5556a48a68045932b9f5fa62a531b3 Mon Sep 17 00:00:00 2001 From: David Rojas Date: Thu, 31 Oct 2024 11:44:43 -0400 Subject: [PATCH 4/4] Added test for use-title hook --- .../explore/pages/explore-page.test.tsx | 2 +- src/features/fund/fund-page.test.tsx | 2 +- src/tests/utils/use-title.test.tsx | 92 +++++++++++++++++++ src/utils/use-title.ts | 2 +- 4 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 src/tests/utils/use-title.test.tsx diff --git a/src/features/explore/pages/explore-page.test.tsx b/src/features/explore/pages/explore-page.test.tsx index 8139c788..623a1244 100644 --- a/src/features/explore/pages/explore-page.test.tsx +++ b/src/features/explore/pages/explore-page.test.tsx @@ -22,7 +22,7 @@ describe('explore-page', () => { describe('when no blocks are available', () => { const myStore = createStore() - it.only('no latest blocks are displayed', () => { + it('no latest blocks are displayed', () => { vi.mocked(useParams).mockReturnValue({ round: '1234' }) return executeComponentTest( () => render(, undefined, myStore), diff --git a/src/features/fund/fund-page.test.tsx b/src/features/fund/fund-page.test.tsx index d008f5a9..10812d24 100644 --- a/src/features/fund/fund-page.test.tsx +++ b/src/features/fund/fund-page.test.tsx @@ -13,7 +13,7 @@ import { useParams } from 'react-router-dom' describe('fund-page', () => { describe('when on localnet', () => { - it.only('should render the localnet funding controls', () => { + it('should render the localnet funding controls', () => { renderHook(async () => { const setSelectedNetwork = useSetSelectedNetwork() await setSelectedNetwork(localnetId) diff --git a/src/tests/utils/use-title.test.tsx b/src/tests/utils/use-title.test.tsx new file mode 100644 index 00000000..5867ca5d --- /dev/null +++ b/src/tests/utils/use-title.test.tsx @@ -0,0 +1,92 @@ +import { useTitle } from '@/utils/use-title' +import { render, waitFor } from '@testing-library/react' +import { createMemoryRouter, RouterProvider } from 'react-router-dom' +import { expect, test, vi } from 'vitest' + +// This is to override the mocks for react-router-dom in src/test/setup/mocks for this test +vi.mock('react-router-dom', async () => ({ + ...(await vi.importActual('react-router-dom')), +})) + +type TestCase = { + routePathName: string + routePath: string + url: string + pagePrefix?: string + expectedText: string +} +const testCases: TestCase[] = [ + { + routePathName: 'Explore', + routePath: '/:networkId', + url: '/mainnet', + pagePrefix: 'Explore', + expectedText: 'Lora Explore mainnet', + }, + { + routePathName: 'Explore_Transaction_ById', + routePath: '/:networkId/transaction/:transactionId', + url: '/mainnet/transaction/CFNKY4JV5BMIRSP2SMZE634DYB22FALLURI72U6UMWZNKEBOYEMQ', + expectedText: 'Lora Txn:CFNKY4JV5B mainnet', + }, + { + routePathName: 'Explore_Transaction_ById_Inner_ById', + routePath: '/:networkId/transaction/:transactionId/inner/*', + url: '/mainnet/transaction/CFNKY4JV5BMIRSP2SMZE634DYB22FALLURI72U6UMWZNKEBOYEMQ/inner/1', + expectedText: 'Lora Txn:CFNKY4JV5B Inner:1 mainnet', + }, + { + routePathName: 'Explore_Block_ByRound', + routePath: '/:networkId/block/:round', + url: '/mainnet/block/43904244', + expectedText: 'Lora Block:43904244 mainnet', + }, + { + routePathName: 'Explore_Block_ByRound_Group_ById', + routePath: '/:networkId/block/:round/group/:groupId', + url: '/mainnet/block/43904244/group/iUE01XrzcJZ+ENIwPyjPmtaVUF5OKy8vYYOwGbdKliQ=', + expectedText: 'Lora Block:43904244 Group:iUE01XrzcJ mainnet', + }, + { + routePathName: 'Explore_Account_ByAddress', + routePath: '/:networkId/account/:address', + url: '/mainnet/account/W2IZ3EHDRW2IQNPC33CI2CXSLMFCFICVKQVWIYLJWXCTD765RW47ONNCEY', + expectedText: 'Lora Acct:W2IZ3EHDRW mainnet', + }, + { + routePathName: 'Explore_Asset_ById', + routePath: '/:networkId/asset/:assetId', + url: '/localnet/asset/1014', + expectedText: 'Lora Asset:1014 localnet', + }, + { + routePathName: 'Explore_Application_ById', + routePath: '/:networkId/application/:applicationId', + url: '/localnet/application/1019', + expectedText: 'Lora App:1019 localnet', + }, + { + routePathName: 'Custom_Page_Prefix', + routePath: '/txn-wizard', + url: '/txn-wizard', + pagePrefix: 'Custom Prefix', + expectedText: 'Lora Custom Prefix', + }, +] + +const TestComponent = ({ pagePrefix }: { pagePrefix?: string }) => { + useTitle(pagePrefix) + return
test
+} + +testCases.forEach(({ routePathName, routePath, url, pagePrefix, expectedText }) => { + test(`useTitle - ${routePathName}`, async () => { + const router = createMemoryRouter([{ path: routePath, element: }], { + initialEntries: [url], + }) + render() + await waitFor(() => { + expect(document.title).toEqual(expectedText) + }) + }) +}) diff --git a/src/utils/use-title.ts b/src/utils/use-title.ts index 3918c9e7..09fda181 100644 --- a/src/utils/use-title.ts +++ b/src/utils/use-title.ts @@ -3,7 +3,7 @@ import { useParams } from 'react-router-dom' const TRUNCATE_LENGTH = 10 -const setTitle = (title: string) => { +export const setTitle = (title: string) => { document.title = title }