Merge pull request #659 from acelaya-forks/feature/moar-rtl

Feature/moar rtl
This commit is contained in:
Alejandro Celaya 2022-06-04 10:25:17 +02:00 committed by GitHub
commit 807c5c3fb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 287 additions and 222 deletions

View file

@ -26,7 +26,7 @@ export const DeleteServerModal: FC<DeleteServerModalConnectProps> = (
return (
<Modal isOpen={isOpen} toggle={toggle} centered>
<ModalHeader toggle={toggle}><span className="text-danger">Remove server</span></ModalHeader>
<ModalHeader toggle={toggle} className="text-danger">Remove server</ModalHeader>
<ModalBody>
<p>Are you sure you want to remove <b>{server ? server.name : ''}</b>?</p>
<p>

View file

@ -39,7 +39,7 @@ export const ManageServersRowDropdown = (
<DropdownItem tag={Link} to={`${serverUrl}/edit`}>
<FontAwesomeIcon icon={editIcon} fixedWidth /> Edit server
</DropdownItem>
<DropdownItem onClick={() => setAutoConnect(server, !server.autoConnect)}>
<DropdownItem onClick={() => setAutoConnect(server, !isAutoConnect)}>
<FontAwesomeIcon icon={autoConnectIcon} fixedWidth /> {isAutoConnect ? 'Do not a' : 'A'}uto-connect
</DropdownItem>
<DropdownItem divider />

View file

@ -1,13 +1,13 @@
import { parseISO, format as formatDate, getUnixTime, formatDistance } from 'date-fns';
import { isDateObject } from './helpers/date';
export interface DateProps {
export interface TimeProps {
date: Date | string;
format?: string;
relative?: boolean;
}
export const Time = ({ date, format = 'yyyy-MM-dd HH:mm', relative = false }: DateProps) => {
export const Time = ({ date, format = 'yyyy-MM-dd HH:mm', relative = false }: TimeProps) => {
const dateObject = isDateObject(date) ? date : parseISO(date);
return (

View file

@ -1,5 +1,5 @@
import { shallow, ShallowWrapper } from 'enzyme';
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Mock } from 'ts-mockery';
import { useNavigate } from 'react-router-dom';
import { DeleteServerModal } from '../../src/servers/DeleteServerModal';
@ -8,56 +8,63 @@ import { ServerWithId } from '../../src/servers/data';
jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: jest.fn() }));
describe('<DeleteServerModal />', () => {
let wrapper: ShallowWrapper;
const deleteServerMock = jest.fn();
const navigate = jest.fn();
const toggleMock = jest.fn();
const serverName = 'the_server_name';
beforeEach(() => {
const setUp = () => {
(useNavigate as any).mockReturnValue(navigate);
wrapper = shallow(
<DeleteServerModal
server={Mock.of<ServerWithId>({ name: serverName })}
toggle={toggleMock}
isOpen
deleteServer={deleteServerMock}
/>,
);
});
afterEach(() => wrapper.unmount());
return {
user: userEvent.setup(),
...render(
<DeleteServerModal
server={Mock.of<ServerWithId>({ name: serverName })}
toggle={toggleMock}
isOpen
deleteServer={deleteServerMock}
/>,
),
};
};
afterEach(jest.clearAllMocks);
it('renders a modal window', () => {
expect(wrapper.find(Modal)).toHaveLength(1);
expect(wrapper.find(ModalHeader)).toHaveLength(1);
expect(wrapper.find(ModalBody)).toHaveLength(1);
expect(wrapper.find(ModalFooter)).toHaveLength(1);
setUp();
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByRole('heading')).toHaveTextContent('Remove server');
});
it('displays the name of the server as part of the content', () => {
const modalBody = wrapper.find(ModalBody);
setUp();
expect(modalBody.find('p').first().text()).toEqual(
`Are you sure you want to remove ${serverName}?`,
);
expect(screen.getByText(/^Are you sure you want to remove/)).toBeInTheDocument();
expect(screen.getByText(serverName)).toBeInTheDocument();
});
it('toggles when clicking cancel button', () => {
const cancelBtn = wrapper.find(Button).first();
it.each([
[() => screen.getByRole('button', { name: 'Cancel' })],
[() => screen.getByLabelText('Close')],
])('toggles when clicking cancel button', async (getButton) => {
const { user } = setUp();
cancelBtn.simulate('click');
expect(toggleMock).not.toHaveBeenCalled();
await user.click(getButton());
expect(toggleMock).toHaveBeenCalledTimes(1);
expect(deleteServerMock).not.toHaveBeenCalled();
expect(navigate).not.toHaveBeenCalled();
});
it('deletes server when clicking accept button', () => {
const acceptBtn = wrapper.find(Button).last();
it('deletes server when clicking accept button', async () => {
const { user } = setUp();
acceptBtn.simulate('click');
expect(toggleMock).not.toHaveBeenCalled();
expect(deleteServerMock).not.toHaveBeenCalled();
expect(navigate).not.toHaveBeenCalled();
await user.click(screen.getByRole('button', { name: 'Delete' }));
expect(toggleMock).toHaveBeenCalledTimes(1);
expect(deleteServerMock).toHaveBeenCalledTimes(1);

View file

@ -1,93 +1,103 @@
import { Mock } from 'ts-mockery';
import { shallow, ShallowWrapper } from 'enzyme';
import { Button } from 'reactstrap';
import userEvent from '@testing-library/user-event';
import { render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import ServersExporter from '../../src/servers/services/ServersExporter';
import { ManageServers as createManageServers } from '../../src/servers/ManageServers';
import { ServersMap, ServerWithId } from '../../src/servers/data';
import { SearchField } from '../../src/utils/SearchField';
import { Result } from '../../src/utils/Result';
describe('<ManageServers />', () => {
const exportServers = jest.fn();
const serversExporter = Mock.of<ServersExporter>({ exportServers });
const ImportServersBtn = () => null;
const ManageServersRow = () => null;
const useTimeoutToggle = jest.fn().mockReturnValue([false, jest.fn()]);
const ManageServers = createManageServers(serversExporter, ImportServersBtn, useTimeoutToggle, ManageServersRow);
let wrapper: ShallowWrapper;
const ManageServers = createManageServers(
serversExporter,
() => <span>ImportServersBtn</span>,
useTimeoutToggle,
({ hasAutoConnect }) => <span>ManageServersRow {hasAutoConnect ? '[YES]' : '[NO]'}</span>,
);
const createServerMock = (value: string, autoConnect = false) => Mock.of<ServerWithId>(
{ id: value, name: value, url: value, autoConnect },
);
const createWrapper = (servers: ServersMap = {}) => {
wrapper = shallow(<ManageServers servers={servers} />);
return wrapper;
};
const setUp = (servers: ServersMap = {}) => ({
user: userEvent.setup(),
...render(<MemoryRouter><ManageServers servers={servers} /></MemoryRouter>),
});
afterEach(jest.clearAllMocks);
afterEach(() => wrapper?.unmount());
it('shows search field which allows searching servers, affecting te amount of rendered rows', () => {
const wrapper = createWrapper({
it('shows search field which allows searching servers, affecting te amount of rendered rows', async () => {
const { user } = setUp({
foo: createServerMock('foo'),
bar: createServerMock('bar'),
baz: createServerMock('baz'),
});
const searchField = wrapper.find(SearchField);
const search = async (searchTerm: string) => {
await user.clear(screen.getByPlaceholderText('Search...'));
await user.type(screen.getByPlaceholderText('Search...'), searchTerm);
};
expect(wrapper.find(ManageServersRow)).toHaveLength(3);
expect(wrapper.find('tbody').find('tr')).toHaveLength(0);
expect(screen.getAllByText(/^ManageServersRow/)).toHaveLength(3);
expect(screen.queryByText('No servers found.')).not.toBeInTheDocument();
searchField.simulate('change', 'foo');
expect(wrapper.find(ManageServersRow)).toHaveLength(1);
expect(wrapper.find('tbody').find('tr')).toHaveLength(0);
await search('foo');
await waitFor(() => expect(screen.getAllByText(/^ManageServersRow/)).toHaveLength(1));
expect(screen.queryByText('No servers found.')).not.toBeInTheDocument();
searchField.simulate('change', 'ba');
expect(wrapper.find(ManageServersRow)).toHaveLength(2);
expect(wrapper.find('tbody').find('tr')).toHaveLength(0);
await search('ba');
await waitFor(() => expect(screen.getAllByText(/^ManageServersRow/)).toHaveLength(2));
expect(screen.queryByText('No servers found.')).not.toBeInTheDocument();
searchField.simulate('change', 'invalid');
expect(wrapper.find(ManageServersRow)).toHaveLength(0);
expect(wrapper.find('tbody').find('tr')).toHaveLength(1);
await search('invalid');
await waitFor(() => expect(screen.queryByText(/^ManageServersRow/)).not.toBeInTheDocument());
expect(screen.getByText('No servers found.')).toBeInTheDocument();
});
it.each([
[createServerMock('foo'), 3],
[createServerMock('foo', true), 4],
])('shows different amount of columns if there are at least one auto-connect server', (server, expectedCols) => {
const wrapper = createWrapper({ server });
const row = wrapper.find(ManageServersRow);
setUp({ server });
expect(wrapper.find('th')).toHaveLength(expectedCols);
expect(row.prop('hasAutoConnect')).toEqual(server.autoConnect);
expect(screen.getAllByRole('columnheader')).toHaveLength(expectedCols);
if (server.autoConnect) {
expect(screen.getByText(/\[YES\]/)).toBeInTheDocument();
expect(screen.queryByText(/\[NO\]/)).not.toBeInTheDocument();
} else {
expect(screen.queryByText(/\[YES\]/)).not.toBeInTheDocument();
expect(screen.getByText(/\[NO\]/)).toBeInTheDocument();
}
});
it.each([
[{}, 1],
[{ foo: createServerMock('foo') }, 2],
[{}, 0],
[{ foo: createServerMock('foo') }, 1],
])('shows export button if the list of servers is not empty', (servers, expectedButtons) => {
const wrapper = createWrapper(servers);
const exportBtn = wrapper.find(Button);
expect(exportBtn).toHaveLength(expectedButtons);
setUp(servers);
expect(screen.queryAllByRole('button', { name: 'Export servers' })).toHaveLength(expectedButtons);
});
it('allows exporting servers when clicking on button', () => {
const wrapper = createWrapper({ foo: createServerMock('foo') });
const exportBtn = wrapper.find(Button).first();
it('allows exporting servers when clicking on button', async () => {
const { user } = setUp({ foo: createServerMock('foo') });
expect(exportServers).not.toHaveBeenCalled();
exportBtn.simulate('click');
await user.click(screen.getByRole('button', { name: 'Export servers' }));
expect(exportServers).toHaveBeenCalled();
});
it('shows an error message if an error occurs while importing servers', () => {
useTimeoutToggle.mockReturnValue([true, jest.fn()]);
it.each([[true], [false]])('shows an error message if an error occurs while importing servers', (hasError) => {
useTimeoutToggle.mockReturnValue([hasError, jest.fn()]);
const wrapper = createWrapper({ foo: createServerMock('foo') });
const result = wrapper.find(Result);
setUp({ foo: createServerMock('foo') });
expect(result).toHaveLength(1);
expect(result.prop('type')).toEqual('error');
if (hasError) {
expect(
screen.getByText('The servers could not be imported. Make sure the format is correct.'),
).toBeInTheDocument();
} else {
expect(
screen.queryByText('The servers could not be imported. Make sure the format is correct.'),
).not.toBeInTheDocument();
}
});
});

View file

@ -1,66 +1,58 @@
import { shallow, ShallowWrapper } from 'enzyme';
import { UncontrolledTooltip } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Link } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { ManageServersRow as createManageServersRow } from '../../src/servers/ManageServersRow';
import { ServerWithId } from '../../src/servers/data';
describe('<ManageServersRow />', () => {
const ManageServersRowDropdown = () => null;
const ManageServersRow = createManageServersRow(ManageServersRowDropdown);
const ManageServersRow = createManageServersRow(() => <span>ManageServersRowDropdown</span>);
const server: ServerWithId = {
name: 'My server',
url: 'https://example.com',
apiKey: '123',
id: 'abc',
};
let wrapper: ShallowWrapper;
const createWrapper = (hasAutoConnect = false, autoConnect = false) => {
wrapper = shallow(<ManageServersRow server={{ ...server, autoConnect }} hasAutoConnect={hasAutoConnect} />);
return wrapper;
};
afterEach(() => wrapper?.unmount());
const setUp = (hasAutoConnect = false, autoConnect = false) => render(
<MemoryRouter>
<table>
<tbody>
<ManageServersRow server={{ ...server, autoConnect }} hasAutoConnect={hasAutoConnect} />
</tbody>
</table>
</MemoryRouter>,
);
it.each([
[true, 4],
[false, 3],
])('renders expected amount of columns', (hasAutoConnect, expectedCols) => {
const wrapper = createWrapper(hasAutoConnect);
const td = wrapper.find('td');
const th = wrapper.find('th');
setUp(hasAutoConnect);
const td = screen.getAllByRole('cell');
const th = screen.getAllByRole('columnheader');
expect(td.length + th.length).toEqual(expectedCols);
});
it('renders a dropdown', () => {
const wrapper = createWrapper();
const dropdown = wrapper.find(ManageServersRowDropdown);
expect(dropdown).toHaveLength(1);
expect(dropdown.prop('server')).toEqual(expect.objectContaining(server));
setUp();
expect(screen.getByText('ManageServersRowDropdown')).toBeInTheDocument();
});
it.each([
[true, 1],
[false, 0],
])('renders auto-connect icon only if server is autoConnect', (autoConnect, expectedIcons) => {
const wrapper = createWrapper(true, autoConnect);
const icon = wrapper.find(FontAwesomeIcon);
const iconTooltip = wrapper.find(UncontrolledTooltip);
expect(icon).toHaveLength(expectedIcons);
expect(iconTooltip).toHaveLength(expectedIcons);
[true],
[false],
])('renders auto-connect icon only if server is autoConnect', (autoConnect) => {
const { container } = setUp(true, autoConnect);
expect(container).toMatchSnapshot();
});
it('renders server props where appropriate', () => {
const wrapper = createWrapper();
const link = wrapper.find(Link);
const td = wrapper.find('td').first();
setUp();
expect(link.prop('to')).toEqual(`/server/${server.id}`);
expect(link.prop('children')).toEqual(server.name);
expect(td.prop('children')).toEqual(server.url);
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', `/server/${server.id}`);
expect(link).toHaveTextContent(server.name);
expect(screen.getByText(server.url)).toBeInTheDocument();
});
});

View file

@ -1,84 +1,60 @@
import { shallow, ShallowWrapper } from 'enzyme';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';
import { Mock } from 'ts-mockery';
import { DropdownItem } from 'reactstrap';
import { MemoryRouter } from 'react-router-dom';
import { ServerWithId } from '../../src/servers/data';
import { ManageServersRowDropdown as createManageServersRowDropdown } from '../../src/servers/ManageServersRowDropdown';
describe('<ManageServersRowDropdown />', () => {
const DeleteServerModal = () => null;
const ManageServersRowDropdown = createManageServersRowDropdown(DeleteServerModal);
const ManageServersRowDropdown = createManageServersRowDropdown(
({ isOpen }) => <span>DeleteServerModal {isOpen ? '[OPEN]' : '[CLOSED]'}</span>,
);
const setAutoConnect = jest.fn();
let wrapper: ShallowWrapper;
const createWrapper = (autoConnect = false) => {
const setUp = (autoConnect = false) => {
const server = Mock.of<ServerWithId>({ id: 'abc123', autoConnect });
wrapper = shallow(<ManageServersRowDropdown setAutoConnect={setAutoConnect} server={server} />);
return wrapper;
return {
user: userEvent.setup(),
...render(
<MemoryRouter>
<ManageServersRowDropdown setAutoConnect={setAutoConnect} server={server} />
</MemoryRouter>,
),
};
};
afterEach(jest.clearAllMocks);
it('renders expected amount of dropdown items', () => {
const wrapper = createWrapper();
const items = wrapper.find(DropdownItem);
it('renders expected amount of dropdown items', async () => {
const { user } = setUp();
expect(items).toHaveLength(5);
expect(items.find('[divider]')).toHaveLength(1);
expect(items.at(0).prop('to')).toEqual('/server/abc123');
expect(items.at(1).prop('to')).toEqual('/server/abc123/edit');
expect(screen.queryByRole('menu')).not.toBeInTheDocument();
await user.click(screen.getByRole('button'));
expect(screen.getByRole('menu')).toBeInTheDocument();
expect(screen.getAllByRole('menuitem')).toHaveLength(4);
expect(screen.getByRole('menuitem', { name: 'Connect' })).toHaveAttribute('href', '/server/abc123');
expect(screen.getByRole('menuitem', { name: 'Edit server' })).toHaveAttribute('href', '/server/abc123/edit');
});
it('allows toggling auto-connect', () => {
const wrapper = createWrapper();
it('allows toggling auto-connect', async () => {
const { user } = setUp();
expect(setAutoConnect).not.toHaveBeenCalled();
wrapper.find(DropdownItem).at(2).simulate('click');
await user.click(screen.getByRole('button'));
await user.click(screen.getByRole('menuitem', { name: 'Auto-connect' }));
expect(setAutoConnect).toHaveBeenCalledWith(expect.objectContaining({ id: 'abc123' }), true);
});
it('renders a modal', () => {
const wrapper = createWrapper();
const modal = wrapper.find(DeleteServerModal);
it('renders deletion modal', async () => {
const { user } = setUp();
expect(modal).toHaveLength(1);
expect(modal.prop('redirectHome')).toEqual(false);
expect(modal.prop('server')).toEqual(expect.objectContaining({ id: 'abc123' }));
expect(modal.prop('isOpen')).toEqual(false);
});
expect(screen.queryByText('DeleteServerModal [OPEN]')).not.toBeInTheDocument();
expect(screen.getByText('DeleteServerModal [CLOSED]')).toBeInTheDocument();
it('allows toggling the modal', () => {
const wrapper = createWrapper();
const modalToggle = wrapper.find(DropdownItem).last();
await user.click(screen.getByRole('button'));
await user.click(screen.getByRole('menuitem', { name: 'Remove server' }));
expect(wrapper.find(DeleteServerModal).prop('isOpen')).toEqual(false);
modalToggle.simulate('click');
expect(wrapper.find(DeleteServerModal).prop('isOpen')).toEqual(true);
(wrapper.find(DeleteServerModal).prop('toggle') as Function)();
expect(wrapper.find(DeleteServerModal).prop('isOpen')).toEqual(false);
});
it('can be toggled', () => {
const wrapper = createWrapper();
expect(wrapper.prop('isOpen')).toEqual(false);
(wrapper.prop('toggle') as Function)();
expect(wrapper.prop('isOpen')).toEqual(true);
(wrapper.prop('toggle') as Function)();
expect(wrapper.prop('isOpen')).toEqual(false);
});
it.each([
[true, 'Do not auto-connect'],
[false, 'Auto-connect'],
])('shows different auto-connect toggle text depending on current server status', (autoConnect, expectedText) => {
const wrapper = createWrapper(autoConnect);
const item = wrapper.find(DropdownItem).at(2);
expect(item.html()).toContain(expectedText);
expect(screen.getByText('DeleteServerModal [OPEN]')).toBeInTheDocument();
expect(screen.queryByText('DeleteServerModal [CLOSED]')).not.toBeInTheDocument();
});
});

View file

@ -1,6 +1,6 @@
import { shallow, ShallowWrapper } from 'enzyme';
import { ListGroup } from 'reactstrap';
import { render, screen } from '@testing-library/react';
import { Mock } from 'ts-mockery';
import { MemoryRouter } from 'react-router-dom';
import { ServersListGroup } from '../../src/servers/ServersListGroup';
import { ServerWithId } from '../../src/servers/data';
@ -9,44 +9,36 @@ describe('<ServersListGroup />', () => {
Mock.of<ServerWithId>({ name: 'foo', id: '123' }),
Mock.of<ServerWithId>({ name: 'bar', id: '456' }),
];
let wrapped: ShallowWrapper;
const createComponent = (params: { servers?: ServerWithId[]; withChildren?: boolean; embedded?: boolean }) => {
const setUp = (params: { servers?: ServerWithId[]; withChildren?: boolean; embedded?: boolean }) => {
const { servers = [], withChildren = true, embedded } = params;
wrapped = shallow(
<ServersListGroup servers={servers} embedded={embedded}>
{withChildren ? 'The list of servers' : undefined}
</ServersListGroup>,
return render(
<MemoryRouter>
<ServersListGroup servers={servers} embedded={embedded}>
{withChildren ? 'The list of servers' : undefined}
</ServersListGroup>
</MemoryRouter>,
);
return wrapped;
};
afterEach(() => wrapped?.unmount());
it('renders title', () => {
const wrapped = createComponent({});
const title = wrapped.find('h5');
expect(title).toHaveLength(1);
expect(title.text()).toEqual('The list of servers');
setUp({});
expect(screen.getByRole('heading')).toHaveTextContent('The list of servers');
});
it('does not render title when children is not provided', () => {
const wrapped = createComponent({ withChildren: false });
const title = wrapped.find('h5');
expect(title).toHaveLength(0);
setUp({ withChildren: false });
expect(screen.queryByRole('heading')).not.toBeInTheDocument();
});
it.each([
[servers],
[[]],
])('shows servers list', (servers) => {
const wrapped = createComponent({ servers });
setUp({ servers });
expect(wrapped.find(ListGroup)).toHaveLength(servers.length ? 1 : 0);
expect(wrapped.find('ServerListItem')).toHaveLength(servers.length);
expect(screen.queryAllByRole('list')).toHaveLength(servers.length ? 1 : 0);
expect(screen.queryAllByRole('link')).toHaveLength(servers.length);
});
it.each([
@ -54,9 +46,7 @@ describe('<ServersListGroup />', () => {
[false, 'servers-list__list-group'],
[undefined, 'servers-list__list-group'],
])('renders proper classes for embedded', (embedded, expectedClasses) => {
const wrapped = createComponent({ servers, embedded });
const listGroup = wrapped.find(ListGroup);
expect(listGroup.prop('className')).toEqual(expectedClasses);
setUp({ servers, embedded });
expect(screen.getByRole('list')).toHaveAttribute('class', `${expectedClasses} list-group`);
});
});

View file

@ -0,0 +1,98 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<ManageServersRow /> renders auto-connect icon only if server is autoConnect 1`] = `
<div>
<table>
<tbody>
<tr
class="responsive-table__row"
>
<td
class="responsive-table__cell"
data-th="Auto-connect"
>
<svg
aria-hidden="true"
class="svg-inline--fa fa-check text-primary"
data-icon="check"
data-prefix="fas"
focusable="false"
id="autoConnectIcon"
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>
</td>
<th
class="responsive-table__cell"
data-th="Name"
>
<a
href="/server/abc"
>
My server
</a>
</th>
<td
class="responsive-table__cell"
data-th="Base URL"
>
https://example.com
</td>
<td
class="responsive-table__cell text-end"
>
<span>
ManageServersRowDropdown
</span>
</td>
</tr>
</tbody>
</table>
</div>
`;
exports[`<ManageServersRow /> renders auto-connect icon only if server is autoConnect 2`] = `
<div>
<table>
<tbody>
<tr
class="responsive-table__row"
>
<td
class="responsive-table__cell"
data-th="Auto-connect"
/>
<th
class="responsive-table__cell"
data-th="Name"
>
<a
href="/server/abc"
>
My server
</a>
</th>
<td
class="responsive-table__cell"
data-th="Base URL"
>
https://example.com
</td>
<td
class="responsive-table__cell text-end"
>
<span>
ManageServersRowDropdown
</span>
</td>
</tr>
</tbody>
</table>
</div>
`;

View file

@ -1,30 +1,22 @@
import { shallow, ShallowWrapper } from 'enzyme';
import { DateProps, Time } from '../../src/utils/Time';
import { render } from '@testing-library/react';
import { TimeProps, Time } from '../../src/utils/Time';
import { parseDate } from '../../src/utils/helpers/date';
describe('<Time />', () => {
let wrapper: ShallowWrapper;
const createWrapper = (props: DateProps) => {
wrapper = shallow(<Time {...props} />);
return wrapper;
};
afterEach(() => wrapper?.unmount());
const setUp = (props: TimeProps) => render(<Time {...props} />);
it.each([
[{ date: parseDate('2020-05-05', 'yyyy-MM-dd') }, '1588636800000', '2020-05-05 00:00'],
[{ date: parseDate('2021-03-20', 'yyyy-MM-dd'), format: 'dd/MM/yyyy' }, '1616198400000', '20/03/2021'],
])('includes expected dateTime and format', (props, expectedDateTime, expectedFormatted) => {
const wrapper = createWrapper(props);
const { container } = setUp(props);
expect(wrapper.prop('dateTime')).toEqual(expectedDateTime);
expect(wrapper.prop('children')).toEqual(expectedFormatted);
expect(container.firstChild).toHaveAttribute('datetime', expectedDateTime);
expect(container.firstChild).toHaveTextContent(expectedFormatted);
});
it('renders relative times when requested', () => {
const wrapper = createWrapper({ date: new Date(), relative: true });
expect(wrapper.prop('children')).toContain(' ago');
const { container } = setUp({ date: new Date(), relative: true });
expect(container.firstChild).toHaveTextContent(' ago');
});
});