Skip to content

Commit

Permalink
Merge branch 'main' into asnaith/additional-watched-accounts-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
asnaith committed Oct 12, 2023
2 parents f154ce7 + f3040eb commit 76f8de8
Show file tree
Hide file tree
Showing 30 changed files with 589 additions and 211 deletions.
3 changes: 2 additions & 1 deletion packages/ui/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { AuthRequests, Extension, TxRequests } from './Extension'
import { MultisigInfo, rejectCurrentMultisigTxs } from '../utils/rejectCurrentMultisigTxs'
import { InjectedAccountWitMnemonic } from '../fixtures/injectedAccounts'
import 'cypress-wait-until'

// ***********************************************
// This example commands.ts shows you how to
Expand Down Expand Up @@ -67,7 +68,7 @@ Cypress.Commands.add('rejectAuth', (id: number, reason: string) => {
})

Cypress.Commands.add('getTxRequests', () => {
return cy.wait(500).then(() => cy.wrap(extension.getTxRequests()))
return cy.wrap(extension.getTxRequests())
})

Cypress.Commands.add('approveTx', (id: number) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/cypress/support/page-objects/landingPage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const landingPage = {
watchAccountButton: () => cy.get('[data-cy=button-watch-address]'),
accountsOrRpcLoader: () => cy.get('[data-cy=loader-accounts-rpc-connection]'),
noAccountFoundError: () => cy.get('[data-cy=text-no-account-found]')
accountsLoader: () => cy.get('[data-cy="loader-accounts-connection"]'),
noAccountFoundError: () => cy.get('[data-cy="text-no-account-found"]')
}
5 changes: 4 additions & 1 deletion packages/ui/cypress/tests/login.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import { injectedAccounts } from '../fixtures/injectedAccounts'
import { landingPageUrl } from '../fixtures/landingData'
import { landingPage } from '../support/page-objects/landingPage'
import { topMenuItems } from '../support/page-objects/topMenuItems'
import { waitForAuthRequest } from '../utils/waitForAuthRequests'

describe('Connect Account', () => {
beforeEach(() => {
cy.visit(landingPageUrl)
cy.initExtension(injectedAccounts)
topMenuItems.connectButton().click()
landingPage.accountsOrRpcLoader().should('contain', 'Loading accounts')
landingPage.accountsLoader().should('contain', 'Loading accounts')
})

it('Reject connection', () => {
waitForAuthRequest()
cy.getAuthRequests().then((authRequests) => {
const requests = Object.values(authRequests)
// we should have 1 connection request to the extension
Expand All @@ -26,6 +28,7 @@ describe('Connect Account', () => {
})

it('Connects with Alice', () => {
waitForAuthRequest()
const AliceAddress = Object.values(injectedAccounts)[0].address
cy.getAuthRequests().then((authRequests) => {
const requests = Object.values(authRequests)
Expand Down
8 changes: 6 additions & 2 deletions packages/ui/cypress/tests/transactions.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { multisigPage } from '../support/page-objects/multisigPage'
import { notifications } from '../support/page-objects/notifications'
import { sendTxModal } from '../support/page-objects/sendTxModal'
import { topMenuItems } from '../support/page-objects/topMenuItems'
import { waitForAuthRequest } from '../utils/waitForAuthRequests'
import { waitForTxRequest } from '../utils/waitForTxRequests'

const AliceAddress = Object.values(injectedAccounts)[0].address

Expand All @@ -20,7 +22,8 @@ describe('Perform transactions', () => {
cy.visit(landingPageUrl)
cy.initExtension(injectedAccounts)
topMenuItems.connectButton().click()
landingPage.accountsOrRpcLoader().should('contain', 'Loading accounts')
landingPage.accountsLoader().should('contain', 'Loading accounts')
waitForAuthRequest()
cy.getAuthRequests().then((authRequests) => {
const requests = Object.values(authRequests)
// we should have 1 connection request to the extension
Expand All @@ -38,9 +41,9 @@ describe('Perform transactions', () => {
multisigPage.newTransactionButton().click()
sendTxModal.sendTxTitle().should('be.visible')
fillAndSubmitTransactionForm()
waitForTxRequest()
cy.getTxRequests().then((req) => {
const txRequests = Object.values(req)
console.log('txRequests', JSON.stringify(txRequests))
cy.wrap(txRequests.length).should('eq', 1)
cy.wrap(txRequests[0].payload.address).should('eq', AliceAddress)
sendTxModal.buttonSend().should('be.disabled')
Expand All @@ -67,6 +70,7 @@ describe('Perform transactions', () => {
multisigPage.newTransactionButton().click()
sendTxModal.sendTxTitle().should('be.visible')
fillAndSubmitTransactionForm()
waitForTxRequest()
cy.getTxRequests().then((req) => {
const txRequests = Object.values(req)
cy.wrap(txRequests.length).should('eq', 1)
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/cypress/utils/waitForAuthRequests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const waitForAuthRequest = () =>
cy.waitUntil(() => cy.getAuthRequests().then((req) => Object.entries(req).length > 0))
2 changes: 2 additions & 0 deletions packages/ui/cypress/utils/waitForTxRequests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const waitForTxRequest = () =>
cy.waitUntil(() => cy.getTxRequests().then((req) => Object.entries(req).length > 0))
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@typescript-eslint/parser": "^6.7.2",
"@vitejs/plugin-react": "^4.0.4",
"cypress": "^13.2.0",
"cypress-wait-until": "^2.0.1",
"eslint": "^8.49.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-react-app": "^7.0.1",
Expand Down
125 changes: 95 additions & 30 deletions packages/ui/src/components/CallInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import { HiOutlineArrowTopRightOnSquare as LaunchIcon } from 'react-icons/hi2'
import { Link } from './library'
import { usePjsLinks } from '../hooks/usePjsLinks'
import { Alert } from '@mui/material'
import { ApiPromise } from '@polkadot/api'
import { isTypeBalance } from '../utils/isTypeBalance'
import { isTypeAccount } from '../utils/isTypeAccount'

interface Props {
aggregatedData: Omit<AggregatedData, 'from' | 'timestamp'>
Expand All @@ -26,43 +29,97 @@ interface CreateTreeParams {
decimals: number
unit: string
name?: string
api: ApiPromise
typeName?: string
}

const createUlTree = ({ name, args, decimals, unit }: CreateTreeParams) => {
const handleBatchDisplay = ({
value,
decimals,
unit,
api,
key
}: {
value: any[]
decimals: number
unit: string
key: string
api: ApiPromise
}) =>
value.map((call: any, index: number) => {
const name = `${call.section}.${call.method}`
return (
<>
<li key={`${key}-${index}`}>{name}</li>
{createUlTree({
name: `${call.section}.${call.method}`,
args: call.args,
decimals,
unit,
api
})}
</>
)
})

const handleBalanceDisplay = ({
value,
decimals,
unit,
key
}: {
value: any
decimals: number
unit: string
key: string
}) => {
const balance = formatBnBalance(value.replace(/,/g, ''), decimals, {
withThousandDelimiter: true,
tokenSymbol: unit,
numberAfterComma: 4
})

return (
<li key={key}>
{key}: {balance}
</li>
)
}

const getTypeName = (index: number, name: string, value: any, api: ApiPromise) => {
const [palletFromName, methodFromName] = name.split('.')
const pallet = value.section || palletFromName
const method = value.method || methodFromName
const metaArgs = !!pallet && !!method && api.tx[pallet][method].meta.args

return (
(!!metaArgs && metaArgs[index] && (metaArgs[index].toHuman().typeName as string)) || undefined
)
}

const createUlTree = ({ name, args, decimals, unit, api, typeName }: CreateTreeParams) => {
if (!args) return
if (!name) return

const isBalancesTransferAlike = ['balances.transfer', 'balances.transferKeepAlive'].includes(name)
const isProxyCreationDeletion = ['proxy.addProxy', 'proxy.removeProxy'].includes(name)

return (
<ul className="params">
{Object.entries(args).map(([key, value]) => {
// in case the call was a WrapperOpaque<Call> the destination is the value and has no Id
const destAddress = value?.Id || value
// show nice dest
if (
((isBalancesTransferAlike && key === 'dest') ||
(isProxyCreationDeletion && key === 'delegate')) &&
typeof destAddress === 'string'
) {
return (
<li key={key}>
{key}: {<MultisigCompactDisplay address={destAddress} />}
</li>
)
{Object.entries(args).map(([key, value], index) => {
const _typeName = typeName || getTypeName(index, name, value, api)

if (_typeName === 'Vec<RuntimeCall>') {
return handleBatchDisplay({ value, decimals, unit, api, key: `${key}-batch` })
}

// generically show nice value for Balance type
if (isTypeBalance(_typeName)) {
return handleBalanceDisplay({ value, decimals, unit, key })
}

// show nice value
if (isBalancesTransferAlike && key === 'value') {
const balance = formatBnBalance(value.replace(/,/g, ''), decimals, {
withThousandDelimiter: true,
tokenSymbol: unit,
numberAfterComma: 4
})
const destAddress = value?.Id || value
if (isTypeAccount(_typeName) && typeof destAddress === 'string') {
return (
<li key={key}>
{key}: {balance}
{key}: {<MultisigCompactDisplay address={destAddress} />}
</li>
)
}
Expand All @@ -71,7 +128,14 @@ const createUlTree = ({ name, args, decimals, unit }: CreateTreeParams) => {
<li key={key}>
{key}:{' '}
{typeof value === 'object'
? createUlTree({ name, args: value, decimals, unit })
? createUlTree({
name,
args: value,
decimals,
unit,
api,
typeName: _typeName
})
: value}
</li>
)
Expand Down Expand Up @@ -108,14 +172,15 @@ const CallInfo = ({
withProxyFiltered = true
}: Props) => {
const { args, name } = withProxyFiltered ? filterProxyProxy(aggregatedData) : aggregatedData
const { chainInfo } = useApi()
const { chainInfo, api } = useApi()
const decimals = useMemo(() => chainInfo?.tokenDecimals || 0, [chainInfo])
const unit = useMemo(() => chainInfo?.tokenSymbol || '', [chainInfo])
const { getDecodeUrl } = usePjsLinks()
const link = useMemo(
() => aggregatedData.callData && getDecodeUrl(aggregatedData.callData),
[aggregatedData, getDecodeUrl]
)
const hasArgs = useMemo(() => args && Object.keys(args).length > 0, [args])

return (
<div className={className}>
Expand All @@ -140,11 +205,11 @@ const CallInfo = ({
annoyance.
</AlertStyled>
)}
{args && Object.keys(args).length > 0 && (
{!!api && hasArgs && (
<Expander
expanded={expanded}
title="Params"
content={createUlTree({ name, args, decimals, unit })}
content={createUlTree({ name, args, decimals, unit, api })}
/>
)}
{children}
Expand Down
30 changes: 20 additions & 10 deletions packages/ui/src/components/ConnectOrWatch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ export const ConnectOrWatch = () => {

return (
<ConnectButtonWrapperStyled>
No multisig found for your accounts or watched accounts.{' '}
{isAllowedToConnectToExtension ? (
<Button onClick={() => navigate('/create')}>Create one</Button>
) : (
<Button onClick={allowConnectionToExtension}>Connect Wallet</Button>
)}
or
<Button onClick={() => navigate(`/settings${WATCH_ACCOUNT_ANCHOR}`)}>Watch one</Button>
<div>No multisig found for your accounts or watched accounts.</div>
<ButtonWrapperStyled>
{isAllowedToConnectToExtension ? (
<Button onClick={() => navigate('/create')}>Create one</Button>
) : (
<Button onClick={allowConnectionToExtension}>Connect Wallet</Button>
)}
or
<Button onClick={() => navigate(`/settings${WATCH_ACCOUNT_ANCHOR}`)}>Watch one</Button>
</ButtonWrapperStyled>
</ConnectButtonWrapperStyled>
)
}
Expand All @@ -26,8 +28,16 @@ const ConnectButtonWrapperStyled = styled('div')`
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
`

const ButtonWrapperStyled = styled('div')`
display: flex;
align-items: center;
justify-content: center;
padding: 1rem 0;
& > button {
margin: 0 1rem;
button {
margin: 0 0.5rem;
}
`
18 changes: 16 additions & 2 deletions packages/ui/src/components/Drawer/DrawerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function DrawerMenu({ handleDrawerClose }: DrawerMenuProps) {
<ChevronRightIcon size={20} />
</IconButton>
</DrawerHeader>
<List>
<List disablePadding={true}>
{!isAllowedToConnectToExtension && (
<ListItemStyled disablePadding>
<ButtonStyled
Expand Down Expand Up @@ -65,7 +65,21 @@ function DrawerMenu({ handleDrawerClose }: DrawerMenuProps) {
)
}
const ListItemStyled = styled(ListItem)`
justify-content: flex-end;
justify-content: center;
width: 100%;
@media (min-width: ${({ theme }) => theme.breakpoints.values.md}px) {
justify-content: flex-end;
}
a {
width: 100%;
text-align: center;
@media (min-width: ${({ theme }) => theme.breakpoints.values.md}px) {
width: auto;
}
}
`

const ButtonStyled = styled(Button)`
Expand Down
3 changes: 1 addition & 2 deletions packages/ui/src/components/EasySetup/ManualExtrinsic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useApi } from '../../contexts/ApiContext'
import paramConversion from '../../utils/paramConversion'
import { getGlobalMaxValue, inputToBn } from '../../utils'
import BN from 'bn.js'
import { isTypeBalance } from '../../utils/isTypeBalance'

interface Props {
extrinsicIndex?: string
Expand Down Expand Up @@ -47,8 +48,6 @@ const initFormState = {

const argIsOptional = (arg: any) => arg.type.toString().startsWith('Option<')

const isTypeBalance = (typeName: string) => ['Balance', 'BalanceOf', 'Amount'].includes(typeName)

const isNumType = (type: string) => paramConversion.num.includes(type)

const parseFloatOrInt = (value: any) => {
Expand Down
Loading

0 comments on commit 76f8de8

Please sign in to comment.