shlink-web-client/test/short-urls/helpers/ShortUrlsRow.test.tsx

166 lines
6.2 KiB
TypeScript
Raw Normal View History

import { screen } from '@testing-library/react';
import { last } from 'ramda';
import { Mock } from 'ts-mockery';
import { addDays, formatISO, subDays } from 'date-fns';
import { MemoryRouter, useLocation } from 'react-router-dom';
import { ShortUrlsRow as createShortUrlsRow } from '../../../src/short-urls/helpers/ShortUrlsRow';
import { TimeoutToggle } from '../../../src/utils/helpers/hooks';
import { ShortUrl, ShortUrlMeta } from '../../../src/short-urls/data';
import { Settings } from '../../../src/settings/reducers/settings';
import { ReachableServer } from '../../../src/servers/data';
import { parseDate, now } from '../../../src/utils/helpers/date';
import { renderWithEvents } from '../../__helpers__/setUpTest';
import { OptionalString } from '../../../src/utils/utils';
2022-07-16 11:52:45 +03:00
import { colorGeneratorMock } from '../../utils/services/__mocks__/ColorGenerator.mock';
2019-01-13 11:49:02 +03:00
interface SetUpOptions {
title?: OptionalString;
tags?: string[];
meta?: ShortUrlMeta;
settings?: Partial<Settings>;
}
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: jest.fn().mockReturnValue({}),
}));
2019-01-13 11:49:02 +03:00
describe('<ShortUrlsRow />', () => {
const timeoutToggle = jest.fn(() => true);
const useTimeoutToggle = jest.fn(() => [false, timeoutToggle]) as TimeoutToggle;
const server = Mock.of<ReachableServer>({ url: 'https://s.test' });
const shortUrl: ShortUrl = {
2019-01-13 11:49:02 +03:00
shortCode: 'abc123',
shortUrl: 'https://s.test/abc123',
longUrl: 'https://foo.com/bar',
dateCreated: formatISO(parseDate('2018-05-23 18:30:41', 'yyyy-MM-dd HH:mm:ss')),
tags: [],
2019-01-13 11:49:02 +03:00
visitsCount: 45,
visitsSummary: {
total: 45,
nonBots: 40,
bots: 5,
},
domain: null,
meta: {
validSince: null,
validUntil: null,
maxVisits: null,
},
2019-01-13 11:49:02 +03:00
};
2022-07-16 11:52:45 +03:00
const ShortUrlsRow = createShortUrlsRow(() => <span>ShortUrlsRowMenu</span>, colorGeneratorMock, useTimeoutToggle);
const setUp = ({ title, tags = [], meta = {}, settings = {} }: SetUpOptions = {}, search = '') => {
(useLocation as any).mockReturnValue({ search });
return renderWithEvents(
<MemoryRouter>
<table>
<tbody>
<ShortUrlsRow
selectedServer={server}
shortUrl={{ ...shortUrl, title, tags, meta: { ...shortUrl.meta, ...meta } }}
onTagClick={() => null}
settings={Mock.of<Settings>(settings)}
/>
</tbody>
</table>
</MemoryRouter>,
);
};
2019-01-13 11:49:02 +03:00
2021-03-05 17:23:38 +03:00
it.each([
[null, 7],
[undefined, 7],
['The title', 8],
2021-03-05 17:23:38 +03:00
])('renders expected amount of columns', (title, expectedAmount) => {
setUp({ title });
expect(screen.getAllByRole('cell')).toHaveLength(expectedAmount);
2021-03-05 17:23:38 +03:00
});
2019-01-13 11:49:02 +03:00
it('renders date in first column', () => {
setUp();
expect(screen.getAllByRole('cell')[0]).toHaveTextContent('2018-05-23 18:30');
2019-01-13 11:49:02 +03:00
});
it.each([
[1, shortUrl.shortUrl],
[2, shortUrl.longUrl],
])('renders expected links on corresponding columns', (colIndex, expectedLink) => {
setUp();
2019-01-13 11:49:02 +03:00
const col = screen.getAllByRole('cell')[colIndex];
const link = col.querySelector('a');
2021-03-05 17:23:38 +03:00
expect(link).toHaveAttribute('href', expectedLink);
2021-03-05 17:23:38 +03:00
});
it.each([
['My super cool title', 'My super cool title'],
[undefined, shortUrl.longUrl],
])('renders title when short URL has it', (title, expectedContent) => {
setUp({ title });
2019-01-13 11:49:02 +03:00
const titleSharedCol = screen.getAllByRole('cell')[2];
2019-01-13 11:49:02 +03:00
expect(titleSharedCol.querySelector('a')).toHaveAttribute('href', shortUrl.longUrl);
expect(titleSharedCol).toHaveTextContent(expectedContent);
});
2019-01-13 11:49:02 +03:00
it.each([
[[], ['No tags']],
[['nodejs', 'reactjs'], ['nodejs', 'reactjs']],
])('renders list of tags in fourth row', (tags, expectedContents) => {
setUp({ tags });
const cell = screen.getAllByRole('cell')[3];
2019-01-13 11:49:02 +03:00
expectedContents.forEach((content) => expect(cell).toHaveTextContent(content));
2019-01-13 11:49:02 +03:00
});
it.each([
[{}, '', shortUrl.visitsSummary?.total],
[Mock.of<Settings>({ visits: { excludeBots: false } }), '', shortUrl.visitsSummary?.total],
[Mock.of<Settings>({ visits: { excludeBots: true } }), '', shortUrl.visitsSummary?.nonBots],
[Mock.of<Settings>({ visits: { excludeBots: false } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[Mock.of<Settings>({ visits: { excludeBots: true } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[{}, 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[Mock.of<Settings>({ visits: { excludeBots: true } }), 'excludeBots=false', shortUrl.visitsSummary?.total],
[Mock.of<Settings>({ visits: { excludeBots: false } }), 'excludeBots=false', shortUrl.visitsSummary?.total],
[{}, 'excludeBots=false', shortUrl.visitsSummary?.total],
])('renders visits count in fifth row', (settings, search, expectedAmount) => {
setUp({ settings }, search);
expect(screen.getAllByRole('cell')[4]).toHaveTextContent(`${expectedAmount}`);
2019-01-13 11:49:02 +03:00
});
it('updates state when copied to clipboard', async () => {
const { user } = setUp();
2019-01-13 11:49:02 +03:00
expect(timeoutToggle).not.toHaveBeenCalled();
await user.click(screen.getAllByRole('img', { hidden: true })[0]);
expect(timeoutToggle).toHaveBeenCalledTimes(1);
2019-01-13 11:49:02 +03:00
});
it.each([
[{ validUntil: formatISO(subDays(now(), 1)) }, ['fa-calendar-xmark', 'text-danger']],
[{ validSince: formatISO(addDays(now(), 1)) }, ['fa-calendar-xmark', 'text-warning']],
[{ maxVisits: 45 }, ['fa-link-slash', 'text-danger']],
[{ maxVisits: 45, validSince: formatISO(addDays(now(), 1)) }, ['fa-link-slash', 'text-danger']],
[
{ validSince: formatISO(addDays(now(), 1)), validUntil: formatISO(subDays(now(), 1)) },
['fa-calendar-xmark', 'text-danger'],
],
[
{ validSince: formatISO(subDays(now(), 1)), validUntil: formatISO(addDays(now(), 1)) },
['fa-check', 'text-primary'],
],
[{ maxVisits: 500 }, ['fa-check', 'text-primary']],
[{}, ['fa-check', 'text-primary']],
])('displays expected status icon', (meta, expectedIconClasses) => {
setUp({ meta });
const statusIcon = last(screen.getAllByRole('img', { hidden: true }));
expect(statusIcon).toBeInTheDocument();
expectedIconClasses.forEach((expectedClass) => expect(statusIcon).toHaveClass(expectedClass));
expect(statusIcon).toMatchSnapshot();
});
2019-01-13 11:49:02 +03:00
});