Skip to content

Commit

Permalink
first round of unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
storywithoutend committed Sep 16, 2023
1 parent c4daca5 commit 83ca62b
Show file tree
Hide file tree
Showing 22 changed files with 429 additions and 36 deletions.
14 changes: 14 additions & 0 deletions src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { render, screen, userEvent} from '@app/test-utils'
import { ExpandableSection } from './ExpandableSection'

describe('ExpandableSection', () => {
it('should expand and close when header is clicked', async () => {
render(<ExpandableSection title="Test">CONTENT</ExpandableSection>)
const header = screen.getByRole('button', { name: /Test/i })
expect(screen.getByText('CONTENT')).not.toBeVisible()
await userEvent.click(header)
expect(screen.getByText('CONTENT')).toBeVisible()
await userEvent.click(header)
expect(screen.getByText('CONTENT')).not.toBeVisible()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { act, render, screen, userEvent, waitFor} from '@app/test-utils'
import { PseudoActionButton } from './PseudoActionButton'

beforeAll(() => {
jest.useFakeTimers()
})

afterAll(() => {
jest.useRealTimers()
})

describe('PseudoActionButton', () => {
it('should show loading state when clicked and reset after timeout has been run', async () => {
const testIcon = <div data-testid="icon"/>
render(<PseudoActionButton prefix={testIcon} timeout={500}>Test</PseudoActionButton>)
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime})
const button = screen.getByRole('button', { name: /Test/i })
const icon = screen.getByTestId('icon')
expect(icon).toBeVisible()
await user.click(button)
expect(icon).not.toBeVisible()
act(() => {
jest.runAllTimers()
})
await waitFor(() => {
expect(screen.getByTestId('icon')).toBeVisible()
})
})

it('should maintain loading state if loading is set to true', async () => {
const testIcon = <div data-testid="icon"/>
render(<PseudoActionButton loading prefix={testIcon} timeout={500}>Test</PseudoActionButton>)
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime})
const button = screen.getByRole('button', { name: /Test/i })
expect(screen.queryByTestId('icon')).toEqual(null)
await user.click(button)
expect(screen.queryByTestId('icon')).toEqual(null)
act(() => {
jest.runAllTimers()
})
expect(screen.queryByTestId('icon')).toEqual(null)
})
})
17 changes: 12 additions & 5 deletions src/components/@atoms/PseudoActionButton/PseudoActionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import { ComponentProps, useEffect, useState } from 'react'
import { ComponentProps, useEffect, useRef, useState } from 'react'

import { Button } from '@ensdomains/thorin'

type Props = ComponentProps<typeof Button>
type Props = { timeout?: number } & ComponentProps<typeof Button>

export const PseudoActionButton = ({ loading, onClick, ...props }: Props) => {
export const PseudoActionButton = ({ loading, onClick, timeout = 3000, ...props }: Props) => {
const [pseudoLoading, setPseudoLoading] = useState(false)

const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
useEffect(() => {
if (pseudoLoading) setTimeout(() => setPseudoLoading(false), 5000)
}, [pseudoLoading, setPseudoLoading])
return () => {
if (timerRef.current) clearTimeout(timerRef.current)
}
}, [])

return (
<Button
{...props}
loading={loading || pseudoLoading}
onClick={(e) => {
setPseudoLoading(true)
if (timerRef.current) clearTimeout(timerRef.current)
timerRef.current = setTimeout(() => setPseudoLoading(false), timeout)
onClick?.(e)
}}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { render, screen} from '@app/test-utils'

import { AvatarWithIdentifier } from './AvatarWithIdentifier'

const mockUsePrimary = jest.fn().mockImplementation((address) => {
console.log('mockUsePrimary', address)
return ({
data: address === '0xaddressWithoutAPrimaryName' ? undefined : { beautifiedName: 'test.eth', name: 'test.eth' },
isLoading: false
})})
jest.mock('@app/hooks/usePrimary', () => ({
usePrimary: (address: unknown, skip: boolean) => skip ? {isLoading: false} : mockUsePrimary(address)
}))

jest.mock('@app/components/AvatarWithZorb', () => ({
AvatarWithZorb: () => <div>ZORB</div>
}))

afterEach(() => {
jest.clearAllMocks()
})

describe('AvatarWithIdentifier', () => {
it('should render', async () => {
render(<AvatarWithIdentifier address="0x1234" />)
})

it('should render name and address', async () => {
render(<AvatarWithIdentifier address="0x1234" />)
expect(screen.getByText('test.eth')).toBeVisible()
expect(screen.getByText('0x1234')).toBeVisible()
})

it('should overwrite subtitle if prop is provided', async () => {
render(<AvatarWithIdentifier address="0x1234" subtitle='subtitle'/>)
expect(screen.getByText('test.eth')).toBeVisible()
expect(screen.getByText('subtitle')).toBeVisible()
expect(screen.queryByText('0x1234')).toEqual(null)
})

it('should display shortened address as title if address does not have primary name', async () => {
render(<AvatarWithIdentifier address="0xaddressWithoutAPrimaryName"/>)
expect(screen.getByTestId('avatar-label-title')).toHaveTextContent('0xadd...yName')
})

it('should display full address as title if address does not have primary name and shortenAddressAsTitle is false', async () => {
render(<AvatarWithIdentifier address="0xaddressWithoutAPrimaryName" shortenAddressAsTitle={false}/>)
expect(screen.getByTestId('avatar-label-title')).toHaveTextContent('0xaddressWithoutAPrimaryName')
})

it('should display subtitle and address as title if address does not have primary name and subtitle is provided', async () => {
render(<AvatarWithIdentifier address="0xaddressWithoutAPrimaryName" subtitle='subtitle'/>)
expect(screen.getByTestId('avatar-label-title')).toHaveTextContent('0xadd...yName')
expect(screen.getByText('subtitle')).toBeVisible()
})

it('should not call usePrimary if name is provided', async () => {
render(<AvatarWithIdentifier address="0x1234" name="name.eth" />)
expect(mockUsePrimary).not.toHaveBeenCalled()
expect(screen.getByText('name.eth')).toBeVisible()
})
})
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import styled, { css } from 'styled-components'
import { useChainId } from 'wagmi'

import { Typography } from '@ensdomains/thorin'

import { AvatarWithZorb } from '@app/components/AvatarWithZorb'
import { useChainId } from '@app/hooks/useChainId'
import { usePrimary } from '@app/hooks/usePrimary'
import { QuerySpace } from '@app/types'
import { emptyAddress } from '@app/utils/constants'
Expand Down Expand Up @@ -41,39 +41,39 @@ type Props = {
name?: string
subtitle?: string
size?: QuerySpace
shorten?: boolean
shortenAddressAsTitle?: boolean
}

export const AvatarWithIdentifier = ({
name,
address,
subtitle,
size = '10',
shorten = true,
shortenAddressAsTitle = true,
}: Props) => {
const primary = usePrimary(address, !address || !!name || address === emptyAddress)
const network = useChainId()

const _name = name || primary.data?.beautifiedName
const _title = _name || (shorten ? shortenAddress(address) : address)
const _title = _name || (shortenAddressAsTitle ? shortenAddress(address) : address)
const _subtitle =
subtitle || (primary.data?.beautifiedName || name ? shortenAddress(address) : undefined)

const isTitleFullAddress = !shorten && !_name
const isTitleFullAddress = !shortenAddressAsTitle && !_name

return (
<Container>
<AvatarWithZorb label={_title} address={address} name={_name} size={size} network={network} />
<TextContainer>
{isTitleFullAddress ? (
<AddressTitleContainer>{_title}</AddressTitleContainer>
<AddressTitleContainer data-testid="avatar-label-title">{_title}</AddressTitleContainer>
) : (
<Typography fontVariant="bodyBold" ellipsis data-testid="avatar-label-name">
<Typography fontVariant="bodyBold" ellipsis data-testid="avatar-label-title">
{_title}
</Typography>
)}
{_subtitle && (
<Typography fontVariant="extraSmall" color="grey" data-testid="avatar-label-address">
<Typography fontVariant="extraSmall" color="grey" data-testid="avatar-label-subtitle">
{_subtitle}
</Typography>
)}
Expand Down
19 changes: 19 additions & 0 deletions src/components/@molecules/QuestionTooltip/QuestionTooltip.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { render, screen, userEvent} from '@app/test-utils'

import { QuestionTooltip } from './QuestionTooltip'

describe('QuestionTooltip', () => {
it('should render and show tooltip', async () => {
render(<QuestionTooltip content="CONTENT"/>)
await userEvent.hover(screen.getByTestId('question-icon'))
expect(screen.getByText('CONTENT')).toBeVisible()
expect(screen.queryByText('action.learnMore')).toEqual(null)
})

it('should render and show tooltip with link', async () => {
render(<QuestionTooltip content="CONTENT" link="https://google.com"/>)
await userEvent.hover(screen.getByTestId('question-icon'))
expect(screen.getByText('CONTENT')).toBeVisible()
expect(screen.getByText('action.learnMore')).toBeVisible()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const QuestionTooltip = ({ content, link, ...props }: Props) => {
)
return (
<Tooltip {...props} content={_content} background="indigoSurface">
<IconWrapper>
<IconWrapper data-testid="question-icon">
<QuestionCircleSVG />
</IconWrapper>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { renderHook } from '@app/test-utils'

import { useOwnershipWarning } from './useOwnershipWarning'

jest.mock('@app/hooks/useAccountSafely', () => ({
useAccountSafely: () => ({
address: '0x1234'
})
}))

jest.mock('@app/hooks/useParentBasicName', () => () => ({
isLoading: false,
ownerData: {
owner: '0x456'
}
}))

describe('useOwnershipWarning', () => {
it('should return a warning if user is owner not manager of 2ld eth name ', async () => {
const { result } = renderHook(() => useOwnershipWarning({
name: 'test.eth',
nameType: {
data: 'eth-unwrapped-2ld',
isLoading: false
} as any,
details: {
isLoading: false,
ownerData: {
registrant: '0x1234',
owner: '0x456'
},
dnsOwner: '0x1234'
} as any
}))
expect(result.current.data).toEqual('tabs.ownership.warning.ownerNotManager')
})

it('should return a warning if user is dns owner not manager of 2ld dns name ', async () => {
const { result } = renderHook(() => useOwnershipWarning({
name: 'test.com',
nameType: {
data: 'dns-unwrapped-2ld',
isLoading: false
} as any,
details: {
isLoading: false,
ownerData: {
owner: '0x456'
},
dnsOwner: '0x1234'
} as any
}))
expect(result.current.data).toEqual('tabs.ownership.warning.dnsOwnerNotManager')
})

it('should return a warning if user is manager not dns owner of 2ld dns name ', async () => {
const { result } = renderHook(() => useOwnershipWarning({
name: 'test.com',
nameType: {
data: 'dns-unwrapped-2ld',
isLoading: false
} as any,
details: {
isLoading: false,
ownerData: {
owner: '0x1234'
},
dnsOwner: '0x456'
} as any
}))
expect(result.current.data).toEqual('tabs.ownership.warning.managerNotDNSOwner')
})

it('should return a warning if user is manager not dns owner of 2ld dns name ', async () => {
const { result } = renderHook(() => useOwnershipWarning({
name: 'test.com',
nameType: {
data: 'dns-unwrapped-2ld',
isLoading: false
} as any,
details: {
isLoading: false,
ownerData: {
owner: '0x1234'
},
dnsOwner: '0x456'
} as any
}))
expect(result.current.data).toEqual('tabs.ownership.warning.managerNotDNSOwner')
})

it('should return a warning if user is manager not owner of unwrapped subname ', async () => {
const { result } = renderHook(() => useOwnershipWarning({
name: 'test.com',
nameType: {
data: 'dns-unwrapped-subname',
isLoading: false
} as any,
details: {
isLoading: false,
ownerData: {
owner: '0x1234'
},
dnsOwner: ''
} as any
}))
expect(result.current.data).not.toBeUndefined()
})

it('should return undefined if user is not owner or manager of subname ', async () => {
const { result } = renderHook(() => useOwnershipWarning({
name: 'test.com',
nameType: {
data: 'dns-unwrapped-subname',
isLoading: false
} as any,
details: {
isLoading: false,
ownerData: {
owner: '0x456'
},
dnsOwner: ''
} as any
}))
expect(result.current.data).toBeUndefined()
})
})
Loading

0 comments on commit 83ca62b

Please sign in to comment.