analytics/assets/js/dashboard/stats/reports/metric-value.test.tsx

239 lines
6.2 KiB
TypeScript

import React from 'react'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import MetricValue from './metric-value'
jest.mock('@heroicons/react/24/solid', () => ({
ArrowUpRightIcon: () => <></>,
ArrowDownRightIcon: () => <></>
}))
const REVENUE = { long: '$1,659.50', short: '$1.7K' }
describe('single value', () => {
it('renders small value', async () => {
render(<MetricValue {...valueProps('visitors', 10)} />)
expect(screen.getByTestId('metric-value')).toHaveTextContent('10')
})
it('renders large value', async () => {
await renderWithTooltip(<MetricValue {...valueProps('visitors', 12345)} />)
expect(screen.getByTestId('metric-value')).toHaveTextContent('12.3k')
expect(screen.getByRole('tooltip')).toHaveTextContent('12,345')
})
it('renders percentages', async () => {
render(<MetricValue {...valueProps('bounce_rate', 5.3)} />)
expect(screen.getByTestId('metric-value')).toHaveTextContent('5.3%')
})
it('renders durations', async () => {
render(<MetricValue {...valueProps('visit_duration', 60)} />)
expect(screen.getByTestId('metric-value')).toHaveTextContent('1m 00s')
})
it('renders with custom formatter', async () => {
render(
<MetricValue
{...valueProps('test_money', 5.3)}
formatter={(value) => `${value}$`}
/>
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('5.3$')
})
it('renders revenue properly', async () => {
await renderWithTooltip(
<MetricValue {...valueProps('average_revenue', REVENUE)} />
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('$1.7K')
expect(screen.getByRole('tooltip')).toHaveTextContent('$1,659.50')
})
it('renders null revenue without tooltip', async () => {
render(<MetricValue {...valueProps('average_revenue', null)} />)
expect(screen.getByTestId('metric-value')).toHaveTextContent('-')
await expect(waitForTooltip).rejects.toThrow()
})
})
describe('comparisons', () => {
it('renders increased metric', async () => {
await renderWithTooltip(
<MetricValue {...valueProps('visitors', 10, { value: 5, change: 100 })} />
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('10↑')
expect(screen.getByRole('tooltip')).toHaveTextContent(
[
'10 visitors',
'01 Aug - 31 Aug',
'↑ 100%',
'5 visitors',
'01 July - 31 July'
].join('')
)
})
it('renders decreased metric', async () => {
await renderWithTooltip(
<MetricValue {...valueProps('visitors', 5, { value: 10, change: -50 })} />
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('5↓')
expect(screen.getByRole('tooltip')).toHaveTextContent(
[
'5 visitors',
'01 Aug - 31 Aug',
'↓ 50%',
'10 visitors',
'01 July - 31 July'
].join('')
)
})
it('renders unchanged metric', async () => {
await renderWithTooltip(
<MetricValue {...valueProps('visitors', 10, { value: 10, change: 0 })} />
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('10')
expect(screen.getByRole('tooltip')).toHaveTextContent(
[
'10 visitors',
'01 Aug - 31 Aug',
'0%',
'10 visitors',
'01 July - 31 July'
].join('')
)
})
it('renders metric with custom label', async () => {
await renderWithTooltip(
<MetricValue
{...valueProps('visitors', 10, { value: 10, change: 0 })}
renderLabel={() => 'Conversions'}
/>
)
expect(screen.getByRole('tooltip')).toHaveTextContent(
[
'10 conversions',
'01 Aug - 31 Aug',
'0%',
'10 conversions',
'01 July - 31 July'
].join('')
)
})
it('does not render very short labels', async () => {
await renderWithTooltip(
<MetricValue
{...valueProps('percentage', 10, { value: 10, change: 0 })}
renderLabel={() => '%'}
/>
)
expect(screen.getByRole('tooltip')).toHaveTextContent(
['10% ', '01 Aug - 31 Aug', '0%', '10% ', '01 July - 31 July'].join('')
)
})
it('renders with custom formatter', async () => {
await renderWithTooltip(
<MetricValue
{...valueProps('test', 10, { value: 5, change: 100 })}
formatter={(value) => `${value}$`}
/>
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('10$↑')
expect(screen.getByRole('tooltip')).toHaveTextContent(
[
'10$ test',
'01 Aug - 31 Aug',
'↑ 100%',
'5$ test',
'01 July - 31 July'
].join('')
)
})
it('renders revenue change', async () => {
await renderWithTooltip(
<MetricValue
{...valueProps('average_revenue', REVENUE, {
value: REVENUE,
change: 0
})}
/>
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('$1.7K')
expect(screen.getByRole('tooltip')).toHaveTextContent(
[
'$1,659.50 average_revenue',
'01 Aug - 31 Aug',
'0%',
'$1,659.50 average_revenue',
'01 July - 31 July'
].join('')
)
})
it('renders without tooltip when revenue null', async () => {
render(
<MetricValue
{...valueProps('average_revenue', null, { value: null, change: 0 })}
/>
)
expect(screen.getByTestId('metric-value')).toHaveTextContent('-')
await expect(waitForTooltip).rejects.toThrow()
})
})
function valueProps<T>(
metric: string,
value: T,
comparison?: { value: T; change: number }
) {
return {
metric: metric,
listItem: {
[metric]: value,
comparison: comparison && {
[metric]: comparison.value,
change: {
[metric]: comparison.change
}
}
},
meta: {
date_range_label: '01 Aug - 31 Aug',
comparison_date_range_label: '01 July - 31 July'
},
renderLabel: (_query: unknown) => metric.toUpperCase()
} as any /* eslint-disable-line @typescript-eslint/no-explicit-any */
}
async function renderWithTooltip(ui: React.ReactNode) {
render(ui)
await waitForTooltip()
}
async function waitForTooltip() {
fireEvent.mouseOver(screen.getByTestId('metric-value'))
await waitFor(() => screen.getByRole('tooltip'))
}