mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 17:40:23 +03:00
Merge pull request #640 from acelaya-forks/feature/more-rtl-tests
Feature/more rtl tests
This commit is contained in:
commit
686fe5abbe
25 changed files with 870 additions and 383 deletions
|
@ -3,3 +3,5 @@ import 'jest-canvas-mock';
|
||||||
import ResizeObserver from 'resize-observer-polyfill';
|
import ResizeObserver from 'resize-observer-polyfill';
|
||||||
|
|
||||||
(global as any).ResizeObserver = ResizeObserver;
|
(global as any).ResizeObserver = ResizeObserver;
|
||||||
|
(global as any).scrollTo = () => {};
|
||||||
|
(global as any).matchMedia = (media: string) => ({ matches: false, media });
|
||||||
|
|
|
@ -9,10 +9,10 @@ module.exports = {
|
||||||
],
|
],
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
statements: 85,
|
statements: 90,
|
||||||
branches: 80,
|
branches: 80,
|
||||||
functions: 80,
|
functions: 85,
|
||||||
lines: 85,
|
lines: 90,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setupFiles: ['<rootDir>/config/jest/setupBeforeEnzyme.js', '<rootDir>/config/jest/setupEnzyme.js'],
|
setupFiles: ['<rootDir>/config/jest/setupBeforeEnzyme.js', '<rootDir>/config/jest/setupEnzyme.js'],
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
"build:serve": "serve -p 5000 ./build",
|
"build:serve": "serve -p 5000 ./build",
|
||||||
"test": "jest --env=jsdom --colors --verbose",
|
"test": "jest --env=jsdom --colors --verbose",
|
||||||
"test:coverage": "npm run test -- --coverage --coverageReporters=text --coverageReporters=text-summary",
|
"test:coverage": "npm run test -- --coverage --coverageReporters=text --coverageReporters=text-summary",
|
||||||
"test:ci": "npm run test:coverage -- --coverageReporters=clover",
|
"test:ci": "npm run test:coverage -- --coverageReporters=clover --ci",
|
||||||
"test:pretty": "npm run test:coverage -- --coverageReporters=html",
|
"test:pretty": "npm run test:coverage -- --coverageReporters=html",
|
||||||
"mutate": "./node_modules/.bin/stryker run --concurrency 4 --ignoreStatic"
|
"mutate": "./node_modules/.bin/stryker run --concurrency 4 --ignoreStatic"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { FC, PropsWithChildren, useEffect } from 'react';
|
import { FC, PropsWithChildren, useEffect } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
const ScrollToTop = (): FC<PropsWithChildren<unknown>> => ({ children }) => {
|
export const ScrollToTop: FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -10,5 +10,3 @@ const ScrollToTop = (): FC<PropsWithChildren<unknown>> => ({ children }) => {
|
||||||
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ScrollToTop;
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ interface SimplePaginatorProps {
|
||||||
centered?: boolean;
|
centered?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SimplePaginator: FC<SimplePaginatorProps> = ({ pagesCount, currentPage, setCurrentPage, centered = true }) => {
|
export const SimplePaginator: FC<SimplePaginatorProps> = (
|
||||||
|
{ pagesCount, currentPage, setCurrentPage, centered = true },
|
||||||
|
) => {
|
||||||
if (pagesCount < 2) {
|
if (pagesCount < 2) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +37,9 @@ const SimplePaginator: FC<SimplePaginatorProps> = ({ pagesCount, currentPage, se
|
||||||
disabled={pageIsEllipsis(pageNumber)}
|
disabled={pageIsEllipsis(pageNumber)}
|
||||||
active={currentPage === pageNumber}
|
active={currentPage === pageNumber}
|
||||||
>
|
>
|
||||||
<PaginationLink tag="span" onClick={onClick(pageNumber)}>{prettifyPageNumber(pageNumber)}</PaginationLink>
|
<PaginationLink role="link" tag="span" onClick={onClick(pageNumber)}>
|
||||||
|
{prettifyPageNumber(pageNumber)}
|
||||||
|
</PaginationLink>
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
))}
|
))}
|
||||||
<PaginationItem disabled={currentPage >= pagesCount}>
|
<PaginationItem disabled={currentPage >= pagesCount}>
|
||||||
|
@ -44,5 +48,3 @@ const SimplePaginator: FC<SimplePaginatorProps> = ({ pagesCount, currentPage, se
|
||||||
</Pagination>
|
</Pagination>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SimplePaginator;
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Bottle from 'bottlejs';
|
import Bottle from 'bottlejs';
|
||||||
import ScrollToTop from '../ScrollToTop';
|
import { ScrollToTop } from '../ScrollToTop';
|
||||||
import { MainHeader } from '../MainHeader';
|
import { MainHeader } from '../MainHeader';
|
||||||
import { Home } from '../Home';
|
import { Home } from '../Home';
|
||||||
import { MenuLayout } from '../MenuLayout';
|
import { MenuLayout } from '../MenuLayout';
|
||||||
|
@ -23,7 +23,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.service('ReportExporter', ReportExporter, 'window', 'jsonToCsv');
|
bottle.service('ReportExporter', ReportExporter, 'window', 'jsonToCsv');
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
bottle.serviceFactory('ScrollToTop', ScrollToTop);
|
bottle.serviceFactory('ScrollToTop', () => ScrollToTop);
|
||||||
|
|
||||||
bottle.serviceFactory('MainHeader', MainHeader, 'ServersDropdown');
|
bottle.serviceFactory('MainHeader', MainHeader, 'ServersDropdown');
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ export const DomainSelector = ({ listDomains, value, domainsList, onChange }: Do
|
||||||
outline
|
outline
|
||||||
type="button"
|
type="button"
|
||||||
className="domains-dropdown__back-btn"
|
className="domains-dropdown__back-btn"
|
||||||
|
aria-label="Back to domains list"
|
||||||
onClick={pipe(unselectDomain, hideInput)}
|
onClick={pipe(unselectDomain, hideInput)}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faUndo} />
|
<FontAwesomeIcon icon={faUndo} />
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { FC, useEffect, useRef } from 'react';
|
||||||
import { splitEvery } from 'ramda';
|
import { splitEvery } from 'ramda';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { SimpleCard } from '../utils/SimpleCard';
|
import { SimpleCard } from '../utils/SimpleCard';
|
||||||
import SimplePaginator from '../common/SimplePaginator';
|
import { SimplePaginator } from '../common/SimplePaginator';
|
||||||
import { useQueryState } from '../utils/helpers/hooks';
|
import { useQueryState } from '../utils/helpers/hooks';
|
||||||
import { parseQuery } from '../utils/helpers/query';
|
import { parseQuery } from '../utils/helpers/query';
|
||||||
import { TableOrderIcon } from '../utils/table/TableOrderIcon';
|
import { TableOrderIcon } from '../utils/table/TableOrderIcon';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { min, splitEvery } from 'ramda';
|
||||||
import { faCheck as checkIcon, faRobot as botIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faCheck as checkIcon, faRobot as botIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { UncontrolledTooltip } from 'reactstrap';
|
import { UncontrolledTooltip } from 'reactstrap';
|
||||||
import SimplePaginator from '../common/SimplePaginator';
|
import { SimplePaginator } from '../common/SimplePaginator';
|
||||||
import SearchField from '../utils/SearchField';
|
import SearchField from '../utils/SearchField';
|
||||||
import { determineOrderDir, Order, sortList } from '../utils/helpers/ordering';
|
import { determineOrderDir, Order, sortList } from '../utils/helpers/ordering';
|
||||||
import { prettify } from '../utils/helpers/numbers';
|
import { prettify } from '../utils/helpers/numbers';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { FC, useState } from 'react';
|
||||||
import { fromPairs, pipe, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda';
|
import { fromPairs, pipe, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda';
|
||||||
import { rangeOf } from '../../utils/utils';
|
import { rangeOf } from '../../utils/utils';
|
||||||
import { Order } from '../../utils/helpers/ordering';
|
import { Order } from '../../utils/helpers/ordering';
|
||||||
import SimplePaginator from '../../common/SimplePaginator';
|
import { SimplePaginator } from '../../common/SimplePaginator';
|
||||||
import { roundTen } from '../../utils/helpers/numbers';
|
import { roundTen } from '../../utils/helpers/numbers';
|
||||||
import { OrderingDropdown } from '../../utils/OrderingDropdown';
|
import { OrderingDropdown } from '../../utils/OrderingDropdown';
|
||||||
import PaginationDropdown from '../../utils/PaginationDropdown';
|
import PaginationDropdown from '../../utils/PaginationDropdown';
|
||||||
|
|
|
@ -1,47 +1,32 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { Link } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { NotFound } from '../../src/common/NotFound';
|
import { NotFound } from '../../src/common/NotFound';
|
||||||
import { SimpleCard } from '../../src/utils/SimpleCard';
|
|
||||||
|
|
||||||
describe('<NotFound />', () => {
|
describe('<NotFound />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (props = {}) => render(<MemoryRouter><NotFound {...props} /></MemoryRouter>);
|
||||||
const createWrapper = (props = {}) => {
|
|
||||||
wrapper = shallow(<NotFound {...props} />).find(SimpleCard);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it('shows expected error title', () => {
|
it('shows expected error title', () => {
|
||||||
const wrapper = createWrapper();
|
setUp();
|
||||||
|
expect(screen.getByText('Oops! We could not find requested route.')).toBeInTheDocument();
|
||||||
expect(wrapper.contains('Oops! We could not find requested route.')).toEqual(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows expected error message', () => {
|
it('shows expected error message', () => {
|
||||||
const wrapper = createWrapper();
|
setUp();
|
||||||
|
expect(screen.getByText(
|
||||||
expect(wrapper.contains(
|
|
||||||
'Use your browser\'s back button to navigate to the page you have previously come from, or just press this button.',
|
'Use your browser\'s back button to navigate to the page you have previously come from, or just press this button.',
|
||||||
)).toEqual(true);
|
)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows a link to the home', () => {
|
it.each([
|
||||||
const wrapper = createWrapper();
|
[{}, '/', 'Home'],
|
||||||
const link = wrapper.find(Link);
|
[{ to: '/foo/bar', children: 'Hello' }, '/foo/bar', 'Hello'],
|
||||||
|
[{ to: '/baz-bar', children: <>Foo</> }, '/baz-bar', 'Foo'],
|
||||||
|
])('shows expected link and text', (props, expectedLink, expectedText) => {
|
||||||
|
setUp(props);
|
||||||
|
const link = screen.getByRole('link');
|
||||||
|
|
||||||
expect(link.prop('to')).toEqual('/');
|
expect(link).toHaveAttribute('href', expectedLink);
|
||||||
expect(link.prop('className')).toEqual('btn btn-outline-primary btn-lg');
|
expect(link).toHaveTextContent(expectedText);
|
||||||
expect(link.prop('children')).toEqual('Home');
|
expect(link).toHaveAttribute('class', 'btn btn-outline-primary btn-lg');
|
||||||
});
|
|
||||||
|
|
||||||
it('shows a link with provided props', () => {
|
|
||||||
const wrapper = createWrapper({ to: '/foo/bar', children: 'Hello' });
|
|
||||||
const link = wrapper.find(Link);
|
|
||||||
|
|
||||||
expect(link.prop('to')).toEqual('/foo/bar');
|
|
||||||
expect(link.prop('className')).toEqual('btn btn-outline-primary btn-lg');
|
|
||||||
expect(link.prop('children')).toEqual('Hello');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,21 +1,14 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render, screen } from '@testing-library/react';
|
||||||
import createScrollToTop from '../../src/common/ScrollToTop';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import { ScrollToTop } from '../../src/common/ScrollToTop';
|
||||||
jest.mock('react-router-dom', () => ({
|
|
||||||
...jest.requireActual('react-router-dom'),
|
|
||||||
useLocation: jest.fn().mockReturnValue({}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('<ScrollToTop />', () => {
|
describe('<ScrollToTop />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
it.each([
|
||||||
|
['Foobar'],
|
||||||
beforeEach(() => {
|
['Barfoo'],
|
||||||
const ScrollToTop = createScrollToTop();
|
['Something'],
|
||||||
|
])('just renders children', (children) => {
|
||||||
wrapper = shallow(<ScrollToTop>Foobar</ScrollToTop>);
|
render(<MemoryRouter><ScrollToTop>{children}</ScrollToTop></MemoryRouter>);
|
||||||
|
expect(screen.getByText(children)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => wrapper.unmount());
|
|
||||||
|
|
||||||
it('just renders children', () => expect(wrapper.text()).toEqual('Foobar'));
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import ShlinkVersions, { ShlinkVersionsProps } from '../../src/common/ShlinkVersions';
|
import ShlinkVersions, { ShlinkVersionsProps } from '../../src/common/ShlinkVersions';
|
||||||
import { NonReachableServer, NotFoundServer, ReachableServer } from '../../src/servers/data';
|
import { NonReachableServer, NotFoundServer, ReachableServer } from '../../src/servers/data';
|
||||||
|
|
||||||
describe('<ShlinkVersions />', () => {
|
describe('<ShlinkVersions />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (props: ShlinkVersionsProps) => render(<ShlinkVersions {...props} />);
|
||||||
const createWrapper = (props: ShlinkVersionsProps) => {
|
|
||||||
wrapper = shallow(<ShlinkVersions {...props} />);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['1.2.3', Mock.of<ReachableServer>({ version: '1.0.0', printableVersion: 'foo' }), 'v1.2.3', 'foo'],
|
['1.2.3', Mock.of<ReachableServer>({ version: '1.0.0', printableVersion: 'foo' }), 'v1.2.3', 'foo'],
|
||||||
|
@ -22,15 +15,19 @@ describe('<ShlinkVersions />', () => {
|
||||||
])(
|
])(
|
||||||
'displays expected versions when selected server is reachable',
|
'displays expected versions when selected server is reachable',
|
||||||
(clientVersion, selectedServer, expectedClientVersion, expectedServerVersion) => {
|
(clientVersion, selectedServer, expectedClientVersion, expectedServerVersion) => {
|
||||||
const wrapper = createWrapper({ clientVersion, selectedServer });
|
setUp({ clientVersion, selectedServer });
|
||||||
const links = wrapper.find('VersionLink');
|
const [serverLink, clientLink] = screen.getAllByRole('link');
|
||||||
const serverLink = links.at(0);
|
|
||||||
const clientLink = links.at(1);
|
|
||||||
|
|
||||||
expect(serverLink.prop('project')).toEqual('shlink');
|
expect(serverLink).toHaveAttribute(
|
||||||
expect(serverLink.prop('version')).toEqual(expectedServerVersion);
|
'href',
|
||||||
expect(clientLink.prop('project')).toEqual('shlink-web-client');
|
`https://github.com/shlinkio/shlink/releases/${expectedServerVersion}`,
|
||||||
expect(clientLink.prop('version')).toEqual(expectedClientVersion);
|
);
|
||||||
|
expect(serverLink).toHaveTextContent(expectedServerVersion);
|
||||||
|
expect(clientLink).toHaveAttribute(
|
||||||
|
'href',
|
||||||
|
`https://github.com/shlinkio/shlink-web-client/releases/${expectedClientVersion}`,
|
||||||
|
);
|
||||||
|
expect(clientLink).toHaveTextContent(expectedClientVersion);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -39,10 +36,10 @@ describe('<ShlinkVersions />', () => {
|
||||||
['1.2.3', Mock.of<NotFoundServer>({ serverNotFound: true })],
|
['1.2.3', Mock.of<NotFoundServer>({ serverNotFound: true })],
|
||||||
['1.2.3', Mock.of<NonReachableServer>({ serverNotReachable: true })],
|
['1.2.3', Mock.of<NonReachableServer>({ serverNotReachable: true })],
|
||||||
])('displays only client version when selected server is not reachable', (clientVersion, selectedServer) => {
|
])('displays only client version when selected server is not reachable', (clientVersion, selectedServer) => {
|
||||||
const wrapper = createWrapper({ clientVersion, selectedServer });
|
setUp({ clientVersion, selectedServer });
|
||||||
const links = wrapper.find('VersionLink');
|
const links = screen.getAllByRole('link');
|
||||||
|
|
||||||
expect(links).toHaveLength(1);
|
expect(links).toHaveLength(1);
|
||||||
expect(links.at(0).prop('project')).toEqual('shlink-web-client');
|
expect(links[0]).toHaveAttribute('href', 'https://github.com/shlinkio/shlink-web-client/releases/v1.2.3');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,26 +1,19 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render } from '@testing-library/react';
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import ShlinkVersionsContainer from '../../src/common/ShlinkVersionsContainer';
|
import ShlinkVersionsContainer from '../../src/common/ShlinkVersionsContainer';
|
||||||
import { SelectedServer } from '../../src/servers/data';
|
import { SelectedServer } from '../../src/servers/data';
|
||||||
import { Sidebar } from '../../src/common/reducers/sidebar';
|
import { Sidebar } from '../../src/common/reducers/sidebar';
|
||||||
|
|
||||||
describe('<ShlinkVersionsContainer />', () => {
|
describe('<ShlinkVersionsContainer />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (sidebar: Sidebar) => render(
|
||||||
|
<ShlinkVersionsContainer selectedServer={Mock.all<SelectedServer>()} sidebar={sidebar} />,
|
||||||
const createWrapper = (sidebar: Sidebar) => {
|
);
|
||||||
wrapper = shallow(<ShlinkVersionsContainer selectedServer={Mock.all<SelectedServer>()} sidebar={sidebar} />);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[{ sidebarPresent: false }, 'text-center'],
|
[{ sidebarPresent: false }, 'text-center'],
|
||||||
[{ sidebarPresent: true }, 'text-center shlink-versions-container--with-sidebar'],
|
[{ sidebarPresent: true }, 'text-center shlink-versions-container--with-sidebar'],
|
||||||
])('renders proper col classes based on sidebar status', (sidebar, expectedClasses) => {
|
])('renders proper col classes based on sidebar status', (sidebar, expectedClasses) => {
|
||||||
const wrapper = createWrapper(sidebar);
|
const { container } = setUp(sidebar);
|
||||||
|
expect(container.firstChild).toHaveAttribute('class', `${expectedClasses}`);
|
||||||
expect(wrapper.find('div').prop('className')).toEqual(`${expectedClasses}`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,28 +1,23 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { identity } from 'ramda';
|
import { SimplePaginator } from '../../src/common/SimplePaginator';
|
||||||
import { PaginationItem } from 'reactstrap';
|
|
||||||
import SimplePaginator from '../../src/common/SimplePaginator';
|
|
||||||
import { ELLIPSIS } from '../../src/utils/helpers/pagination';
|
import { ELLIPSIS } from '../../src/utils/helpers/pagination';
|
||||||
|
|
||||||
describe('<SimplePaginator />', () => {
|
describe('<SimplePaginator />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (pagesCount: number, currentPage = 1) => render(
|
||||||
const createWrapper = (pagesCount: number, currentPage = 1) => {
|
<SimplePaginator pagesCount={pagesCount} currentPage={currentPage} setCurrentPage={jest.fn()} />,
|
||||||
wrapper = shallow(<SimplePaginator pagesCount={pagesCount} currentPage={currentPage} setCurrentPage={identity} />);
|
);
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it.each([-3, -2, 0, 1])('renders empty when the amount of pages is smaller than 2', (pagesCount) => {
|
it.each([-3, -2, 0, 1])('renders empty when the amount of pages is smaller than 2', (pagesCount) => {
|
||||||
expect(createWrapper(pagesCount).text()).toEqual('');
|
const { container } = setUp(pagesCount);
|
||||||
|
expect(container.firstChild).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ELLIPSIS are rendered where expected', () => {
|
describe('ELLIPSIS are rendered where expected', () => {
|
||||||
const getItemsForPages = (pagesCount: number, currentPage: number) => {
|
const getItemsForPages = (pagesCount: number, currentPage: number) => {
|
||||||
const paginator = createWrapper(pagesCount, currentPage);
|
setUp(pagesCount, currentPage);
|
||||||
const items = paginator.find(PaginationItem);
|
|
||||||
const itemsWithEllipsis = items.filterWhere((item) => item?.key()?.includes(ELLIPSIS));
|
const items = screen.getAllByRole('link');
|
||||||
|
const itemsWithEllipsis = items.filter((item) => item.innerHTML.includes(ELLIPSIS));
|
||||||
|
|
||||||
return { items, itemsWithEllipsis };
|
return { items, itemsWithEllipsis };
|
||||||
};
|
};
|
||||||
|
@ -30,22 +25,22 @@ describe('<SimplePaginator />', () => {
|
||||||
it('renders first ELLIPSIS', () => {
|
it('renders first ELLIPSIS', () => {
|
||||||
const { items, itemsWithEllipsis } = getItemsForPages(9, 7);
|
const { items, itemsWithEllipsis } = getItemsForPages(9, 7);
|
||||||
|
|
||||||
expect(items.at(2).html()).toContain(ELLIPSIS);
|
expect(items[1]).toHaveTextContent(ELLIPSIS);
|
||||||
expect(itemsWithEllipsis).toHaveLength(1);
|
expect(itemsWithEllipsis).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders last ELLIPSIS', () => {
|
it('renders last ELLIPSIS', () => {
|
||||||
const { items, itemsWithEllipsis } = getItemsForPages(9, 2);
|
const { items, itemsWithEllipsis } = getItemsForPages(9, 2);
|
||||||
|
|
||||||
expect(items.at(items.length - 3).html()).toContain(ELLIPSIS);
|
expect(items[items.length - 2]).toHaveTextContent(ELLIPSIS);
|
||||||
expect(itemsWithEllipsis).toHaveLength(1);
|
expect(itemsWithEllipsis).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders both ELLIPSIS', () => {
|
it('renders both ELLIPSIS', () => {
|
||||||
const { items, itemsWithEllipsis } = getItemsForPages(20, 9);
|
const { items, itemsWithEllipsis } = getItemsForPages(20, 9);
|
||||||
|
|
||||||
expect(items.at(2).html()).toContain(ELLIPSIS);
|
expect(items[1]).toHaveTextContent(ELLIPSIS);
|
||||||
expect(items.at(items.length - 3).html()).toContain(ELLIPSIS);
|
expect(items[items.length - 2]).toHaveTextContent(ELLIPSIS);
|
||||||
expect(itemsWithEllipsis).toHaveLength(2);
|
expect(itemsWithEllipsis).toHaveLength(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,25 +1,17 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render } from '@testing-library/react';
|
||||||
import { ShlinkLogo, ShlinkLogoProps } from '../../../src/common/img/ShlinkLogo';
|
import { ShlinkLogo, ShlinkLogoProps } from '../../../src/common/img/ShlinkLogo';
|
||||||
import { MAIN_COLOR } from '../../../src/utils/theme';
|
import { MAIN_COLOR } from '../../../src/utils/theme';
|
||||||
|
|
||||||
describe('<ShlinkLogo />', () => {
|
describe('<ShlinkLogo />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (props: ShlinkLogoProps) => render(<ShlinkLogo {...props} />);
|
||||||
const createWrapper = (props: ShlinkLogoProps) => {
|
|
||||||
wrapper = shallow(<ShlinkLogo {...props} />);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[undefined, MAIN_COLOR],
|
[undefined, MAIN_COLOR],
|
||||||
['red', 'red'],
|
['red', 'red'],
|
||||||
['white', 'white'],
|
['white', 'white'],
|
||||||
])('renders expected color', (color, expectedColor) => {
|
])('renders expected color', (color, expectedColor) => {
|
||||||
const wrapper = createWrapper({ color });
|
const { container } = setUp({ color });
|
||||||
|
expect(container.querySelector('g')).toHaveAttribute('fill', expectedColor);
|
||||||
expect(wrapper.find('g').prop('fill')).toEqual(expectedColor);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
|
@ -27,8 +19,12 @@ describe('<ShlinkLogo />', () => {
|
||||||
['foo', 'foo'],
|
['foo', 'foo'],
|
||||||
['bar', 'bar'],
|
['bar', 'bar'],
|
||||||
])('renders expected class', (className, expectedClassName) => {
|
])('renders expected class', (className, expectedClassName) => {
|
||||||
const wrapper = createWrapper({ className });
|
const { container } = setUp({ className });
|
||||||
|
|
||||||
expect(wrapper.prop('className')).toEqual(expectedClassName);
|
if (expectedClassName) {
|
||||||
|
expect(container.firstChild).toHaveAttribute('class', expectedClassName);
|
||||||
|
} else {
|
||||||
|
expect(container.firstChild).not.toHaveAttribute('class');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import { ShlinkDomainRedirects } from '../../src/api/types';
|
import { ShlinkDomainRedirects } from '../../src/api/types';
|
||||||
import { DomainRow } from '../../src/domains/DomainRow';
|
import { DomainRow } from '../../src/domains/DomainRow';
|
||||||
|
@ -6,42 +6,71 @@ import { SelectedServer } from '../../src/servers/data';
|
||||||
import { Domain } from '../../src/domains/data';
|
import { Domain } from '../../src/domains/data';
|
||||||
|
|
||||||
describe('<DomainRow />', () => {
|
describe('<DomainRow />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
const redirectsCombinations = [
|
||||||
const createWrapper = (domain: Domain, selectedServer = Mock.all<SelectedServer>()) => {
|
[Mock.of<ShlinkDomainRedirects>({ baseUrlRedirect: 'foo' })],
|
||||||
wrapper = shallow(
|
[Mock.of<ShlinkDomainRedirects>({ invalidShortUrlRedirect: 'bar' })],
|
||||||
<DomainRow
|
[Mock.of<ShlinkDomainRedirects>({ baseUrlRedirect: 'baz', regular404Redirect: 'foo' })],
|
||||||
domain={domain}
|
|
||||||
selectedServer={selectedServer}
|
|
||||||
editDomainRedirects={jest.fn()}
|
|
||||||
checkDomainHealth={jest.fn()}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
[undefined, 3],
|
|
||||||
[Mock.of<ShlinkDomainRedirects>(), 3],
|
|
||||||
[Mock.of<ShlinkDomainRedirects>({ baseUrlRedirect: 'foo' }), 2],
|
|
||||||
[Mock.of<ShlinkDomainRedirects>({ invalidShortUrlRedirect: 'foo' }), 2],
|
|
||||||
[Mock.of<ShlinkDomainRedirects>({ baseUrlRedirect: 'foo', regular404Redirect: 'foo' }), 1],
|
|
||||||
[
|
[
|
||||||
Mock.of<ShlinkDomainRedirects>(
|
Mock.of<ShlinkDomainRedirects>(
|
||||||
{ baseUrlRedirect: 'foo', regular404Redirect: 'foo', invalidShortUrlRedirect: 'foo' },
|
{ baseUrlRedirect: 'baz', regular404Redirect: 'bar', invalidShortUrlRedirect: 'foo' },
|
||||||
),
|
),
|
||||||
0,
|
|
||||||
],
|
],
|
||||||
])('shows expected redirects', (redirects, expectedNoRedirects) => {
|
];
|
||||||
const wrapper = createWrapper(Mock.of<Domain>({ domain: '', isDefault: true, redirects }));
|
const setUp = (domain: Domain, defaultRedirects?: ShlinkDomainRedirects) => render(
|
||||||
const noRedirects = wrapper.find('Nr');
|
<DomainRow
|
||||||
const cells = wrapper.find('td');
|
domain={domain}
|
||||||
|
defaultRedirects={defaultRedirects}
|
||||||
|
selectedServer={Mock.all<SelectedServer>()}
|
||||||
|
editDomainRedirects={jest.fn()}
|
||||||
|
checkDomainHealth={jest.fn()}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
expect(noRedirects).toHaveLength(expectedNoRedirects);
|
it.each(redirectsCombinations)('shows expected redirects', (redirects) => {
|
||||||
redirects?.baseUrlRedirect && expect(cells.at(1).html()).toContain(redirects.baseUrlRedirect);
|
setUp(Mock.of<Domain>({ domain: '', isDefault: true, redirects }));
|
||||||
redirects?.regular404Redirect && expect(cells.at(2).html()).toContain(redirects.regular404Redirect);
|
const cells = screen.getAllByRole('cell');
|
||||||
redirects?.invalidShortUrlRedirect && expect(cells.at(3).html()).toContain(redirects.invalidShortUrlRedirect);
|
|
||||||
|
redirects?.baseUrlRedirect && expect(cells[1]).toHaveTextContent(redirects.baseUrlRedirect);
|
||||||
|
redirects?.regular404Redirect && expect(cells[2]).toHaveTextContent(redirects.regular404Redirect);
|
||||||
|
redirects?.invalidShortUrlRedirect && expect(cells[3]).toHaveTextContent(redirects.invalidShortUrlRedirect);
|
||||||
|
expect(screen.queryByText('(as fallback)')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[undefined],
|
||||||
|
[Mock.of<ShlinkDomainRedirects>()],
|
||||||
|
])('shows expected "no redirects"', (redirects) => {
|
||||||
|
setUp(Mock.of<Domain>({ domain: '', isDefault: true, redirects }));
|
||||||
|
const cells = screen.getAllByRole('cell');
|
||||||
|
|
||||||
|
expect(cells[1]).toHaveTextContent('No redirect');
|
||||||
|
expect(cells[2]).toHaveTextContent('No redirect');
|
||||||
|
expect(cells[3]).toHaveTextContent('No redirect');
|
||||||
|
expect(screen.queryByText('(as fallback)')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(redirectsCombinations)('shows expected fallback redirects', (fallbackRedirects) => {
|
||||||
|
setUp(Mock.of<Domain>({ domain: '', isDefault: true }), fallbackRedirects);
|
||||||
|
const cells = screen.getAllByRole('cell');
|
||||||
|
|
||||||
|
fallbackRedirects?.baseUrlRedirect && expect(cells[1]).toHaveTextContent(
|
||||||
|
`${fallbackRedirects.baseUrlRedirect} (as fallback)`,
|
||||||
|
);
|
||||||
|
fallbackRedirects?.regular404Redirect && expect(cells[2]).toHaveTextContent(
|
||||||
|
`${fallbackRedirects.regular404Redirect} (as fallback)`,
|
||||||
|
);
|
||||||
|
fallbackRedirects?.invalidShortUrlRedirect && expect(cells[3]).toHaveTextContent(
|
||||||
|
`${fallbackRedirects.invalidShortUrlRedirect} (as fallback)`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([[true], [false]])('shows icon on default domain only', (isDefault) => {
|
||||||
|
const { container } = setUp(Mock.of<Domain>({ domain: '', isDefault }));
|
||||||
|
|
||||||
|
if (isDefault) {
|
||||||
|
expect(container.querySelector('#defaultDomainIcon')).toBeInTheDocument();
|
||||||
|
} else {
|
||||||
|
expect(container.querySelector('#defaultDomainIcon')).not.toBeInTheDocument();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import { DropdownItem, InputGroup } from 'reactstrap';
|
|
||||||
import { DomainSelector } from '../../src/domains/DomainSelector';
|
import { DomainSelector } from '../../src/domains/DomainSelector';
|
||||||
import { DomainsList } from '../../src/domains/reducers/domainsList';
|
import { DomainsList } from '../../src/domains/reducers/domainsList';
|
||||||
import { ShlinkDomain } from '../../src/api/types';
|
import { ShlinkDomain } from '../../src/api/types';
|
||||||
import { DropdownBtn } from '../../src/utils/DropdownBtn';
|
|
||||||
|
|
||||||
describe('<DomainSelector />', () => {
|
describe('<DomainSelector />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
|
||||||
const domainsList = Mock.of<DomainsList>({
|
const domainsList = Mock.of<DomainsList>({
|
||||||
domains: [
|
domains: [
|
||||||
Mock.of<ShlinkDomain>({ domain: 'default.com', isDefault: true }),
|
Mock.of<ShlinkDomain>({ domain: 'default.com', isDefault: true }),
|
||||||
|
@ -15,51 +12,59 @@ describe('<DomainSelector />', () => {
|
||||||
Mock.of<ShlinkDomain>({ domain: 'bar.com' }),
|
Mock.of<ShlinkDomain>({ domain: 'bar.com' }),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
const createWrapper = (value = '') => {
|
const setUp = (value = '') => render(
|
||||||
wrapper = shallow(
|
<DomainSelector value={value} domainsList={domainsList} listDomains={jest.fn()} onChange={jest.fn()} />,
|
||||||
<DomainSelector value={value} domainsList={domainsList} listDomains={jest.fn()} onChange={jest.fn()} />,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
afterEach(() => wrapper.unmount());
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
['', 'Domain', 'domains-dropdown__toggle-btn'],
|
['', 'Domain', 'domains-dropdown__toggle-btn'],
|
||||||
['my-domain.com', 'Domain: my-domain.com', 'domains-dropdown__toggle-btn--active'],
|
['my-domain.com', 'Domain: my-domain.com', 'domains-dropdown__toggle-btn--active'],
|
||||||
])('shows dropdown by default', (value, expectedText, expectedClassName) => {
|
])('shows dropdown by default', async (value, expectedText, expectedClassName) => {
|
||||||
const wrapper = createWrapper(value);
|
setUp(value);
|
||||||
const input = wrapper.find(InputGroup);
|
|
||||||
const dropdown = wrapper.find(DropdownBtn);
|
|
||||||
|
|
||||||
expect(input).toHaveLength(0);
|
const btn = screen.getByRole('button', { name: expectedText });
|
||||||
expect(dropdown).toHaveLength(1);
|
|
||||||
expect(dropdown.find(DropdownItem)).toHaveLength(5);
|
expect(screen.queryByPlaceholderText('Domain')).not.toBeInTheDocument();
|
||||||
expect(dropdown.prop('text')).toEqual(expectedText);
|
expect(btn).toHaveAttribute(
|
||||||
expect(dropdown.prop('className')).toEqual(expectedClassName);
|
'class',
|
||||||
|
`dropdown-btn__toggle btn-block ${expectedClassName} dropdown-toggle btn btn-primary`,
|
||||||
|
);
|
||||||
|
fireEvent.click(btn);
|
||||||
|
|
||||||
|
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
||||||
|
expect(screen.getAllByRole('menuitem')).toHaveLength(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows toggling between dropdown and input', () => {
|
it('allows toggling between dropdown and input', async () => {
|
||||||
const wrapper = createWrapper();
|
setUp();
|
||||||
|
|
||||||
wrapper.find(DropdownItem).last().simulate('click');
|
expect(screen.queryByPlaceholderText('Domain')).not.toBeInTheDocument();
|
||||||
expect(wrapper.find(InputGroup)).toHaveLength(1);
|
expect(screen.getByRole('button', { name: 'Domain' })).toBeInTheDocument();
|
||||||
expect(wrapper.find(DropdownBtn)).toHaveLength(0);
|
|
||||||
|
|
||||||
wrapper.find('.domains-dropdown__back-btn').simulate('click');
|
fireEvent.click(screen.getByRole('button', { name: 'Domain' }));
|
||||||
expect(wrapper.find(InputGroup)).toHaveLength(0);
|
fireEvent.click(await screen.findByText('New domain'));
|
||||||
expect(wrapper.find(DropdownBtn)).toHaveLength(1);
|
|
||||||
|
expect(screen.getByPlaceholderText('Domain')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByRole('button', { name: 'Domain' })).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Back to domains list' }));
|
||||||
|
|
||||||
|
expect(screen.queryByPlaceholderText('Domain')).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('button', { name: 'Domain' })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[0, 'default.com<span class="float-end text-muted">default</span>'],
|
[0, 'default.comdefault'],
|
||||||
[1, 'foo.com'],
|
[1, 'foo.com'],
|
||||||
[2, 'bar.com'],
|
[2, 'bar.com'],
|
||||||
])('shows expected content on every item', (index, expectedContent) => {
|
])('shows expected content on every item', async (index, expectedContent) => {
|
||||||
const item = createWrapper().find(DropdownItem).at(index);
|
setUp();
|
||||||
|
|
||||||
expect(item.html()).toContain(expectedContent);
|
fireEvent.click(screen.getByRole('button', { name: 'Domain' }));
|
||||||
|
const items = await screen.findAllByRole('menuitem');
|
||||||
|
|
||||||
|
expect(items[index]).toHaveTextContent(expectedContent);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,108 +1,70 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import { DomainsList } from '../../src/domains/reducers/domainsList';
|
import { DomainsList } from '../../src/domains/reducers/domainsList';
|
||||||
import { ManageDomains } from '../../src/domains/ManageDomains';
|
import { ManageDomains } from '../../src/domains/ManageDomains';
|
||||||
import Message from '../../src/utils/Message';
|
|
||||||
import { Result } from '../../src/utils/Result';
|
|
||||||
import SearchField from '../../src/utils/SearchField';
|
|
||||||
import { ProblemDetailsError, ShlinkDomain } from '../../src/api/types';
|
import { ProblemDetailsError, ShlinkDomain } from '../../src/api/types';
|
||||||
import { ShlinkApiError } from '../../src/api/ShlinkApiError';
|
|
||||||
import { DomainRow } from '../../src/domains/DomainRow';
|
|
||||||
import { SelectedServer } from '../../src/servers/data';
|
import { SelectedServer } from '../../src/servers/data';
|
||||||
|
|
||||||
describe('<ManageDomains />', () => {
|
describe('<ManageDomains />', () => {
|
||||||
const listDomains = jest.fn();
|
const listDomains = jest.fn();
|
||||||
const filterDomains = jest.fn();
|
const filterDomains = jest.fn();
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (domainsList: DomainsList) => render(
|
||||||
const createWrapper = (domainsList: DomainsList) => {
|
<ManageDomains
|
||||||
wrapper = shallow(
|
listDomains={listDomains}
|
||||||
<ManageDomains
|
filterDomains={filterDomains}
|
||||||
listDomains={listDomains}
|
editDomainRedirects={jest.fn()}
|
||||||
filterDomains={filterDomains}
|
checkDomainHealth={jest.fn()}
|
||||||
editDomainRedirects={jest.fn()}
|
domainsList={domainsList}
|
||||||
checkDomainHealth={jest.fn()}
|
selectedServer={Mock.all<SelectedServer>()}
|
||||||
domainsList={domainsList}
|
/>,
|
||||||
selectedServer={Mock.all<SelectedServer>()}
|
);
|
||||||
/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it('shows loading message while domains are loading', () => {
|
it('shows loading message while domains are loading', () => {
|
||||||
const wrapper = createWrapper(Mock.of<DomainsList>({ loading: true, filteredDomains: [] }));
|
setUp(Mock.of<DomainsList>({ loading: true, filteredDomains: [] }));
|
||||||
const message = wrapper.find(Message);
|
|
||||||
const searchField = wrapper.find(SearchField);
|
|
||||||
const result = wrapper.find(Result);
|
|
||||||
const apiError = wrapper.find(ShlinkApiError);
|
|
||||||
|
|
||||||
expect(message).toHaveLength(1);
|
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||||
expect(message.prop('loading')).toEqual(true);
|
expect(screen.queryByText('Error loading domains :(')).not.toBeInTheDocument();
|
||||||
expect(searchField).toHaveLength(0);
|
|
||||||
expect(result).toHaveLength(0);
|
|
||||||
expect(apiError).toHaveLength(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows error result when domains loading fails', () => {
|
it.each([
|
||||||
const errorData = Mock.of<ProblemDetailsError>();
|
[undefined, 'Error loading domains :('],
|
||||||
const wrapper = createWrapper(Mock.of<DomainsList>(
|
[Mock.of<ProblemDetailsError>(), 'Error loading domains :('],
|
||||||
{ loading: false, error: true, errorData, filteredDomains: [] },
|
[Mock.of<ProblemDetailsError>({ detail: 'Foo error!!' }), 'Foo error!!'],
|
||||||
));
|
])('shows error result when domains loading fails', (errorData, expectedErrorMessage) => {
|
||||||
const message = wrapper.find(Message);
|
setUp(Mock.of<DomainsList>({ loading: false, error: true, errorData, filteredDomains: [] }));
|
||||||
const searchField = wrapper.find(SearchField);
|
|
||||||
const result = wrapper.find(Result);
|
|
||||||
const apiError = wrapper.find(ShlinkApiError);
|
|
||||||
|
|
||||||
expect(result).toHaveLength(1);
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
||||||
expect(result.prop('type')).toEqual('error');
|
expect(screen.getByText(expectedErrorMessage)).toBeInTheDocument();
|
||||||
expect(apiError).toHaveLength(1);
|
|
||||||
expect(apiError.prop('errorData')).toEqual(errorData);
|
|
||||||
expect(searchField).toHaveLength(1);
|
|
||||||
expect(message).toHaveLength(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('filters domains when SearchField changes', () => {
|
it('filters domains when SearchField changes', async () => {
|
||||||
const wrapper = createWrapper(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains: [] }));
|
setUp(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains: [] }));
|
||||||
const searchField = wrapper.find(SearchField);
|
|
||||||
|
|
||||||
expect(filterDomains).not.toHaveBeenCalled();
|
expect(filterDomains).not.toHaveBeenCalled();
|
||||||
searchField.simulate('change');
|
fireEvent.change(screen.getByPlaceholderText('Search...'), { target: { value: 'Foo' } });
|
||||||
expect(filterDomains).toHaveBeenCalledTimes(1);
|
await waitFor(() => expect(filterDomains).toHaveBeenCalledTimes(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows expected headers', () => {
|
it('shows expected headers and one row when list of domains is empty', () => {
|
||||||
const wrapper = createWrapper(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains: [] }));
|
setUp(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains: [] }));
|
||||||
const headerCells = wrapper.find('th');
|
|
||||||
|
|
||||||
expect(headerCells).toHaveLength(7);
|
expect(screen.getAllByRole('columnheader')).toHaveLength(7);
|
||||||
|
expect(screen.getByText('No results found')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('one row when list of domains is empty', () => {
|
it('has many rows if multiple domains are provided', () => {
|
||||||
const wrapper = createWrapper(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains: [] }));
|
|
||||||
const tableBody = wrapper.find('tbody');
|
|
||||||
const regularRows = tableBody.find('tr');
|
|
||||||
const domainRows = tableBody.find(DomainRow);
|
|
||||||
|
|
||||||
expect(regularRows).toHaveLength(1);
|
|
||||||
expect(regularRows.html()).toContain('No results found');
|
|
||||||
expect(domainRows).toHaveLength(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('as many DomainRows as domains are provided', () => {
|
|
||||||
const filteredDomains = [
|
const filteredDomains = [
|
||||||
Mock.of<ShlinkDomain>({ domain: 'foo' }),
|
Mock.of<ShlinkDomain>({ domain: 'foo' }),
|
||||||
Mock.of<ShlinkDomain>({ domain: 'bar' }),
|
Mock.of<ShlinkDomain>({ domain: 'bar' }),
|
||||||
Mock.of<ShlinkDomain>({ domain: 'baz' }),
|
Mock.of<ShlinkDomain>({ domain: 'baz' }),
|
||||||
];
|
];
|
||||||
const wrapper = createWrapper(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains }));
|
setUp(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains }));
|
||||||
const tableBody = wrapper.find('tbody');
|
|
||||||
const regularRows = tableBody.find('tr');
|
|
||||||
const domainRows = tableBody.find(DomainRow);
|
|
||||||
|
|
||||||
expect(regularRows).toHaveLength(0);
|
expect(screen.getAllByRole('row')).toHaveLength(filteredDomains.length + 1);
|
||||||
expect(domainRows).toHaveLength(filteredDomains.length);
|
expect(screen.getByText('foo')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('bar')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('baz')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,73 +1,30 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { fireEvent, render, screen } from '@testing-library/react';
|
||||||
import { UncontrolledTooltip } from 'reactstrap';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import { faTimes, faCheck, faCircleNotch } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { DomainStatus } from '../../../src/domains/data';
|
import { DomainStatus } from '../../../src/domains/data';
|
||||||
import { DomainStatusIcon } from '../../../src/domains/helpers/DomainStatusIcon';
|
import { DomainStatusIcon } from '../../../src/domains/helpers/DomainStatusIcon';
|
||||||
|
|
||||||
describe('<DomainStatusIcon />', () => {
|
describe('<DomainStatusIcon />', () => {
|
||||||
const matchMedia = jest.fn().mockReturnValue(Mock.of<MediaQueryList>({ matches: false }));
|
const matchMedia = jest.fn().mockReturnValue(Mock.of<MediaQueryList>({ matches: false }));
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (status: DomainStatus) => render(<DomainStatusIcon status={status} matchMedia={matchMedia} />);
|
||||||
const createWrapper = (status: DomainStatus) => {
|
|
||||||
wrapper = shallow(<DomainStatusIcon status={status} matchMedia={matchMedia} />);
|
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(jest.clearAllMocks);
|
beforeEach(jest.clearAllMocks);
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it('renders loading icon when status is "validating"', () => {
|
it.each([
|
||||||
const wrapper = createWrapper('validating');
|
['validating' as DomainStatus],
|
||||||
const tooltip = wrapper.find(UncontrolledTooltip);
|
['invalid' as DomainStatus],
|
||||||
const faIcon = wrapper.find(FontAwesomeIcon);
|
['valid' as DomainStatus],
|
||||||
|
])('renders expected icon and tooltip when status is not validating', (status) => {
|
||||||
expect(tooltip).toHaveLength(0);
|
const { container } = setUp(status);
|
||||||
expect(faIcon).toHaveLength(1);
|
expect(container.firstChild).toMatchSnapshot();
|
||||||
expect(faIcon.prop('icon')).toEqual(faCircleNotch);
|
|
||||||
expect(faIcon.prop('spin')).toEqual(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[
|
['invalid' as DomainStatus],
|
||||||
'invalid' as DomainStatus,
|
['valid' as DomainStatus],
|
||||||
faTimes,
|
])('renders proper tooltip based on state', async (status) => {
|
||||||
'Oops! There is some missing configuration, and short URLs shared with this domain will not work.',
|
const { container } = setUp(status);
|
||||||
],
|
|
||||||
['valid' as DomainStatus, faCheck, 'Congratulations! This domain is properly configured.'],
|
|
||||||
])('renders expected icon and tooltip when status is not validating', (status, expectedIcon, expectedText) => {
|
|
||||||
const wrapper = createWrapper(status);
|
|
||||||
const tooltip = wrapper.find(UncontrolledTooltip);
|
|
||||||
const faIcon = wrapper.find(FontAwesomeIcon);
|
|
||||||
const getTooltipText = (): string => {
|
|
||||||
const children = tooltip.prop('children');
|
|
||||||
|
|
||||||
if (typeof children === 'string') {
|
container.firstChild && fireEvent.mouseOver(container.firstChild);
|
||||||
return children;
|
expect(await screen.findByRole('tooltip')).toMatchSnapshot();
|
||||||
}
|
|
||||||
|
|
||||||
return tooltip.find('span').html();
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(tooltip).toHaveLength(1);
|
|
||||||
expect(tooltip.prop('autohide')).toEqual(status === 'valid');
|
|
||||||
expect(getTooltipText()).toContain(expectedText);
|
|
||||||
expect(faIcon).toHaveLength(1);
|
|
||||||
expect(faIcon.prop('icon')).toEqual(expectedIcon);
|
|
||||||
expect(faIcon.prop('spin')).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
[true, 'top-start'],
|
|
||||||
[false, 'left'],
|
|
||||||
])('places the tooltip properly based on query match', (isMobile, expectedPlacement) => {
|
|
||||||
matchMedia.mockReturnValue(Mock.of<MediaQueryList>({ matches: isMobile }));
|
|
||||||
|
|
||||||
const wrapper = createWrapper('valid');
|
|
||||||
const tooltip = wrapper.find(UncontrolledTooltip);
|
|
||||||
|
|
||||||
expect(tooltip).toHaveLength(1);
|
|
||||||
expect(tooltip.prop('placement')).toEqual(expectedPlacement);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<DomainStatusIcon /> renders expected icon and tooltip when status is not validating 1`] = `
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="svg-inline--fa fa-circle-notch fa-spin fa-fw "
|
||||||
|
data-icon="circle-notch"
|
||||||
|
data-prefix="fas"
|
||||||
|
focusable="false"
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M222.7 32.15C227.7 49.08 218.1 66.9 201.1 71.94C121.8 95.55 64 169.1 64 255.1C64 362 149.1 447.1 256 447.1C362 447.1 448 362 448 255.1C448 169.1 390.2 95.55 310.9 71.94C293.9 66.9 284.3 49.08 289.3 32.15C294.4 15.21 312.2 5.562 329.1 10.6C434.9 42.07 512 139.1 512 255.1C512 397.4 397.4 511.1 256 511.1C114.6 511.1 0 397.4 0 255.1C0 139.1 77.15 42.07 182.9 10.6C199.8 5.562 217.6 15.21 222.7 32.15V32.15z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<DomainStatusIcon /> renders expected icon and tooltip when status is not validating 2`] = `
|
||||||
|
<span>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="svg-inline--fa fa-xmark fa-fw text-danger"
|
||||||
|
data-icon="xmark"
|
||||||
|
data-prefix="fas"
|
||||||
|
focusable="false"
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 320 512"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M310.6 361.4c12.5 12.5 12.5 32.75 0 45.25C304.4 412.9 296.2 416 288 416s-16.38-3.125-22.62-9.375L160 301.3L54.63 406.6C48.38 412.9 40.19 416 32 416S15.63 412.9 9.375 406.6c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<DomainStatusIcon /> renders expected icon and tooltip when status is not validating 3`] = `
|
||||||
|
<span>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="svg-inline--fa fa-check fa-fw text-muted"
|
||||||
|
data-icon="check"
|
||||||
|
data-prefix="fas"
|
||||||
|
focusable="false"
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 448 512"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M438.6 105.4C451.1 117.9 451.1 138.1 438.6 150.6L182.6 406.6C170.1 419.1 149.9 419.1 137.4 406.6L9.372 278.6C-3.124 266.1-3.124 245.9 9.372 233.4C21.87 220.9 42.13 220.9 54.63 233.4L159.1 338.7L393.4 105.4C405.9 92.88 426.1 92.88 438.6 105.4H438.6z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<DomainStatusIcon /> renders proper tooltip based on state 1`] = `
|
||||||
|
<div
|
||||||
|
class="tooltip-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Oops! There is some missing configuration, and short URLs shared with this domain will not work.
|
||||||
|
<br />
|
||||||
|
Check the
|
||||||
|
<a
|
||||||
|
href="https://slnk.to/multi-domain-docs"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
documentation
|
||||||
|
</a>
|
||||||
|
in order to find out what is missing.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<DomainStatusIcon /> renders proper tooltip based on state 2`] = `
|
||||||
|
<div
|
||||||
|
class="tooltip-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
Congratulations! This domain is properly configured.
|
||||||
|
</div>
|
||||||
|
`;
|
|
@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom';
|
||||||
import { TagsTable as createTagsTable } from '../../src/tags/TagsTable';
|
import { TagsTable as createTagsTable } from '../../src/tags/TagsTable';
|
||||||
import { SelectedServer } from '../../src/servers/data';
|
import { SelectedServer } from '../../src/servers/data';
|
||||||
import { rangeOf } from '../../src/utils/utils';
|
import { rangeOf } from '../../src/utils/utils';
|
||||||
import SimplePaginator from '../../src/common/SimplePaginator';
|
import { SimplePaginator } from '../../src/common/SimplePaginator';
|
||||||
import { NormalizedTag } from '../../src/tags/data';
|
import { NormalizedTag } from '../../src/tags/data';
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: jest.fn() }));
|
jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: jest.fn() }));
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { shallow, ShallowWrapper } from 'enzyme';
|
||||||
import { Mock } from 'ts-mockery';
|
import { Mock } from 'ts-mockery';
|
||||||
import VisitsTable, { VisitsTableProps } from '../../src/visits/VisitsTable';
|
import VisitsTable, { VisitsTableProps } from '../../src/visits/VisitsTable';
|
||||||
import { rangeOf } from '../../src/utils/utils';
|
import { rangeOf } from '../../src/utils/utils';
|
||||||
import SimplePaginator from '../../src/common/SimplePaginator';
|
import { SimplePaginator } from '../../src/common/SimplePaginator';
|
||||||
import SearchField from '../../src/utils/SearchField';
|
import SearchField from '../../src/utils/SearchField';
|
||||||
import { NormalizedVisit } from '../../src/visits/types';
|
import { NormalizedVisit } from '../../src/visits/types';
|
||||||
import { ReachableServer, SelectedServer } from '../../src/servers/data';
|
import { ReachableServer, SelectedServer } from '../../src/servers/data';
|
||||||
|
|
|
@ -1,58 +1,20 @@
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { render } from '@testing-library/react';
|
||||||
import { Bar } from 'react-chartjs-2';
|
import { HorizontalBarChart, HorizontalBarChartProps } from '../../../src/visits/charts/HorizontalBarChart';
|
||||||
import { prettify } from '../../../src/utils/helpers/numbers';
|
|
||||||
import { MAIN_COLOR, MAIN_COLOR_ALPHA } from '../../../src/utils/theme';
|
|
||||||
import { HorizontalBarChart } from '../../../src/visits/charts/HorizontalBarChart';
|
|
||||||
|
|
||||||
describe('<HorizontalBarChart />', () => {
|
describe('<HorizontalBarChart />', () => {
|
||||||
let wrapper: ShallowWrapper;
|
const setUp = (props: HorizontalBarChartProps) => {
|
||||||
const stats = {
|
const { container } = render(<HorizontalBarChart {...props} />);
|
||||||
foo: 123,
|
return container.querySelector('canvas')?.getContext('2d')?.__getEvents(); // eslint-disable-line no-underscore-dangle
|
||||||
bar: 456,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
afterEach(() => wrapper?.unmount());
|
|
||||||
|
|
||||||
it('renders Bar with expected properties', () => {
|
|
||||||
wrapper = shallow(<HorizontalBarChart stats={stats} />);
|
|
||||||
const horizontal = wrapper.find(Bar);
|
|
||||||
|
|
||||||
expect(horizontal).toHaveLength(1);
|
|
||||||
|
|
||||||
const { datasets: [{ backgroundColor, borderColor }] } = horizontal.prop('data') as any;
|
|
||||||
const { plugins, scales } = (horizontal.prop('options') ?? {}) as any;
|
|
||||||
|
|
||||||
expect(backgroundColor).toEqual(MAIN_COLOR_ALPHA);
|
|
||||||
expect(borderColor).toEqual(MAIN_COLOR);
|
|
||||||
expect(plugins.legend).toEqual({ display: false });
|
|
||||||
expect(scales).toEqual({
|
|
||||||
x: {
|
|
||||||
beginAtZero: true,
|
|
||||||
stacked: true,
|
|
||||||
ticks: {
|
|
||||||
precision: 0,
|
|
||||||
callback: prettify,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
y: { stacked: true },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[{ foo: 23 }, [100, 456], [23, 0]],
|
[{ foo: 123, bar: 456 }, undefined],
|
||||||
[{ foo: 50 }, [73, 456], [50, 0]],
|
[{ one: 999, two: 131313 }, { one: 30, two: 100 }],
|
||||||
[{ bar: 45 }, [123, 411], [0, 45]],
|
[{ one: 999, two: 131313, max: 3 }, { one: 30, two: 100 }],
|
||||||
[{ bar: 20, foo: 13 }, [110, 436], [13, 20]],
|
])('renders chart with expected canvas', (stats, highlightedStats) => {
|
||||||
[undefined, [123, 456], undefined],
|
const events = setUp({ stats, highlightedStats });
|
||||||
])('splits highlighted data from regular data', (highlightedStats, expectedData, expectedHighlightedData) => {
|
|
||||||
wrapper = shallow(<HorizontalBarChart stats={stats} highlightedStats={highlightedStats} />);
|
|
||||||
const horizontal = wrapper.find(Bar);
|
|
||||||
|
|
||||||
const { datasets: [{ data, label }, highlightedData] } = horizontal.prop('data') as any;
|
expect(events).toBeTruthy();
|
||||||
|
expect(events).toMatchSnapshot();
|
||||||
expect(label).toEqual('Visits');
|
|
||||||
expect(data).toEqual(expectedData);
|
|
||||||
expectedHighlightedData && expect(highlightedData.data).toEqual(expectedHighlightedData);
|
|
||||||
!expectedHighlightedData && expect(highlightedData).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,521 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<HorizontalBarChart /> renders chart with expected canvas 1`] = `
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"a": 1,
|
||||||
|
"b": 0,
|
||||||
|
"c": 0,
|
||||||
|
"d": 1,
|
||||||
|
"e": 0,
|
||||||
|
"f": 0,
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "setTransform",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "foo",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "bar",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "0",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "500",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<HorizontalBarChart /> renders chart with expected canvas 2`] = `
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"a": 1,
|
||||||
|
"b": 0,
|
||||||
|
"c": 0,
|
||||||
|
"d": 1,
|
||||||
|
"e": 0,
|
||||||
|
"f": 0,
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "setTransform",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "one",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "two",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "0",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "200,000",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<HorizontalBarChart /> renders chart with expected canvas 3`] = `
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"a": 1,
|
||||||
|
"b": 0,
|
||||||
|
"c": 0,
|
||||||
|
"d": 1,
|
||||||
|
"e": 0,
|
||||||
|
"f": 0,
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "setTransform",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "one",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "two",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "max",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "0",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"text": "200,000",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "measureText",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"props": Object {
|
||||||
|
"value": "12px \\"Helvetica Neue\\", 'Helvetica', 'Arial', sans-serif",
|
||||||
|
},
|
||||||
|
"transform": Array [
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
],
|
||||||
|
"type": "font",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`;
|
Loading…
Reference in a new issue