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'; import { colorGeneratorMock } from '../../utils/services/__mocks__/ColorGenerator.mock'; interface SetUpOptions { title?: OptionalString; tags?: string[]; meta?: ShortUrlMeta; settings?: Partial; } jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: jest.fn().mockReturnValue({}), })); describe('', () => { const timeoutToggle = jest.fn(() => true); const useTimeoutToggle = jest.fn(() => [false, timeoutToggle]) as TimeoutToggle; const server = Mock.of({ url: 'https://doma.in' }); const shortUrl: ShortUrl = { shortCode: 'abc123', shortUrl: 'https://doma.in/abc123', longUrl: 'https://foo.com/bar', dateCreated: formatISO(parseDate('2018-05-23 18:30:41', 'yyyy-MM-dd HH:mm:ss')), tags: [], visitsCount: 45, visitsSummary: { total: 45, nonBots: 40, bots: 5, }, domain: null, meta: { validSince: null, validUntil: null, maxVisits: null, }, }; const ShortUrlsRow = createShortUrlsRow(() => ShortUrlsRowMenu, colorGeneratorMock, useTimeoutToggle); const setUp = ({ title, tags = [], meta = {}, settings = {} }: SetUpOptions = {}, search = '') => { (useLocation as any).mockReturnValue({ search }); return renderWithEvents( null} settings={Mock.of(settings)} />
, ); }; it.each([ [null, 7], [undefined, 7], ['The title', 8], ])('renders expected amount of columns', (title, expectedAmount) => { setUp({ title }); expect(screen.getAllByRole('cell')).toHaveLength(expectedAmount); }); it('renders date in first column', () => { setUp(); expect(screen.getAllByRole('cell')[0]).toHaveTextContent('2018-05-23 18:30'); }); it.each([ [1, shortUrl.shortUrl], [2, shortUrl.longUrl], ])('renders expected links on corresponding columns', (colIndex, expectedLink) => { setUp(); const col = screen.getAllByRole('cell')[colIndex]; const link = col.querySelector('a'); expect(link).toHaveAttribute('href', expectedLink); }); it.each([ ['My super cool title', 'My super cool title'], [undefined, shortUrl.longUrl], ])('renders title when short URL has it', (title, expectedContent) => { setUp({ title }); const titleSharedCol = screen.getAllByRole('cell')[2]; expect(titleSharedCol.querySelector('a')).toHaveAttribute('href', shortUrl.longUrl); expect(titleSharedCol).toHaveTextContent(expectedContent); }); 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]; expectedContents.forEach((content) => expect(cell).toHaveTextContent(content)); }); it.each([ [{}, '', shortUrl.visitsSummary?.total], [Mock.of({ visits: { excludeBots: false } }), '', shortUrl.visitsSummary?.total], [Mock.of({ visits: { excludeBots: true } }), '', shortUrl.visitsSummary?.nonBots], [Mock.of({ visits: { excludeBots: false } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots], [Mock.of({ visits: { excludeBots: true } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots], [{}, 'excludeBots=true', shortUrl.visitsSummary?.nonBots], [Mock.of({ visits: { excludeBots: true } }), 'excludeBots=false', shortUrl.visitsSummary?.total], [Mock.of({ 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}`); }); it('updates state when copied to clipboard', async () => { const { user } = setUp(); expect(timeoutToggle).not.toHaveBeenCalled(); await user.click(screen.getAllByRole('img', { hidden: true })[0]); expect(timeoutToggle).toHaveBeenCalledTimes(1); }); 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(); }); });