diff --git a/shlink-web-client.d.ts b/shlink-web-client.d.ts index dbc6e0fd..a1713f06 100644 --- a/shlink-web-client.d.ts +++ b/shlink-web-client.d.ts @@ -10,7 +10,7 @@ declare module 'event-source-polyfill' { declare module 'csvjson' { export declare class CsvJson { public toObject(content: string): T[]; - public toCSV(data: T[], options: { headers: 'full' | 'none' | 'relative' | 'key' }): string; + public toCSV(data: T[], options: { headers: 'full' | 'none' | 'relative' | 'key'; wrap?: true }): string; } } diff --git a/src/common/services/ReportExporter.ts b/src/common/services/ReportExporter.ts new file mode 100644 index 00000000..a80cdded --- /dev/null +++ b/src/common/services/ReportExporter.ts @@ -0,0 +1,33 @@ +import { CsvJson } from 'csvjson'; +import { NormalizedVisit } from '../../visits/types'; +import { ExportableShortUrl } from '../../short-urls/data'; +import { saveCsv } from '../../utils/helpers/files'; + +export class ReportExporter { + public constructor( + private readonly window: Window, + private readonly csvjson: CsvJson, + ) {} + + public readonly exportVisits = (filename: string, visits: NormalizedVisit[]) => { + if (!visits.length) { + return; + } + + this.exportCsv(filename, visits); + }; + + public readonly exportShortUrls = (shortUrls: ExportableShortUrl[]) => { + if (!shortUrls.length) { + return; + } + + this.exportCsv('short_urls.csv', shortUrls); + }; + + private readonly exportCsv = (filename: string, rows: object[]) => { + const csv = this.csvjson.toCSV(rows, { headers: 'key', wrap: true }); + + saveCsv(this.window, csv, filename); + }; +} diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index c085aeaf..05a20a0f 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -11,6 +11,7 @@ import { ConnectDecorator } from '../../container/types'; import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer'; import { sidebarNotPresent, sidebarPresent } from '../reducers/sidebar'; import { ImageDownloader } from './ImageDownloader'; +import { ReportExporter } from './ReportExporter'; const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Services @@ -19,6 +20,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { bottle.constant('axios', axios); bottle.service('ImageDownloader', ImageDownloader, 'axios', 'window'); + bottle.service('ReportExporter', ReportExporter, 'window', 'csvjson'); // Components bottle.serviceFactory('ScrollToTop', ScrollToTop); diff --git a/src/short-urls/ShortUrlsFilteringBar.tsx b/src/short-urls/ShortUrlsFilteringBar.tsx index 610203cb..71082df2 100644 --- a/src/short-urls/ShortUrlsFilteringBar.tsx +++ b/src/short-urls/ShortUrlsFilteringBar.tsx @@ -14,11 +14,11 @@ import { DateRange } from '../utils/dates/types'; import { supportsAllTagsFiltering } from '../utils/helpers/features'; import { SelectedServer } from '../servers/data'; import { TooltipToggleSwitch } from '../utils/TooltipToggleSwitch'; -import { ExportBtn } from '../utils/ExportBtn'; import { OrderDir } from '../utils/helpers/ordering'; import { OrderingDropdown } from '../utils/OrderingDropdown'; import { useShortUrlsQuery } from './helpers/hooks'; import { SHORT_URLS_ORDERABLE_FIELDS, ShortUrlsOrder, ShortUrlsOrderableFields } from './data'; +import { ExportShortUrlsBtnProps } from './helpers/ExportShortUrlsBtn'; import './ShortUrlsFilteringBar.scss'; export interface ShortUrlsFilteringProps { @@ -26,13 +26,15 @@ export interface ShortUrlsFilteringProps { order: ShortUrlsOrder; handleOrderBy: (orderField?: ShortUrlsOrderableFields, orderDir?: OrderDir) => void; className?: string; + shortUrlsAmount?: number; } const dateOrNull = (date?: string) => date ? parseISO(date) : null; -const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC => ( - { selectedServer, className, order, handleOrderBy }, -) => { +const ShortUrlsFilteringBar = ( + colorGenerator: ColorGenerator, + ExportShortUrlsBtn: FC, +): FC => ({ selectedServer, className, shortUrlsAmount, order, handleOrderBy }) => { const [{ search, tags, startDate, endDate, tagsMode = 'any' }, toFirstPage ] = useShortUrlsQuery(); const setDates = pipe( ({ startDate, endDate }: DateRange) => ({ @@ -61,7 +63,7 @@ const ShortUrlsFilteringBar = (colorGenerator: ColorGenerator): FC
- {}} /> +
diff --git a/src/short-urls/ShortUrlsList.tsx b/src/short-urls/ShortUrlsList.tsx index fb1c2115..363c8e18 100644 --- a/src/short-urls/ShortUrlsList.tsx +++ b/src/short-urls/ShortUrlsList.tsx @@ -65,6 +65,7 @@ const ShortUrlsList = ( <> ; + +export interface ExportableShortUrl { + createdAt: string; + title: string; + shortUrl: string; + longUrl: string; + tags: string; + visits: number; +} diff --git a/src/short-urls/helpers/ExportShortUrlsBtn.tsx b/src/short-urls/helpers/ExportShortUrlsBtn.tsx new file mode 100644 index 00000000..03b79584 --- /dev/null +++ b/src/short-urls/helpers/ExportShortUrlsBtn.tsx @@ -0,0 +1,66 @@ +import { FC } from 'react'; +import { ExportBtn } from '../../utils/ExportBtn'; +import { useToggle } from '../../utils/helpers/hooks'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { isServerWithId, SelectedServer } from '../../servers/data'; +import { ShortUrl } from '../data'; +import { ReportExporter } from '../../common/services/ReportExporter'; +import { useShortUrlsQuery } from './hooks'; + +export interface ExportShortUrlsBtnProps { + amount?: number; +} + +interface ExportShortUrlsBtnConnectProps extends ExportShortUrlsBtnProps { + selectedServer: SelectedServer; +} + +const itemsPerPage = 10; + +export const ExportShortUrlsBtn = ( + buildShlinkApiClient: ShlinkApiClientBuilder, + { exportShortUrls }: ReportExporter, +): FC => ({ amount = 0, selectedServer }) => { + const [{ tags, search, startDate, endDate, orderBy, tagsMode }] = useShortUrlsQuery(); + const [ loading,, startLoading, stopLoading ] = useToggle(); + const exportAllUrls = () => { + if (!isServerWithId(selectedServer)) { + return; + } + + const totalPages = amount / itemsPerPage; + const { listShortUrls } = buildShlinkApiClient(selectedServer); + const loadAllUrls = async (page = 1): Promise => { + const { data } = await listShortUrls( + { page: `${page}`, tags, searchTerm: search, startDate, endDate, orderBy, tagsMode, itemsPerPage }, + ); + + if (page >= totalPages) { + return data; + } + + // TODO Support paralelization + return data.concat(await loadAllUrls(page + 1)); + }; + + startLoading(); + loadAllUrls() + .then((shortUrls) => { + exportShortUrls(shortUrls.map((shortUrl) => ({ + createdAt: shortUrl.dateCreated, + shortUrl: shortUrl.shortUrl, + longUrl: shortUrl.longUrl, + title: shortUrl.title ?? '', + tags: shortUrl.tags.join(','), + visits: shortUrl.visitsCount, + }))); + stopLoading(); + }) + .catch((e) => { + // TODO Handle error properly + console.error('An error occurred while exporting short URLs', e); // eslint-disable-line no-console + }); + }; + + return ; +}; diff --git a/src/short-urls/services/provideServices.ts b/src/short-urls/services/provideServices.ts index 425a04a8..165cf91d 100644 --- a/src/short-urls/services/provideServices.ts +++ b/src/short-urls/services/provideServices.ts @@ -16,6 +16,7 @@ import QrCodeModal from '../helpers/QrCodeModal'; import { ShortUrlForm } from '../ShortUrlForm'; import { EditShortUrl } from '../EditShortUrl'; import { getShortUrlDetail } from '../reducers/shortUrlDetail'; +import { ExportShortUrlsBtn } from '../helpers/ExportShortUrlsBtn'; const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Components @@ -49,7 +50,10 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { bottle.serviceFactory('QrCodeModal', QrCodeModal, 'ImageDownloader', 'ForServerVersion'); bottle.decorator('QrCodeModal', connect([ 'selectedServer' ])); - bottle.serviceFactory('ShortUrlsFilteringBar', ShortUrlsFilteringBar, 'ColorGenerator'); + bottle.serviceFactory('ShortUrlsFilteringBar', ShortUrlsFilteringBar, 'ColorGenerator', 'ExportShortUrlsBtn'); + + bottle.serviceFactory('ExportShortUrlsBtn', ExportShortUrlsBtn, 'buildShlinkApiClient', 'ReportExporter'); + bottle.decorator('ExportShortUrlsBtn', connect([ 'selectedServer' ])); // Actions bottle.serviceFactory('listShortUrls', listShortUrls, 'buildShlinkApiClient'); diff --git a/src/utils/ExportBtn.tsx b/src/utils/ExportBtn.tsx index f4f83cd8..2a0a78c9 100644 --- a/src/utils/ExportBtn.tsx +++ b/src/utils/ExportBtn.tsx @@ -1,17 +1,16 @@ import { FC } from 'react'; -import { Button } from 'reactstrap'; +import { Button, ButtonProps } from 'reactstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faFileDownload } from '@fortawesome/free-solid-svg-icons'; import { prettify } from './helpers/numbers'; -interface ExportBtnProps { - onClick: () => void; +interface ExportBtnProps extends Omit { amount?: number; - className?: string; + loading?: boolean; } -export const ExportBtn: FC = ({ onClick, className, amount = 0 }) => ( - ); diff --git a/src/visits/NonOrphanVisits.tsx b/src/visits/NonOrphanVisits.tsx index e6dc6a26..b5e4a1eb 100644 --- a/src/visits/NonOrphanVisits.tsx +++ b/src/visits/NonOrphanVisits.tsx @@ -2,9 +2,9 @@ import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { ShlinkVisitsParams } from '../api/types'; import { Topics } from '../mercure/helpers/Topics'; import { useGoBack } from '../utils/helpers/hooks'; +import { ReportExporter } from '../common/services/ReportExporter'; import VisitsStats from './VisitsStats'; import { NormalizedVisit, VisitsInfo, VisitsParams } from './types'; -import { VisitsExporter } from './services/VisitsExporter'; import { CommonVisitsProps } from './types/CommonVisitsProps'; import { toApiParams } from './types/helpers'; import { NonOrphanVisitsHeader } from './NonOrphanVisitsHeader'; @@ -15,7 +15,7 @@ export interface NonOrphanVisitsProps extends CommonVisitsProps { cancelGetNonOrphanVisits: () => void; } -export const NonOrphanVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({ +export const NonOrphanVisits = ({ exportVisits }: ReportExporter) => boundToMercureHub(({ getNonOrphanVisits, nonOrphanVisits, cancelGetNonOrphanVisits, diff --git a/src/visits/OrphanVisits.tsx b/src/visits/OrphanVisits.tsx index a659f5ea..e2e20393 100644 --- a/src/visits/OrphanVisits.tsx +++ b/src/visits/OrphanVisits.tsx @@ -2,10 +2,10 @@ import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { ShlinkVisitsParams } from '../api/types'; import { Topics } from '../mercure/helpers/Topics'; import { useGoBack } from '../utils/helpers/hooks'; +import { ReportExporter } from '../common/services/ReportExporter'; import VisitsStats from './VisitsStats'; import { OrphanVisitsHeader } from './OrphanVisitsHeader'; import { NormalizedVisit, OrphanVisitType, VisitsInfo, VisitsParams } from './types'; -import { VisitsExporter } from './services/VisitsExporter'; import { CommonVisitsProps } from './types/CommonVisitsProps'; import { toApiParams } from './types/helpers'; @@ -19,7 +19,7 @@ export interface OrphanVisitsProps extends CommonVisitsProps { cancelGetOrphanVisits: () => void; } -export const OrphanVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({ +export const OrphanVisits = ({ exportVisits }: ReportExporter) => boundToMercureHub(({ getOrphanVisits, orphanVisits, cancelGetOrphanVisits, diff --git a/src/visits/ShortUrlVisits.tsx b/src/visits/ShortUrlVisits.tsx index 5956006f..153da858 100644 --- a/src/visits/ShortUrlVisits.tsx +++ b/src/visits/ShortUrlVisits.tsx @@ -6,10 +6,10 @@ import { parseQuery } from '../utils/helpers/query'; import { Topics } from '../mercure/helpers/Topics'; import { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail'; import { useGoBack } from '../utils/helpers/hooks'; +import { ReportExporter } from '../common/services/ReportExporter'; import { ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits'; import ShortUrlVisitsHeader from './ShortUrlVisitsHeader'; import VisitsStats from './VisitsStats'; -import { VisitsExporter } from './services/VisitsExporter'; import { NormalizedVisit, VisitsParams } from './types'; import { CommonVisitsProps } from './types/CommonVisitsProps'; import { toApiParams } from './types/helpers'; @@ -22,7 +22,7 @@ export interface ShortUrlVisitsProps extends CommonVisitsProps { cancelGetShortUrlVisits: () => void; } -const ShortUrlVisits = ({ exportVisits }: VisitsExporter) => boundToMercureHub(({ +const ShortUrlVisits = ({ exportVisits }: ReportExporter) => boundToMercureHub(({ shortUrlVisits, shortUrlDetail, getShortUrlVisits, diff --git a/src/visits/TagVisits.tsx b/src/visits/TagVisits.tsx index 7305aaaf..993edca7 100644 --- a/src/visits/TagVisits.tsx +++ b/src/visits/TagVisits.tsx @@ -4,10 +4,10 @@ import ColorGenerator from '../utils/services/ColorGenerator'; import { ShlinkVisitsParams } from '../api/types'; import { Topics } from '../mercure/helpers/Topics'; import { useGoBack } from '../utils/helpers/hooks'; +import { ReportExporter } from '../common/services/ReportExporter'; import { TagVisits as TagVisitsState } from './reducers/tagVisits'; import TagVisitsHeader from './TagVisitsHeader'; import VisitsStats from './VisitsStats'; -import { VisitsExporter } from './services/VisitsExporter'; import { NormalizedVisit } from './types'; import { CommonVisitsProps } from './types/CommonVisitsProps'; import { toApiParams } from './types/helpers'; @@ -18,7 +18,7 @@ export interface TagVisitsProps extends CommonVisitsProps { cancelGetTagVisits: () => void; } -const TagVisits = (colorGenerator: ColorGenerator, { exportVisits }: VisitsExporter) => boundToMercureHub(({ +const TagVisits = (colorGenerator: ColorGenerator, { exportVisits }: ReportExporter) => boundToMercureHub(({ getTagVisits, tagVisits, cancelGetTagVisits, diff --git a/src/visits/services/VisitsExporter.ts b/src/visits/services/VisitsExporter.ts deleted file mode 100644 index ff863e8b..00000000 --- a/src/visits/services/VisitsExporter.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CsvJson } from 'csvjson'; -import { NormalizedVisit } from '../types'; -import { saveCsv } from '../../utils/helpers/files'; - -export class VisitsExporter { - public constructor( - private readonly window: Window, - private readonly csvjson: CsvJson, - ) {} - - public readonly exportVisits = (filename: string, visits: NormalizedVisit[]) => { - if (!visits.length) { - return; - } - - const csv = this.csvjson.toCSV(visits, { headers: 'key' }); - - saveCsv(this.window, csv, filename); - }; -} diff --git a/src/visits/services/provideServices.ts b/src/visits/services/provideServices.ts index 626d1ee1..90f02dda 100644 --- a/src/visits/services/provideServices.ts +++ b/src/visits/services/provideServices.ts @@ -12,31 +12,30 @@ import { cancelGetNonOrphanVisits, getNonOrphanVisits } from '../reducers/nonOrp import { ConnectDecorator } from '../../container/types'; import { loadVisitsOverview } from '../reducers/visitsOverview'; import * as visitsParser from './VisitsParser'; -import { VisitsExporter } from './VisitsExporter'; const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Components bottle.serviceFactory('MapModal', () => MapModal); - bottle.serviceFactory('ShortUrlVisits', ShortUrlVisits, 'VisitsExporter'); + bottle.serviceFactory('ShortUrlVisits', ShortUrlVisits, 'ReportExporter'); bottle.decorator('ShortUrlVisits', connect( [ 'shortUrlVisits', 'shortUrlDetail', 'mercureInfo', 'settings', 'selectedServer' ], [ 'getShortUrlVisits', 'getShortUrlDetail', 'cancelGetShortUrlVisits', 'createNewVisits', 'loadMercureInfo' ], )); - bottle.serviceFactory('TagVisits', TagVisits, 'ColorGenerator', 'VisitsExporter'); + bottle.serviceFactory('TagVisits', TagVisits, 'ColorGenerator', 'ReportExporter'); bottle.decorator('TagVisits', connect( [ 'tagVisits', 'mercureInfo', 'settings', 'selectedServer' ], [ 'getTagVisits', 'cancelGetTagVisits', 'createNewVisits', 'loadMercureInfo' ], )); - bottle.serviceFactory('OrphanVisits', OrphanVisits, 'VisitsExporter'); + bottle.serviceFactory('OrphanVisits', OrphanVisits, 'ReportExporter'); bottle.decorator('OrphanVisits', connect( [ 'orphanVisits', 'mercureInfo', 'settings', 'selectedServer' ], [ 'getOrphanVisits', 'cancelGetOrphanVisits', 'createNewVisits', 'loadMercureInfo' ], )); - bottle.serviceFactory('NonOrphanVisits', NonOrphanVisits, 'VisitsExporter'); + bottle.serviceFactory('NonOrphanVisits', NonOrphanVisits, 'ReportExporter'); bottle.decorator('NonOrphanVisits', connect( [ 'nonOrphanVisits', 'mercureInfo', 'settings', 'selectedServer' ], [ 'getNonOrphanVisits', 'cancelGetNonOrphanVisits', 'createNewVisits', 'loadMercureInfo' ], @@ -44,7 +43,6 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { // Services bottle.serviceFactory('VisitsParser', () => visitsParser); - bottle.service('VisitsExporter', VisitsExporter, 'window', 'csvjson'); // Actions bottle.serviceFactory('getShortUrlVisits', getShortUrlVisits, 'buildShlinkApiClient'); diff --git a/test/visits/services/VisitsExporter.test.ts b/test/common/services/ReportExporter.test.ts similarity index 84% rename from test/visits/services/VisitsExporter.test.ts rename to test/common/services/ReportExporter.test.ts index 40a34600..f8848bc3 100644 --- a/test/visits/services/VisitsExporter.test.ts +++ b/test/common/services/ReportExporter.test.ts @@ -1,20 +1,20 @@ import { Mock } from 'ts-mockery'; import { CsvJson } from 'csvjson'; -import { VisitsExporter } from '../../../src/visits/services/VisitsExporter'; +import { ReportExporter } from '../../../src/common/services/ReportExporter'; import { NormalizedVisit } from '../../../src/visits/types'; import { windowMock } from '../../mocks/WindowMock'; -describe('VisitsExporter', () => { +describe('ReportExporter', () => { const toCSV = jest.fn(); const csvToJsonMock = Mock.of({ toCSV }); - let exporter: VisitsExporter; + let exporter: ReportExporter; beforeEach(jest.clearAllMocks); beforeEach(() => { (global as any).Blob = class Blob {}; // eslint-disable-line @typescript-eslint/no-extraneous-class (global as any).URL = { createObjectURL: () => '' }; - exporter = new VisitsExporter(windowMock, csvToJsonMock); + exporter = new ReportExporter(windowMock, csvToJsonMock); }); describe('exportVisits', () => { @@ -35,7 +35,7 @@ describe('VisitsExporter', () => { exporter.exportVisits('my_visits.csv', visits); - expect(toCSV).toHaveBeenCalledWith(visits, { headers: 'key' }); + expect(toCSV).toHaveBeenCalledWith(visits, { headers: 'key', wrap: true }); }); it('skips execution when list of visits is empty', () => { diff --git a/test/short-urls/ShortUrlsFilteringBar.test.tsx b/test/short-urls/ShortUrlsFilteringBar.test.tsx index 3d479c15..4e0dbbe6 100644 --- a/test/short-urls/ShortUrlsFilteringBar.test.tsx +++ b/test/short-urls/ShortUrlsFilteringBar.test.tsx @@ -20,7 +20,8 @@ jest.mock('react-router-dom', () => ({ describe('', () => { let wrapper: ShallowWrapper; - const ShortUrlsFilteringBar = filteringBarCreator(Mock.all()); + const ExportShortUrlsBtn = () => null; + const ShortUrlsFilteringBar = filteringBarCreator(Mock.all(), ExportShortUrlsBtn); const navigate = jest.fn(); const handleOrderBy = jest.fn(); const now = new Date(); @@ -48,6 +49,7 @@ describe('', () => { expect(wrapper.find(SearchField)).toHaveLength(1); expect(wrapper.find(DateRangeSelector)).toHaveLength(1); expect(wrapper.find(OrderingDropdown)).toHaveLength(1); + expect(wrapper.find(ExportShortUrlsBtn)).toHaveLength(1); }); it.each([ diff --git a/test/short-urls/ShortUrlsList.test.tsx b/test/short-urls/ShortUrlsList.test.tsx index 0184629e..dae43287 100644 --- a/test/short-urls/ShortUrlsList.test.tsx +++ b/test/short-urls/ShortUrlsList.test.tsx @@ -33,6 +33,7 @@ describe('', () => { tags: [ 'test tag' ], }), ], + pagination: {}, }, }); const ShortUrlsList = shortUrlsListCreator(ShortUrlsTable, ShortUrlsFilteringBar); diff --git a/test/utils/ExportBtn.test.tsx b/test/utils/ExportBtn.test.tsx index 7ee7b705..97d27eee 100644 --- a/test/utils/ExportBtn.test.tsx +++ b/test/utils/ExportBtn.test.tsx @@ -5,9 +5,8 @@ import { ExportBtn } from '../../src/utils/ExportBtn'; describe('', () => { let wrapper: ShallowWrapper; - const onClick = jest.fn(); - const createWrapper = (className?: string, amount?: number) => { - wrapper = shallow(); + const createWrapper = (amount?: number, loading = false) => { + wrapper = shallow(); return wrapper; }; @@ -16,16 +15,15 @@ describe('', () => { afterEach(() => wrapper?.unmount()); it.each([ - [ undefined ], - [ 'foo' ], - [ 'bar' ], - ])('renders a button', (className) => { - const wrapper = createWrapper(className); + [ true, 'Exporting...' ], + [ false, 'Export (' ], + ])('renders a button', (loading, text) => { + const wrapper = createWrapper(undefined, loading); expect(wrapper.prop('outline')).toEqual(true); expect(wrapper.prop('color')).toEqual('primary'); - expect(wrapper.prop('onClick')).toEqual(onClick); - expect(wrapper.prop('className')).toEqual(className); + expect(wrapper.prop('disabled')).toEqual(loading); + expect(wrapper.html()).toContain(text); }); it.each([ @@ -34,7 +32,7 @@ describe('', () => { [ 10_000, '10,000' ], [ 10_000_000, '10,000,000' ], ])('renders expected amount', (amount, expectedRenderedAmount) => { - const wrapper = createWrapper(undefined, amount); + const wrapper = createWrapper(amount); expect(wrapper.html()).toContain(`Export (${expectedRenderedAmount})`); }); @@ -46,12 +44,4 @@ describe('', () => { expect(icon).toHaveLength(1); expect(icon.prop('icon')).toEqual(faFileDownload); }); - - it('invokes callback onClick', () => { - const wrapper = createWrapper(); - - expect(onClick).not.toHaveBeenCalled(); - wrapper.simulate('click'); - expect(onClick).toHaveBeenCalledTimes(1); - }); }); diff --git a/test/visits/NonOrphanVisits.test.tsx b/test/visits/NonOrphanVisits.test.tsx index c1af476b..db6e7666 100644 --- a/test/visits/NonOrphanVisits.test.tsx +++ b/test/visits/NonOrphanVisits.test.tsx @@ -6,7 +6,7 @@ import { VisitsInfo } from '../../src/visits/types'; import VisitsStats from '../../src/visits/VisitsStats'; import { NonOrphanVisitsHeader } from '../../src/visits/NonOrphanVisitsHeader'; import { Settings } from '../../src/settings/reducers/settings'; -import { VisitsExporter } from '../../src/visits/services/VisitsExporter'; +import { ReportExporter } from '../../src/common/services/ReportExporter'; import { SelectedServer } from '../../src/servers/data'; jest.mock('react-router-dom', () => ({ @@ -20,7 +20,7 @@ describe('', () => { const getNonOrphanVisits = jest.fn(); const cancelGetNonOrphanVisits = jest.fn(); const nonOrphanVisits = Mock.all(); - const NonOrphanVisits = createNonOrphanVisits(Mock.all()); + const NonOrphanVisits = createNonOrphanVisits(Mock.all()); const wrapper = shallow( ({ @@ -20,7 +20,7 @@ describe('', () => { const getOrphanVisits = jest.fn(); const cancelGetOrphanVisits = jest.fn(); const orphanVisits = Mock.all(); - const OrphanVisits = createOrphanVisits(Mock.all()); + const OrphanVisits = createOrphanVisits(Mock.all()); const wrapper = shallow( ({ ...jest.requireActual('react-router-dom'), @@ -19,7 +19,7 @@ jest.mock('react-router-dom', () => ({ describe('', () => { let wrapper: ShallowWrapper; const getShortUrlVisitsMock = jest.fn(); - const ShortUrlVisits = createShortUrlVisits(Mock.all()); + const ShortUrlVisits = createShortUrlVisits(Mock.all()); beforeEach(() => { wrapper = shallow( diff --git a/test/visits/TagVisits.test.tsx b/test/visits/TagVisits.test.tsx index 10d60d6a..b95e7be4 100644 --- a/test/visits/TagVisits.test.tsx +++ b/test/visits/TagVisits.test.tsx @@ -6,7 +6,7 @@ import ColorGenerator from '../../src/utils/services/ColorGenerator'; import { TagVisits as TagVisitsStats } from '../../src/visits/reducers/tagVisits'; import VisitsStats from '../../src/visits/VisitsStats'; import { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; -import { VisitsExporter } from '../../src/visits/services/VisitsExporter'; +import { ReportExporter } from '../../src/common/services/ReportExporter'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -20,7 +20,7 @@ describe('', () => { const getTagVisitsMock = jest.fn(); beforeEach(() => { - const TagVisits = createTagVisits(Mock.all(), Mock.all()); + const TagVisits = createTagVisits(Mock.all(), Mock.all()); wrapper = shallow(