Skip to content

Commit

Permalink
add unit test for react-lite
Browse files Browse the repository at this point in the history
  • Loading branch information
theothersideofgods committed Jun 4, 2024
1 parent e878f0c commit e2d429c
Show file tree
Hide file tree
Showing 15 changed files with 1,192 additions and 19 deletions.
119 changes: 119 additions & 0 deletions packages/example/pages/wallet-manager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { WalletManager, Logger } from "@cosmos-kit/core";
import { useMemo, useState } from 'react'
import { wallets as leapWallets } from "@cosmos-kit/leap";
import { wallets as stationWallets } from "@cosmos-kit/station";
import { wallets as coin98Wallets } from "@cosmos-kit/coin98";
import { wallets as keplrWallets } from "@cosmos-kit/keplr";
import { assets } from "chain-registry";
import { Button } from "components/button";
import { AccountData } from "@cosmjs/proto-signing";


export default () => {
const walletManager = useMemo(() => {
return new WalletManager(
["cosmoshub", "juno", "stargaze"], [keplrWallets[0], leapWallets[0], stationWallets[0], coin98Wallets[0]], new Logger('NONE'), false,
undefined, undefined, assets
);
}, [])

const [_, forceUpdate] = useState(0)

return (
<div>
<pre>
{JSON.stringify({
activeRepos: walletManager.activeRepos,

}, null, 2)}
</pre>
<div>Main Wallets</div>
<table >
<tbody>
{walletManager.mainWallets.map(mw => {
return mw.getChainWalletList(false).map(cw => {
cw.callbacks = {
beforeConnect: () => console.log('beforeConnect'),
beforeDisconnect: () => console.log('beforeDisconnect'),
afterConnect: () => forceUpdate(i => i + 1),
afterDisconnect: () => forceUpdate(i => i + 1)
}

const [account, setAccount] = useState<AccountData[] | undefined>(undefined)

const getAddress = async () => {
await cw.initOfflineSigner()
const account = await cw.offlineSigner?.getAccounts()
setAccount(account)
}

return (
<tr>
<td className='border-gray-500 p-1 border-2'>{mw.walletName}</td>
<td className='border-gray-500 p-1 border-2'>{cw.chainName}</td>
<td className='border-gray-500 p-1 border-2 space-x-1'>
<Button size='sm' onClick={() => { cw.connect(true); forceUpdate(i => i + 1) }}>connect</Button>
<Button size='sm' onClick={() => { cw.disconnect(true); forceUpdate(i => i + 1) }}>disconnect</Button>
<Button size='sm' onClick={getAddress}>get offline signer</Button>
</td>
<td className='border-gray-500 p-1 border-2'>{cw.state}</td>
<td className='border-gray-500 p-1 border-2'>{cw.message}</td>
<td className='border-gray-500 p-1 border-2'>{account?.[0]?.address}</td>
</tr>
)
})
})}
</tbody>
</table >
<div>Wallet Repo</div>
<table>
<tbody>
{walletManager.walletRepos.map(wr => {



return (
<>
<tr key={wr.chainName}>
<td className='border-gray-500 p-2 border-2'>current: {wr.current?.walletName}</td>
<td>{'client'}</td>
</tr>
{wr.wallets.map(w => {

const [account, setAccount] = useState<AccountData[] | undefined>(undefined)

const getAddress = async () => {
await w.initOfflineSigner()
const account = await w.offlineSigner?.getAccounts()
if (account) {
setAccount(account)
}
}


return (
<tr key={`${wr.chainName}-${w.walletName}`}>
<td className='border-gray-500 p-1 border-2'>{w.chainName}</td>
<td className='border-gray-500 p-1 border-2'>{w.walletName}</td>
<td className='border-gray-500 p-1 border-2 space-x-1'>
<Button size='sm' onClick={() => { w.connect(); forceUpdate(i => i + 1) }}>connect</Button>
<Button size='sm' onClick={() => { w.disconnect(); forceUpdate(i => i + 1) }}>disconnect</Button>
<Button size='sm' onClick={getAddress}>get offline signer</Button>
</td>
<td className='border-gray-500 p-1 border-2'>{w.state}</td>
<td className='border-gray-500 p-1 border-2'>{w.message}</td>
<td className='border-gray-500 p-1 border-2'>{account?.[0]?.address}</td>
</tr >
)
})
}
</>
)
})}
</tbody>
</table>
</div >)



}
72 changes: 72 additions & 0 deletions packages/react-lite/__test__/useChain.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { act, renderHook, waitFor, render, fireEvent, screen } from '@testing-library/react';
import { useChain, useManager } from '../src'
import { customWrapper } from "../test-utils"
import '@testing-library/jest-dom'
import React from 'react'

const TestComponent = () => {
const chain = useChain('juno')
const manager = useManager()
return <div>
<p>address:{chain.address}</p>
<div className="flex flex-col space-y-2 w-80">
{manager.getWalletRepo('juno').wallets.map(w => {
return <button key={w.walletName} onClick={() => w.connect(true)}>{w.walletName}</button>
})}
</div>
</div>
}

describe('useChain', () => {

const useContextMock = jest.spyOn(React, 'useContext')

afterEach(() => {
useContextMock.mockRestore()
})

it('should throw an error if no modal provided', async () => {
useContextMock.mockReturnValue({ walletManager: {}, modalProvided: undefined } as any)
renderHook(() => {
try {
useChain('juno')
} catch (error) {
expect(error.message).toBe('You have to provide `walletModal` to use `useChain`, or use `useChainWallet` instead.')
}
}, { wrapper: customWrapper })
})

it('should throw an error if used without ChainProvider', async () => {
renderHook(() => {
try {
useChain('juno')
} catch (error) {
expect(error.message).toBe('You have forgot to use ChainProvider.')
}
})
})

it('return undefined if not select a wallet', async () => {
const { result } = renderHook(() => useChain('juno', false), { wrapper: customWrapper })
await waitFor(() => {
expect(result.current.address).toBeUndefined()
})
})

it('should return address of selected wallet and chain', async () => {
render(<TestComponent />, { wrapper: customWrapper })

await act(() => fireEvent.click(screen.getByText('station-extension')))

await waitFor(async () => {
expect(await screen.getByText('address:juno-1AddressStation')).toBeInTheDocument()
})

await act(() => fireEvent.click(screen.getByText('leap-extension')))

await waitFor(async () => {
expect(await screen.getByText('address:juno-1AddressLeap')).toBeInTheDocument()
})

})
})
26 changes: 26 additions & 0 deletions packages/react-lite/__test__/useChainWallet.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { act, renderHook, waitFor } from "@testing-library/react"
import { useChainWallet } from "../src"
import { customWrapper } from "../test-utils"

describe('useChainWallet', () => {
it('should throw error, if not wrapped in ChainProvider', async () => {
renderHook(() => {
try {
useChainWallet('juno', 'keplr-extension', true)
} catch (error) {
expect(error.message).toBe('You have forgot to use ChainProvider.')
}
})
})
it('should return right chain and wallet information', async () => {
const { result } = renderHook(() => useChainWallet('juno', 'leap-extension', true), { wrapper: customWrapper })

await act(async () => {
await result.current?.connect()
})

await waitFor(() => {
expect(result.current?.chain?.chain_name).toBe('juno')
})
})
})
87 changes: 87 additions & 0 deletions packages/react-lite/__test__/useChains.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { act, fireEvent, render, renderHook, screen, waitFor } from "@testing-library/react"
import { useChains, useManager } from "../src"
import React from 'react'
import { customWrapper } from '../test-utils'
import '@testing-library/jest-dom'

const TestComponent = () => {
const chains = useChains(['juno', 'stargaze', 'osmosis']);
const manager = useManager()

const leapWallet = manager.mainWallets.find(w => w.walletName === 'leap-extension')
const stationWallet = manager.mainWallets.find(w => w.walletName === 'station-extension')

return (
<div>
<ul>
{Object.entries(chains).map(([name, chain]) => {
return (
<li key={name}>
<span>{name}:{chain.address}</span>
</li>
)
})}
</ul>
<button onClick={() => leapWallet?.connectAll()}>connect leap</button>
<button onClick={() => leapWallet?.disconnectAll()}>disconnect leap</button>
<button onClick={() => stationWallet?.connectAll()}>connect station</button>
</div>
)
}

describe('useChains', () => {

const useContextMock = jest.spyOn(React, 'useContext')
afterEach(() => {
useContextMock.mockRestore()
})

it('should throw an error if no modal provided', async () => {
useContextMock.mockReturnValue({ walletManager: {}, modalProvided: undefined } as any)
renderHook(() => {
try {
useChains(['juno', 'stargaze'])
} catch (error) {
expect(error.message).toBe('You have to provide `walletModal` to use `useChains`, or use `useChainWallet` instead.')
}
}, { wrapper: customWrapper })
})

it('should throw an error if used without ChainProvider', async () => {
renderHook(() => {
try {
useChains(['juno', 'stargaze'])
} catch (error) {
expect(error.message).toBe('You have forgotten to use ChainProvider.')
}
})
})

it('should render chains address', async () => {
render(<TestComponent />, { wrapper: customWrapper })

await act(async () => {
await fireEvent.click(screen.getByText('connect leap'))
})

await waitFor(() => {
expect(screen.getByText('juno:juno-1AddressLeap')).toBeInTheDocument()
expect(screen.getByText('stargaze:stargaze-1AddressLeap')).toBeInTheDocument()
expect(screen.getByText('osmosis:osmosis-1AddressLeap')).toBeInTheDocument()
})

await act(() => fireEvent.click(screen.getByText('disconnect leap')))

await act(async () => {
await fireEvent.click(screen.getByText('connect station'))
})

await waitFor(() => {
expect(screen.getByText('juno:juno-1AddressStation')).toBeInTheDocument()
expect(screen.getByText('stargaze:stargaze-1AddressStation')).toBeInTheDocument()
expect(screen.getByText('osmosis:osmosis-1AddressStation')).toBeInTheDocument()
})
})


})
29 changes: 29 additions & 0 deletions packages/react-lite/__test__/useManager.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { renderHook, waitFor } from '@testing-library/react'
import { useManager } from '../src'
import { Keplr } from '@keplr-wallet/types'
import { customWrapper } from '../test-utils';

describe('useManager', () => {
it('should throw an error if used without ChainProvider', async () => {
renderHook(() => {
try {
useManager()
} catch (error) {
expect(error.message).toBe('You have forgot to use ChainProvider.')
}
})
})

it('should create main wallet according wallets', async () => {
const { result } = renderHook(() => useManager(), { wrapper: customWrapper })
await waitFor(() => {
expect(result.current.mainWallets).toHaveLength(3)
})
})
it('should create wallet repo according chains', async () => {
const { result } = renderHook(() => useManager(), { wrapper: customWrapper })
await waitFor(() => {
expect(result.current.walletRepos).toHaveLength(4)
})
})
})
61 changes: 61 additions & 0 deletions packages/react-lite/__test__/useNameService.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { renderHook, waitFor } from "@testing-library/react"
import { customWrapper } from "../test-utils"
import { useNameService } from "../src"
import { Keplr } from '@keplr-wallet/types'
import * as useManagerHook from '../src/hooks/useManager'

describe('useNameService', () => {

const getNameServiceMock = jest.fn()
const getNameServiceRegistryFromNameMock = jest.fn()


beforeEach(() => {
jest.spyOn(useManagerHook, 'useManager').mockImplementation(() => ({
defaultNameService: 'icns',
getNameService: getNameServiceMock,
chainRecords: [],
walletRepos: [],
mainWallets: [],
getChainRecord: jest.fn(),
getWalletRepo: jest.fn(),
addChains: jest.fn(),
addEndpoints: jest.fn(),
getChainLogo: jest.fn(),
on: jest.fn(),
off: jest.fn() // Add the missing properties here
}))


})

it('should throw error, if there is no default name space', () => {
renderHook(() => {
try {
useNameService('notexistnameservice')
} catch (error) {
expect(error.message).toBe('No such name service: notexistnameservice')
}
})
})


it('should return right name service', async () => {
getNameServiceMock.mockImplementation(() => Promise.resolve('nameservice1'))

const { result } = renderHook(() => useNameService(), { wrapper: customWrapper })
await waitFor(() => {
expect(result.current.data).toBe('nameservice1')
})
})

it('should return error message', async () => {
getNameServiceMock.mockImplementation(() => Promise.reject(new Error('error message')))

const { result } = renderHook(() => useNameService(), { wrapper: customWrapper })
await waitFor(() => {
expect(result.current.message).toBe('error message')
})
})

})
Loading

0 comments on commit e2d429c

Please sign in to comment.