Skip to content

Commit

Permalink
FET-1707: Improve unit test coverage WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Stanislav Lysak committed Dec 2, 2024
1 parent 4d12ee9 commit 7f8740e
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 54 deletions.
32 changes: 6 additions & 26 deletions src/components/@molecules/Hamburger/MainMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ import {
WalletSVG,
} from '@ensdomains/thorin'

import SocialDiscord from '@app/assets/social/SocialDiscord.svg'
import SocialDiscourse from '@app/assets/social/SocialDiscourse.svg'
import SocialDiscourseColour from '@app/assets/social/SocialDiscourseColour.svg'
import SocialGithub from '@app/assets/social/SocialGithub.svg'
import SocialMirror from '@app/assets/social/SocialMirror.svg'
import SocialMirrorColour from '@app/assets/social/SocialMirrorColour.svg'
import SocialX from '@app/assets/social/SocialX.svg'
import SocialYoutube from '@app/assets/social/SocialYoutube.svg'
import BaseLink from '@app/components/@atoms/BaseLink'
import { SocialIcon } from '@app/components/SocialIcon'
import { useChainName } from '@app/hooks/chain/useChainName'
Expand Down Expand Up @@ -295,24 +287,12 @@ const MainMenu = ({ setCurrentView }: { setCurrentView: (view: 'main' | 'languag
))}
</RoutesSection>
<SocialSection>
<SocialIcon Icon={SocialX} color="black" href="https://x.com/ensdomains" />
<SocialIcon Icon={SocialGithub} color="#0F0F0F" href="https://github.com/ensdomains" />
<SocialIcon Icon={SocialDiscord} color="#7F83FF" href="https://chat.ens.domains" />
<SocialIcon
Icon={SocialMirror}
ColoredIcon={SocialMirrorColour}
href="https://ens.mirror.xyz"
/>
<SocialIcon
Icon={SocialDiscourse}
ColoredIcon={SocialDiscourseColour}
href="https://discuss.ens.domains/"
/>
<SocialIcon
Icon={SocialYoutube}
color="#EE1919"
href="https://www.youtube.com/ensdomains"
/>
<SocialIcon social="x" color="black" href="https://x.com/ensdomains" />
<SocialIcon social="github" color="#0F0F0F" href="https://github.com/ensdomains" />
<SocialIcon social="discord" color="#7F83FF" href="https://chat.ens.domains" />
<SocialIcon social="mirror" href="https://ens.mirror.xyz" />
<SocialIcon social="discourse" href="https://discuss.ens.domains/" />
<SocialIcon social="youtube" color="#EE1919" href="https://www.youtube.com/ensdomains" />
</SocialSection>
<NetworkSection />
</Container>
Expand Down
38 changes: 38 additions & 0 deletions src/components/ConnectButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { mockFunction, render, screen } from '@app/test-utils'

import { beforeEach, describe, expect, it, vi } from 'vitest'

import { useBreakpoint } from '@app/utils/BreakpointProvider'

import { ConnectButton } from './ConnectButton'

vi.mock('@app/utils/BreakpointProvider')

const baseBreakpoints: ReturnType<typeof useBreakpoint> = {
xs: true,
sm: true,
md: true,
lg: false,
xl: false,
}

const mockUseBreakpoint = mockFunction(useBreakpoint)

describe('ConnectButton', () => {
beforeEach(() => {
mockUseBreakpoint.mockReturnValue(baseBreakpoints)
})

it('should render button in header', () => {
render(<ConnectButton inHeader />)
expect(screen.getByTestId('connect-button')).toBeInTheDocument()
})
it('should render button in body', () => {
render(<ConnectButton inHeader={false} />)
expect(screen.getByTestId('body-connect-button')).toBeInTheDocument()
})
it('should render button in tabbar', () => {
render(<ConnectButton isTabBar />)
expect(screen.getByTestId('tabbar-connect-button')).toBeInTheDocument()
})
})
14 changes: 3 additions & 11 deletions src/components/ConnectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,6 @@ type Props = {
inHeader?: boolean
}

const calculateTestId = (isTabBar: boolean | undefined, inHeader: boolean | undefined) => {
if (isTabBar) {
return 'tabbar-connect-button'
}
if (!inHeader) {
return 'body-connect-button'
}
return 'connect-button'
}

export const ConnectButton = ({ isTabBar, large, inHeader }: Props) => {
const { t } = useTranslation('common')
const breakpoints = useBreakpoint()
Expand All @@ -114,7 +104,9 @@ export const ConnectButton = ({ isTabBar, large, inHeader }: Props) => {
return (
<StyledButtonWrapper $large={large} $isTabBar={isTabBar}>
<Button
data-testid={calculateTestId(isTabBar, inHeader)}
data-testid={
isTabBar ? 'tabbar-connect-button' : !inHeader ? 'body-connect-button' : 'connect-button'
}
onClick={() => openConnectModal?.()}
size={breakpoints.sm || large ? 'medium' : 'small'}
width={inHeader ? '45' : undefined}
Expand Down
18 changes: 18 additions & 0 deletions src/components/SocialIcon.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { render, screen } from '@app/test-utils'

import { describe, expect, it } from 'vitest'

import { SocialIcon } from './SocialIcon'

describe('SocialIcon', () => {
it('should render icon', () => {
render(<SocialIcon social="github" href="https://github.com" />)
expect(screen.getByTestId('social-icon-github')).toBeInTheDocument()
expect(screen.getByTestId('social-icon-github')).toHaveAttribute('href', 'https://github.com')
})
it('should render colored icon', () => {
const { container } = render(<SocialIcon social="discourse" href="https://discourse.com" />)
const svgs = container.querySelectorAll('svg')
expect(Array.from(svgs).length).toBe(2)
})
})
73 changes: 59 additions & 14 deletions src/components/SocialIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
import { ElementType } from 'react'
import styled, { css } from 'styled-components'

import SocialDiscord from '@app/assets/social/SocialDiscord.svg'
import SocialDiscourse from '@app/assets/social/SocialDiscourse.svg'
import SocialDiscourseColour from '@app/assets/social/SocialDiscourseColour.svg'
import SocialGithub from '@app/assets/social/SocialGithub.svg'
import SocialMirror from '@app/assets/social/SocialMirror.svg'
import SocialMirrorColour from '@app/assets/social/SocialMirrorColour.svg'
import SocialX from '@app/assets/social/SocialX.svg'
import SocialYoutube from '@app/assets/social/SocialYoutube.svg'

type Social = 'discord' | 'discourse' | 'github' | 'mirror' | 'x' | 'youtube'

const socials: { social: Social; icon: React.ElementType; coloredIcon?: React.ElementType }[] = [
{
social: 'discord',
icon: SocialDiscord,
},
{
social: 'discourse',
icon: SocialDiscourse,
coloredIcon: SocialDiscourseColour,
},
{
social: 'github',
icon: SocialGithub,
},
{
social: 'mirror',
icon: SocialMirror,
coloredIcon: SocialMirrorColour,
},
{
social: 'x',
icon: SocialX,
},
{
social: 'youtube',
icon: SocialYoutube,
},
]

const SocialIconWrapper = styled.a(
({ theme }) => css`
position: relative;
Expand All @@ -13,11 +52,16 @@ const SocialIconWrapper = styled.a(
`,
)

const StyledIcon = styled.div<{ $iconColor?: string }>(
({ theme, $iconColor }) => css`
const BaseStyledIcon = styled.div(
() => css`
height: 100%;
position: absolute;
transition: 0.15s all ease-in-out;
`,
)

const StyledIcon = styled(BaseStyledIcon)<{ $iconColor?: string }>(
({ theme, $iconColor }) => css`
fill: ${theme.colors.greyPrimary};
${SocialIconWrapper}:hover && {
Expand All @@ -26,11 +70,8 @@ const StyledIcon = styled.div<{ $iconColor?: string }>(
`,
)

const StyledColoredIcon = styled.div(
const StyledColoredIcon = styled(BaseStyledIcon)(
() => css`
height: 100%;
position: absolute;
transition: 0.15s all ease-in-out;
opacity: 0;
${SocialIconWrapper}:hover && {
Expand All @@ -40,20 +81,24 @@ const StyledColoredIcon = styled.div(
)

export const SocialIcon = ({
Icon,
ColoredIcon,
color,
href,
social,
Icon,
ColoredIcon,
}: {
Icon: ElementType
ColoredIcon?: ElementType
social: Social
color?: string
href: string
Icon?: React.ElementType
ColoredIcon?: React.ElementType
}) => {
const { icon, coloredIcon } = socials.find((i) => i.social === social) as (typeof socials)[number]

return (
<SocialIconWrapper href={href} target="_blank">
<StyledIcon key={href} $iconColor={color} as={Icon} />
{ColoredIcon && <StyledColoredIcon as={ColoredIcon} />}
<SocialIconWrapper href={href} target="_blank" data-testid={`social-icon-${social}`}>
<StyledIcon key={href} $iconColor={color} as={Icon ?? icon} />
{coloredIcon && <StyledColoredIcon as={ColoredIcon ?? coloredIcon} />}
</SocialIconWrapper>
)
}
67 changes: 67 additions & 0 deletions src/components/TabBar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* eslint-disable no-promise-executor-return */
import { mockFunction, render, screen } from '@app/test-utils'

import mockRouter from 'next-router-mock'
import { beforeEach, describe, expect, it, vi } from 'vitest'

import { useAccountSafely } from '@app/hooks/account/useAccountSafely'
import { useBreakpoint } from '@app/utils/BreakpointProvider'

import { TabBar } from './TabBar'

vi.mock('next/router', async () => await vi.importActual('next-router-mock'))
vi.mock('wagmi', async () => {
const actual = await vi.importActual('wagmi')
return {
...actual,
}
})
vi.mock('@app/transaction-flow/transaction')
vi.mock('@app/hooks/transactions/TransactionStoreContext')
vi.mock('@app/utils/BreakpointProvider')
vi.mock('@app/hooks/account/useAccountSafely')
vi.mock('@app/hooks/ensjs/public/usePrimaryName', () => ({
usePrimaryName: ({ address }: { address: unknown }) => mockUsePrimary({ address }),
}))

const mockUseAccountSafely = mockFunction(useAccountSafely)
const mockUseBreakpoint = mockFunction(useBreakpoint)
const mockUsePrimary = vi.fn().mockImplementation(({}) => {
return {
data: { beautifiedName: 'test.eth', name: 'test.eth' },
isLoading: false,
}
})

const baseBreakpoints: ReturnType<typeof useBreakpoint> = {
xs: true,
sm: true,
md: true,
lg: false,
xl: false,
}

describe('TabBar', () => {
beforeEach(() => {
mockUseBreakpoint.mockReturnValue(baseBreakpoints)
})

it('should render connect button if no address is present', () => {
mockUseAccountSafely.mockReturnValue({})
render(<TabBar />)
expect(screen.queryByTestId('tabbar-connect-button')).toBeInTheDocument()
})

it('should not render connect button if no address is present', () => {
mockUseAccountSafely.mockReturnValue({ address: '0x1234' })
mockRouter.setCurrentUrl('/?from=from')
render(<TabBar />)
expect(screen.queryByTestId('tabbar-connect-button')).not.toBeInTheDocument()
})

it('should render back button if has from query', () => {
mockRouter.setCurrentUrl('/?from=from')
render(<TabBar />)
expect(screen.queryByTestId('tabbar-back')).toBeInTheDocument()
})
})
7 changes: 4 additions & 3 deletions src/components/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ export const TabBar = () => {
const { address } = useAccountSafely()
const primary = usePrimaryName({ address })

const hasPrimary = !!primary.data?.name
const primaryName = primary.data?.name
const hasPrimary = !!primaryName
const hasBack = !!router.query.from

const [isOpen, setIsOpen] = useState(false)
Expand All @@ -243,7 +244,7 @@ export const TabBar = () => {
<>
<TabWrapper id="tabbar">
{hasBack && (
<BackButton onClick={() => router.back()}>
<BackButton data-testid="tabbar-back" onClick={() => router.back()}>
<LeftChevronSVG />
</BackButton>
)}
Expand All @@ -260,7 +261,7 @@ export const TabBar = () => {
address={address}
isOpen={isOpen}
setIsOpen={setIsOpen}
name={primary.data?.name}
name={primaryName}
/>
</>
)}
Expand Down

0 comments on commit 7f8740e

Please sign in to comment.