mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-10-17 03:04:08 +00:00
Migrate from ESLint to Oxlint and Oxfmt
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
import type { FC, ReactElement } from 'react';
|
||||
import { useCallback, useEffect , useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
export type RenderModalArgs = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export const TestModalWrapper: FC<{ renderModal: (args: RenderModalArgs) => ReactElement }> = (
|
||||
{ renderModal },
|
||||
) => {
|
||||
export const TestModalWrapper: FC<{ renderModal: (args: RenderModalArgs) => ReactElement }> = ({ renderModal }) => {
|
||||
const [open, setOpen] = useState(true);
|
||||
const onClose = useCallback(() => setOpen(false), []);
|
||||
|
||||
|
||||
@@ -44,12 +44,15 @@ describe('ShlinkApiClientBuilder', () => {
|
||||
|
||||
await apiClient.health();
|
||||
|
||||
expect(jsonRequest).toHaveBeenCalledWith(expect.stringMatching(new RegExp(`^${url}`)), expect.objectContaining({
|
||||
credentials: undefined,
|
||||
headers: {
|
||||
'X-Api-Key': apiKey,
|
||||
},
|
||||
}));
|
||||
expect(jsonRequest).toHaveBeenCalledWith(
|
||||
expect.stringMatching(new RegExp(`^${url}`)),
|
||||
expect.objectContaining({
|
||||
credentials: undefined,
|
||||
headers: {
|
||||
'X-Api-Key': apiKey,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('includes credentials when forwarding is enabled', async () => {
|
||||
@@ -61,11 +64,14 @@ describe('ShlinkApiClientBuilder', () => {
|
||||
|
||||
await apiClient.health();
|
||||
|
||||
expect(jsonRequest).toHaveBeenCalledWith(expect.stringMatching(new RegExp(`^${url}`)), expect.objectContaining({
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'X-Api-Key': apiKey,
|
||||
},
|
||||
}));
|
||||
expect(jsonRequest).toHaveBeenCalledWith(
|
||||
expect.stringMatching(new RegExp(`^${url}`)),
|
||||
expect.objectContaining({
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'X-Api-Key': apiKey,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,29 +13,32 @@ vi.mock(import('../../src/common/ShlinkWebComponentContainer'), () => ({
|
||||
}));
|
||||
|
||||
describe('<App />', () => {
|
||||
const setUp = async (activeRoute = '/') => act(() => renderWithStore(
|
||||
<MemoryRouter initialEntries={[{ pathname: activeRoute }]}>
|
||||
<ContainerProvider
|
||||
value={fromPartial({
|
||||
HttpClient: fromPartial<HttpClient>({}),
|
||||
buildShlinkApiClient: vi.fn(),
|
||||
useTimeoutToggle: vi.fn().mockReturnValue([false, vi.fn()]),
|
||||
})}
|
||||
>
|
||||
<App />
|
||||
</ContainerProvider>
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: {
|
||||
servers: {
|
||||
abc123: fromPartial<ServerWithId>({ id: 'abc123', name: 'abc123 server' }),
|
||||
def456: fromPartial<ServerWithId>({ id: 'def456', name: 'def456 server' }),
|
||||
const setUp = async (activeRoute = '/') =>
|
||||
act(() =>
|
||||
renderWithStore(
|
||||
<MemoryRouter initialEntries={[{ pathname: activeRoute }]}>
|
||||
<ContainerProvider
|
||||
value={fromPartial({
|
||||
HttpClient: fromPartial<HttpClient>({}),
|
||||
buildShlinkApiClient: vi.fn(),
|
||||
useTimeoutToggle: vi.fn().mockReturnValue([false, vi.fn()]),
|
||||
})}
|
||||
>
|
||||
<App />
|
||||
</ContainerProvider>
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: {
|
||||
servers: {
|
||||
abc123: fromPartial<ServerWithId>({ id: 'abc123', name: 'abc123 server' }),
|
||||
def456: fromPartial<ServerWithId>({ id: 'def456', name: 'def456 server' }),
|
||||
},
|
||||
settings: fromPartial({}),
|
||||
appUpdated: false,
|
||||
},
|
||||
},
|
||||
settings: fromPartial({}),
|
||||
appUpdated: false,
|
||||
},
|
||||
},
|
||||
));
|
||||
),
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ describe('<AppUpdateBanner />', () => {
|
||||
const onClose = vi.fn();
|
||||
const forceUpdate = vi.fn();
|
||||
const setUp = async () => {
|
||||
const result = await act(
|
||||
() => renderWithEvents(<AppUpdateBanner isOpen onClose={onClose} forceUpdate={forceUpdate} />),
|
||||
const result = await act(() =>
|
||||
renderWithEvents(<AppUpdateBanner isOpen onClose={onClose} forceUpdate={forceUpdate} />),
|
||||
);
|
||||
await waitFor(() => screen.getByRole('alert'));
|
||||
|
||||
|
||||
@@ -7,18 +7,18 @@ import { checkAccessibility } from '../__helpers__/accessibility';
|
||||
import { renderWithStore } from '../__helpers__/setUpTest';
|
||||
|
||||
describe('<Home />', () => {
|
||||
const setUp = (servers: ServersMap = {}) => renderWithStore(
|
||||
<MemoryRouter>
|
||||
<Home />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { servers },
|
||||
},
|
||||
);
|
||||
const setUp = (servers: ServersMap = {}) =>
|
||||
renderWithStore(
|
||||
<MemoryRouter>
|
||||
<Home />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { servers },
|
||||
},
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(
|
||||
setUp({ '1a': fromPartial<ServerWithId>({ name: 'foo', id: '1' }) }),
|
||||
));
|
||||
it('passes a11y checks', () =>
|
||||
checkAccessibility(setUp({ '1a': fromPartial<ServerWithId>({ name: 'foo', id: '1' }) })));
|
||||
|
||||
it('renders title', () => {
|
||||
setUp();
|
||||
|
||||
@@ -33,7 +33,8 @@ describe('<MainHeader />', () => {
|
||||
])('sets link to settings as active only when current path is settings', (currentPath, isActive) => {
|
||||
setUp(currentPath);
|
||||
expect(screen.getByRole('menuitem', { name: /Settings$/ })).toHaveAttribute(
|
||||
'data-active', isActive ? 'true' : 'false',
|
||||
'data-active',
|
||||
isActive ? 'true' : 'false',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,12 @@ import { NotFound } from '../../src/common/NotFound';
|
||||
import { checkAccessibility } from '../__helpers__/accessibility';
|
||||
|
||||
describe('<NotFound />', () => {
|
||||
const setUp = (props = {}) => render(<MemoryRouter><NotFound {...props} /></MemoryRouter>);
|
||||
const setUp = (props = {}) =>
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<NotFound {...props} />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
|
||||
@@ -15,9 +20,11 @@ describe('<NotFound />', () => {
|
||||
|
||||
it('shows expected error message', () => {
|
||||
setUp();
|
||||
expect(screen.getByText(
|
||||
'Use your browser\'s back button to navigate to the page you have previously come from, or just press this button.',
|
||||
)).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
"Use your browser's back button to navigate to the page you have previously come from, or just press this button.",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.each([
|
||||
|
||||
@@ -4,15 +4,16 @@ import { ScrollToTop } from '../../src/common/ScrollToTop';
|
||||
import { checkAccessibility } from '../__helpers__/accessibility';
|
||||
|
||||
describe('<ScrollToTop />', () => {
|
||||
const setUp = (children = 'Foo') => render(<MemoryRouter><ScrollToTop>{children}</ScrollToTop></MemoryRouter>);
|
||||
const setUp = (children = 'Foo') =>
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<ScrollToTop>{children}</ScrollToTop>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
|
||||
it.each([
|
||||
['Foobar'],
|
||||
['Barfoo'],
|
||||
['Something'],
|
||||
])('just renders children', (children) => {
|
||||
it.each([['Foobar'], ['Barfoo'], ['Something']])('just renders children', (children) => {
|
||||
setUp(children);
|
||||
expect(screen.getByText(children)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -8,9 +8,8 @@ import { checkAccessibility } from '../__helpers__/accessibility';
|
||||
describe('<ShlinkVersions />', () => {
|
||||
const setUp = (props: ShlinkVersionsProps) => render(<ShlinkVersions {...props} />);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(
|
||||
setUp({ selectedServer: fromPartial({ version: '1.0.0', printableVersion: '1.0.0' }) }),
|
||||
));
|
||||
it('passes a11y checks', () =>
|
||||
checkAccessibility(setUp({ selectedServer: fromPartial({ version: '1.0.0', printableVersion: '1.0.0' }) })));
|
||||
|
||||
it.each([
|
||||
['1.2.3', fromPartial<ReachableServer>({ version: '1.0.0', printableVersion: 'foo' }), 'v1.2.3', 'foo'],
|
||||
|
||||
@@ -5,9 +5,10 @@ import { checkAccessibility } from '../__helpers__/accessibility';
|
||||
import { renderWithStore } from '../__helpers__/setUpTest';
|
||||
|
||||
describe('<ShlinkVersionsContainer />', () => {
|
||||
const setUp = (selectedServer: SelectedServer = null) => renderWithStore(<ShlinkVersionsContainer />, {
|
||||
initialState: { selectedServer },
|
||||
});
|
||||
const setUp = (selectedServer: SelectedServer = null) =>
|
||||
renderWithStore(<ShlinkVersionsContainer />, {
|
||||
initialState: { selectedServer },
|
||||
});
|
||||
|
||||
it.each([
|
||||
[null],
|
||||
|
||||
@@ -13,14 +13,15 @@ vi.mock('@shlinkio/shlink-web-component', () => ({
|
||||
}));
|
||||
|
||||
describe('<ShlinkWebComponentContainer />', () => {
|
||||
const setUp = (selectedServer: SelectedServer) => renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ShlinkWebComponentContainer TagColorsStorage={fromPartial({})} />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { selectedServer, servers: {}, settings: {} },
|
||||
},
|
||||
);
|
||||
const setUp = (selectedServer: SelectedServer) =>
|
||||
renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ShlinkWebComponentContainer TagColorsStorage={fromPartial({})} />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { selectedServer, servers: {}, settings: {} },
|
||||
},
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp(fromPartial({ version: '3.0.0' }))));
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ describe('context', () => {
|
||||
describe('useDependencies', () => {
|
||||
let lastDependencies: unknown[];
|
||||
|
||||
function TestComponent({ name}: { name: string }) {
|
||||
function TestComponent({ name }: { name: string }) {
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
lastDependencies = useDependencies(name);
|
||||
lastDependencies = useDependencies(name);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ describe('context', () => {
|
||||
});
|
||||
|
||||
it('throws when requested dependency is not found in container', () => {
|
||||
expect(() => render(
|
||||
<ContainerProvider value={fromPartial({})}>
|
||||
<TestComponent name="foo" />
|
||||
</ContainerProvider>,
|
||||
)).toThrowError('Dependency with name "foo" not found in container');
|
||||
expect(() =>
|
||||
render(
|
||||
<ContainerProvider value={fromPartial({})}>
|
||||
<TestComponent name="foo" />
|
||||
</ContainerProvider>,
|
||||
),
|
||||
).toThrowError('Dependency with name "foo" not found in container');
|
||||
});
|
||||
|
||||
it('gets dependency from container', () => {
|
||||
|
||||
@@ -70,12 +70,14 @@ describe('<CreateServer />', () => {
|
||||
|
||||
expect(store.getState().servers[expectedServerId]).not.toBeDefined();
|
||||
fireEvent.submit(screen.getByRole('form'));
|
||||
expect(store.getState().servers[expectedServerId]).toEqual(expect.objectContaining({
|
||||
id: expectedServerId,
|
||||
name: 'the_name',
|
||||
url: 'https://the_url.com',
|
||||
apiKey: 'the_api_key',
|
||||
}));
|
||||
expect(store.getState().servers[expectedServerId]).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expectedServerId,
|
||||
name: 'the_name',
|
||||
url: 'https://the_url.com',
|
||||
apiKey: 'the_api_key',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(history.location.pathname).toEqual(`/server/${expectedServerId}`);
|
||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||
|
||||
@@ -21,11 +21,7 @@ describe('<DeleteServerButton />', () => {
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp('Delete me')));
|
||||
|
||||
it.each([
|
||||
['Foo bar'],
|
||||
['baz'],
|
||||
['something'],
|
||||
])('renders expected content', (children) => {
|
||||
it.each([['Foo bar'], ['baz'], ['something']])('renders expected content', (children) => {
|
||||
const { container } = setUp(children);
|
||||
expect(container.firstChild).toBeTruthy();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
|
||||
@@ -9,16 +9,12 @@ import { TestModalWrapper } from '../__helpers__/TestModalWrapper';
|
||||
describe('<DeleteServerModal />', () => {
|
||||
const serverName = 'the_server_name';
|
||||
const server = fromPartial<ServerWithId>({ id: 'foo', name: serverName });
|
||||
const setUp = () => renderWithStore(
|
||||
<TestModalWrapper
|
||||
renderModal={(args) => <DeleteServerModal {...args} server={server} />}
|
||||
/>,
|
||||
{
|
||||
const setUp = () =>
|
||||
renderWithStore(<TestModalWrapper renderModal={(args) => <DeleteServerModal {...args} server={server} />} />, {
|
||||
initialState: {
|
||||
servers: { foo: server },
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
|
||||
@@ -36,19 +32,19 @@ describe('<DeleteServerModal />', () => {
|
||||
expect(screen.getByText(serverName)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.each([
|
||||
[() => screen.getByRole('button', { name: 'Cancel' })],
|
||||
[() => screen.getByLabelText('Close dialog')],
|
||||
])('closes dialog when clicking cancel button', async (getButton) => {
|
||||
const { user, store } = setUp();
|
||||
it.each([[() => screen.getByRole('button', { name: 'Cancel' })], [() => screen.getByLabelText('Close dialog')]])(
|
||||
'closes dialog when clicking cancel button',
|
||||
async (getButton) => {
|
||||
const { user, store } = setUp();
|
||||
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
await user.click(getButton());
|
||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
await user.click(getButton());
|
||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||
|
||||
// No server has been deleted
|
||||
expect(Object.keys(store.getState().servers)).toHaveLength(1);
|
||||
});
|
||||
// No server has been deleted
|
||||
expect(Object.keys(store.getState().servers)).toHaveLength(1);
|
||||
},
|
||||
);
|
||||
|
||||
it('deletes server when clicking accept button', async () => {
|
||||
const { user, store } = setUp();
|
||||
|
||||
@@ -65,27 +65,33 @@ describe('<EditServer />', () => {
|
||||
// await user.click(screen.getByRole('button', { name: 'Save' }));
|
||||
fireEvent.submit(screen.getByRole('form'));
|
||||
|
||||
expect(store.getState().servers[defaultSelectedServer.id]).toEqual(expect.objectContaining({
|
||||
name: 'the_name edited',
|
||||
url: 'the_url edited',
|
||||
}));
|
||||
expect(store.getState().servers[defaultSelectedServer.id]).toEqual(
|
||||
expect.objectContaining({
|
||||
name: 'the_name edited',
|
||||
url: 'the_url edited',
|
||||
}),
|
||||
);
|
||||
|
||||
// After saving we go back, to the first route from history's initialEntries
|
||||
expect(history.location.pathname).toEqual('/foo');
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ forwardCredentials: true },
|
||||
{ forwardCredentials: false },
|
||||
])('edits advanced options - forward credentials', async ({ forwardCredentials }) => {
|
||||
const { user, store } = setUp({ ...defaultSelectedServer, forwardCredentials });
|
||||
it.each([{ forwardCredentials: true }, { forwardCredentials: false }])(
|
||||
'edits advanced options - forward credentials',
|
||||
async ({ forwardCredentials }) => {
|
||||
const { user, store } = setUp({ ...defaultSelectedServer, forwardCredentials });
|
||||
|
||||
await user.click(screen.getByText('Advanced options'));
|
||||
await user.click(screen.getByLabelText('Forward credentials to this server on every request.'));
|
||||
fireEvent.submit(screen.getByRole('form'));
|
||||
await user.click(screen.getByText('Advanced options'));
|
||||
await user.click(screen.getByLabelText('Forward credentials to this server on every request.'));
|
||||
fireEvent.submit(screen.getByRole('form'));
|
||||
|
||||
await waitFor(() => expect(store.getState().servers[defaultSelectedServer.id]).toEqual(expect.objectContaining({
|
||||
forwardCredentials: !forwardCredentials,
|
||||
})));
|
||||
});
|
||||
await waitFor(() =>
|
||||
expect(store.getState().servers[defaultSelectedServer.id]).toEqual(
|
||||
expect.objectContaining({
|
||||
forwardCredentials: !forwardCredentials,
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -11,23 +11,26 @@ describe('<ManageServers />', () => {
|
||||
const exportServers = vi.fn();
|
||||
const serversExporter = fromPartial<ServersExporter>({ exportServers });
|
||||
const useTimeoutToggle = vi.fn().mockReturnValue([false, vi.fn()]);
|
||||
const createServerMock = (value: string, autoConnect = false) => fromPartial<ServerWithId>(
|
||||
{ id: value, name: value, url: value, autoConnect },
|
||||
);
|
||||
const setUp = (servers: ServersMap = {}) => renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ManageServers useTimeoutToggle={useTimeoutToggle} ServersExporter={serversExporter} />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { servers },
|
||||
},
|
||||
);
|
||||
const createServerMock = (value: string, autoConnect = false) =>
|
||||
fromPartial<ServerWithId>({ id: value, name: value, url: value, autoConnect });
|
||||
const setUp = (servers: ServersMap = {}) =>
|
||||
renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ManageServers useTimeoutToggle={useTimeoutToggle} ServersExporter={serversExporter} />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { servers },
|
||||
},
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp({
|
||||
foo: createServerMock('foo'),
|
||||
bar: createServerMock('bar'),
|
||||
baz: createServerMock('baz'),
|
||||
})));
|
||||
it('passes a11y checks', () =>
|
||||
checkAccessibility(
|
||||
setUp({
|
||||
foo: createServerMock('foo'),
|
||||
bar: createServerMock('bar'),
|
||||
baz: createServerMock('baz'),
|
||||
}),
|
||||
));
|
||||
|
||||
it('shows search field which allows searching servers, affecting te amount of rendered rows', async () => {
|
||||
const { user } = setUp({
|
||||
|
||||
@@ -13,13 +13,14 @@ describe('<ManageServersRow />', () => {
|
||||
apiKey: '123',
|
||||
id: 'abc',
|
||||
};
|
||||
const setUp = (hasAutoConnect = false, autoConnect = false) => renderWithStore(
|
||||
<MemoryRouter>
|
||||
<Table header={<Table.Row />}>
|
||||
<ManageServersRow server={{ ...server, autoConnect }} hasAutoConnect={hasAutoConnect} />
|
||||
</Table>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
const setUp = (hasAutoConnect = false, autoConnect = false) =>
|
||||
renderWithStore(
|
||||
<MemoryRouter>
|
||||
<Table header={<Table.Row />}>
|
||||
<ManageServersRow server={{ ...server, autoConnect }} hasAutoConnect={hasAutoConnect} />
|
||||
</Table>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
|
||||
@@ -36,10 +37,7 @@ describe('<ManageServersRow />', () => {
|
||||
expect(screen.getByRole('button', { name: 'Options' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it.each([
|
||||
[true],
|
||||
[false],
|
||||
])('renders auto-connect icon only if server is autoConnect', (autoConnect) => {
|
||||
it.each([[true], [false]])('renders auto-connect icon only if server is autoConnect', (autoConnect) => {
|
||||
const { container } = setUp(true, autoConnect);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -12,16 +12,17 @@ describe('<ServersDropdown />', () => {
|
||||
'2b': fromPartial({ name: 'bar', id: '2b' }),
|
||||
'3c': fromPartial({ name: 'baz', id: '3c' }),
|
||||
};
|
||||
const setUp = (servers: ServersMap = fallbackServers) => renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ul role="menu">
|
||||
<ServersDropdown />
|
||||
</ul>
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { selectedServer: null, servers },
|
||||
},
|
||||
);
|
||||
const setUp = (servers: ServersMap = fallbackServers) =>
|
||||
renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ul role="menu">
|
||||
<ServersDropdown />
|
||||
</ul>
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { selectedServer: null, servers },
|
||||
},
|
||||
);
|
||||
|
||||
it('passes a11y checks', async () => {
|
||||
const { user, ...rest } = setUp();
|
||||
|
||||
@@ -6,10 +6,7 @@ import { ServersListGroup } from '../../src/servers/ServersListGroup';
|
||||
import { checkAccessibility } from '../__helpers__/accessibility';
|
||||
|
||||
describe('<ServersListGroup />', () => {
|
||||
const servers: ServerWithId[] = [
|
||||
fromPartial({ name: 'foo', id: '123' }),
|
||||
fromPartial({ name: 'bar', id: '456' }),
|
||||
];
|
||||
const servers: ServerWithId[] = [fromPartial({ name: 'foo', id: '123' }), fromPartial({ name: 'bar', id: '456' })];
|
||||
const setUp = (params: { servers?: ServerWithId[]; borderless?: boolean } = {}) => {
|
||||
const { servers = [], borderless } = params;
|
||||
|
||||
@@ -22,21 +19,14 @@ describe('<ServersListGroup />', () => {
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
|
||||
it.each([
|
||||
[servers],
|
||||
[[]],
|
||||
])('shows servers list', (servers) => {
|
||||
it.each([[servers], [[]]])('shows servers list', (servers) => {
|
||||
setUp({ servers });
|
||||
|
||||
expect(screen.queryAllByTestId('list')).toHaveLength(servers.length ? 1 : 0);
|
||||
expect(screen.queryAllByRole('link')).toHaveLength(servers.length);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[true],
|
||||
[false],
|
||||
[undefined],
|
||||
])('renders proper classes for embedded', (borderless) => {
|
||||
it.each([[true], [false], [undefined]])('renders proper classes for embedded', (borderless) => {
|
||||
setUp({ servers, borderless });
|
||||
const list = screen.getByTestId('list');
|
||||
|
||||
|
||||
@@ -8,9 +8,12 @@ import { renderWithEvents } from '../../__helpers__/setUpTest';
|
||||
describe('<DuplicatedServersModal />', () => {
|
||||
const onClose = vi.fn();
|
||||
const onConfirm = vi.fn();
|
||||
const setUp = (duplicatedServers: ServerData[] = []) => act(() => renderWithEvents(
|
||||
<DuplicatedServersModal open duplicatedServers={duplicatedServers} onClose={onClose} onConfirm={onConfirm} />,
|
||||
));
|
||||
const setUp = (duplicatedServers: ServerData[] = []) =>
|
||||
act(() =>
|
||||
renderWithEvents(
|
||||
<DuplicatedServersModal open duplicatedServers={duplicatedServers} onClose={onClose} onConfirm={onConfirm} />,
|
||||
),
|
||||
);
|
||||
const mockServer = (data: Partial<ServerData> = {}) => fromPartial<ServerData>(data);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
@@ -60,10 +63,7 @@ describe('<DuplicatedServersModal />', () => {
|
||||
it.each([
|
||||
[[]],
|
||||
[[mockServer({ url: 'url', apiKey: 'apiKey' })]],
|
||||
[[
|
||||
mockServer({ url: 'url_1', apiKey: 'apiKey_1' }),
|
||||
mockServer({ url: 'url_2', apiKey: 'apiKey_2' }),
|
||||
]],
|
||||
[[mockServer({ url: 'url_1', apiKey: 'apiKey_1' }), mockServer({ url: 'url_2', apiKey: 'apiKey_2' })]],
|
||||
])('displays provided server data', async (duplicatedServers) => {
|
||||
await setUp(duplicatedServers);
|
||||
|
||||
|
||||
@@ -12,12 +12,10 @@ describe('<ImportServersBtn />', () => {
|
||||
const onImportMock = vi.fn();
|
||||
const importServersFromFile = vi.fn().mockResolvedValue([]);
|
||||
const serversImporterMock = fromPartial<ServersImporter>({ importServersFromFile });
|
||||
const setUp = (props: Partial<ImportServersBtnProps> = {}, servers: ServersMap = {}) => renderWithStore(
|
||||
<ImportServersBtn {...props} onImport={onImportMock} ServersImporter={serversImporterMock} />,
|
||||
{
|
||||
const setUp = (props: Partial<ImportServersBtnProps> = {}, servers: ServersMap = {}) =>
|
||||
renderWithStore(<ImportServersBtn {...props} onImport={onImportMock} ServersImporter={serversImporterMock} />, {
|
||||
initialState: { servers },
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
|
||||
@@ -26,8 +24,8 @@ describe('<ImportServersBtn />', () => {
|
||||
|
||||
expect(screen.queryByText(/^You can create servers by importing a CSV file/)).not.toBeInTheDocument();
|
||||
await user.hover(screen.getByRole('button'));
|
||||
await waitFor(
|
||||
() => expect(screen.getByText(/^You can create servers by importing a CSV file/)).toBeInTheDocument(),
|
||||
await waitFor(() =>
|
||||
expect(screen.getByText(/^You can create servers by importing a CSV file/)).toBeInTheDocument(),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -59,38 +57,41 @@ describe('<ImportServersBtn />', () => {
|
||||
it.each([
|
||||
{ btnName: 'Save duplicate', savesDuplicatedServers: true },
|
||||
{ btnName: 'Discard', savesDuplicatedServers: false },
|
||||
])('creates duplicated servers depending on selected option in modal', async ({ btnName, savesDuplicatedServers }) => {
|
||||
const existingServerData: ServerData = {
|
||||
name: 'existingServer',
|
||||
url: 'http://s.test/existingUrl',
|
||||
apiKey: 'existingApiKey',
|
||||
};
|
||||
const existingServer: ServerWithId = {
|
||||
...existingServerData,
|
||||
id: 'existingserver-s.test',
|
||||
};
|
||||
const newServer: ServerData = { name: 'newServer', url: 'http://s.test/newUrl', apiKey: 'newApiKey' };
|
||||
const { user, store } = setUp({}, { [existingServer.id]: existingServer });
|
||||
])(
|
||||
'creates duplicated servers depending on selected option in modal',
|
||||
async ({ btnName, savesDuplicatedServers }) => {
|
||||
const existingServerData: ServerData = {
|
||||
name: 'existingServer',
|
||||
url: 'http://s.test/existingUrl',
|
||||
apiKey: 'existingApiKey',
|
||||
};
|
||||
const existingServer: ServerWithId = {
|
||||
...existingServerData,
|
||||
id: 'existingserver-s.test',
|
||||
};
|
||||
const newServer: ServerData = { name: 'newServer', url: 'http://s.test/newUrl', apiKey: 'newApiKey' };
|
||||
const { user, store } = setUp({}, { [existingServer.id]: existingServer });
|
||||
|
||||
importServersFromFile.mockResolvedValue([existingServerData, newServer]);
|
||||
importServersFromFile.mockResolvedValue([existingServerData, newServer]);
|
||||
|
||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||
await user.upload(screen.getByTestId('csv-file-input'), csvFile);
|
||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||
await user.upload(screen.getByTestId('csv-file-input'), csvFile);
|
||||
|
||||
// Once the file is uploaded, non-duplicated servers are immediately created
|
||||
const { servers } = store.getState();
|
||||
expect(Object.keys(servers)).toHaveLength(2);
|
||||
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
await user.click(screen.getByRole('button', { name: btnName }));
|
||||
|
||||
// If duplicated servers are saved, there's one extra server creation
|
||||
if (savesDuplicatedServers) {
|
||||
// Once the file is uploaded, non-duplicated servers are immediately created
|
||||
const { servers } = store.getState();
|
||||
expect(Object.keys(servers)).toHaveLength(3);
|
||||
}
|
||||
expect(Object.keys(servers)).toHaveLength(2);
|
||||
|
||||
// On import is called only once, no matter what
|
||||
expect(onImportMock).toHaveBeenCalledOnce();
|
||||
});
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
await user.click(screen.getByRole('button', { name: btnName }));
|
||||
|
||||
// If duplicated servers are saved, there's one extra server creation
|
||||
if (savesDuplicatedServers) {
|
||||
const { servers } = store.getState();
|
||||
expect(Object.keys(servers)).toHaveLength(3);
|
||||
}
|
||||
|
||||
// On import is called only once, no matter what
|
||||
expect(onImportMock).toHaveBeenCalledOnce();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,19 +7,20 @@ import { checkAccessibility } from '../../__helpers__/accessibility';
|
||||
import { renderWithStore } from '../../__helpers__/setUpTest';
|
||||
|
||||
describe('<ServerError />', () => {
|
||||
const setUp = (selectedServer: SelectedServer) => renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ServerError />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { selectedServer, servers: {} },
|
||||
},
|
||||
);
|
||||
const setUp = (selectedServer: SelectedServer) =>
|
||||
renderWithStore(
|
||||
<MemoryRouter>
|
||||
<ServerError />
|
||||
</MemoryRouter>,
|
||||
{
|
||||
initialState: { selectedServer, servers: {} },
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[fromPartial<NotFoundServer>({})],
|
||||
[fromPartial<NonReachableServer>({ id: 'abc123' })],
|
||||
])('passes a11y checks', (selectedServer) => checkAccessibility(setUp(selectedServer)));
|
||||
it.each([[fromPartial<NotFoundServer>({})], [fromPartial<NonReachableServer>({ id: 'abc123' })]])(
|
||||
'passes a11y checks',
|
||||
(selectedServer) => checkAccessibility(setUp(selectedServer)),
|
||||
);
|
||||
|
||||
it.each([
|
||||
[
|
||||
|
||||
@@ -66,7 +66,6 @@ describe('remoteServersReducer', () => {
|
||||
url: 'http://localhost:8000',
|
||||
apiKey: '7a531c75-134e-4d5c-86e0-a71b7167b57a',
|
||||
},
|
||||
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -21,17 +21,20 @@ describe('selectedServerReducer', () => {
|
||||
|
||||
it('returns selected server when action is SELECT_SERVER', () => {
|
||||
const payload = fromPartial<RegularServer>({ id: 'abc123' });
|
||||
expect(reducer(null, selectServer.fulfilled(payload, '', { serverId: '', buildShlinkApiClient }))).toEqual(payload);
|
||||
expect(reducer(null, selectServer.fulfilled(payload, '', { serverId: '', buildShlinkApiClient }))).toEqual(
|
||||
payload,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('selectServer', () => {
|
||||
const version = '1.19.0';
|
||||
const createGetStateMock = (id: string) => vi.fn().mockReturnValue({
|
||||
servers: {
|
||||
[id]: { id },
|
||||
},
|
||||
});
|
||||
const createGetStateMock = (id: string) =>
|
||||
vi.fn().mockReturnValue({
|
||||
servers: {
|
||||
[id]: { id },
|
||||
},
|
||||
});
|
||||
|
||||
it.each([
|
||||
[version, version, `v${version}`],
|
||||
|
||||
@@ -39,14 +39,16 @@ describe('serversReducer', () => {
|
||||
ghi789: { id: 'ghi789' },
|
||||
}));
|
||||
|
||||
it.each([
|
||||
[true],
|
||||
[false],
|
||||
])('returns state as it is when trying to set auto-connect on invalid server', (autoConnect) =>
|
||||
expect(serversReducer(list, setAutoConnect(fromPartial<ServerWithId>({ id: 'invalid' }), autoConnect))).toEqual({
|
||||
abc123: { id: 'abc123' },
|
||||
def456: { id: 'def456' },
|
||||
}));
|
||||
it.each([[true], [false]])(
|
||||
'returns state as it is when trying to set auto-connect on invalid server',
|
||||
(autoConnect) =>
|
||||
expect(serversReducer(list, setAutoConnect(fromPartial<ServerWithId>({ id: 'invalid' }), autoConnect))).toEqual(
|
||||
{
|
||||
abc123: { id: 'abc123' },
|
||||
def456: { id: 'def456' },
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
it('disables auto-connect on a server which is already set to auto-connect', () => {
|
||||
const listWithDisabledAutoConnect = {
|
||||
@@ -54,10 +56,9 @@ describe('serversReducer', () => {
|
||||
abc123: { ...list.abc123, autoConnect: true },
|
||||
};
|
||||
|
||||
expect(serversReducer(
|
||||
listWithDisabledAutoConnect,
|
||||
setAutoConnect(fromPartial<ServerWithId>({ id: 'abc123' }), false),
|
||||
)).toEqual({
|
||||
expect(
|
||||
serversReducer(listWithDisabledAutoConnect, setAutoConnect(fromPartial<ServerWithId>({ id: 'abc123' }), false)),
|
||||
).toEqual({
|
||||
abc123: { id: 'abc123', autoConnect: false },
|
||||
def456: { id: 'def456' },
|
||||
});
|
||||
@@ -69,10 +70,9 @@ describe('serversReducer', () => {
|
||||
abc123: { ...list.abc123, autoConnect: true },
|
||||
};
|
||||
|
||||
expect(serversReducer(
|
||||
listWithEnabledAutoConnect,
|
||||
setAutoConnect(fromPartial<ServerWithId>({ id: 'def456' }), true),
|
||||
)).toEqual({
|
||||
expect(
|
||||
serversReducer(listWithEnabledAutoConnect, setAutoConnect(fromPartial<ServerWithId>({ id: 'def456' }), true)),
|
||||
).toEqual({
|
||||
abc123: { id: 'abc123', autoConnect: false },
|
||||
def456: { id: 'def456', autoConnect: true },
|
||||
});
|
||||
@@ -108,10 +108,7 @@ describe('serversReducer', () => {
|
||||
});
|
||||
|
||||
describe('setAutoConnect', () => {
|
||||
it.each([
|
||||
[true],
|
||||
[false],
|
||||
])('returns expected action', (autoConnect) => {
|
||||
it.each([[true], [false]])('returns expected action', (autoConnect) => {
|
||||
const serverToEdit = fromPartial<RegularServer>({ id: 'abc123' });
|
||||
const { payload } = setAutoConnect(serverToEdit, autoConnect);
|
||||
|
||||
|
||||
@@ -54,7 +54,9 @@ describe('ServersExporter', () => {
|
||||
it('makes use of download link API', () => {
|
||||
const jsonToCsvMock = createJsonToCsvMock();
|
||||
const exporter = new ServersExporter(storageMock, windowMock, jsonToCsvMock);
|
||||
const { document: { createElement } } = windowMock;
|
||||
const {
|
||||
document: { createElement },
|
||||
} = windowMock;
|
||||
|
||||
exporter.exportServers();
|
||||
|
||||
|
||||
@@ -11,9 +11,7 @@ describe('ServersImporter', () => {
|
||||
|
||||
describe('importServersFromFile', () => {
|
||||
it.each([[null], [undefined]])('rejects with error if no file was provided', async (file) => {
|
||||
await expect(importer.importServersFromFile(file)).rejects.toEqual(
|
||||
new Error('No file provided'),
|
||||
);
|
||||
await expect(importer.importServersFromFile(file)).rejects.toEqual(new Error('No file provided'));
|
||||
});
|
||||
|
||||
it('rejects with error if parsing the file fails', async () => {
|
||||
@@ -52,13 +50,13 @@ describe('ServersImporter', () => {
|
||||
],
|
||||
expectedError: 'Server is missing required "url", "apiKey" and/or "name" properties',
|
||||
},
|
||||
])('rejects with error if provided file does not parse to valid list of servers', async ({
|
||||
parsedObject,
|
||||
expectedError,
|
||||
}) => {
|
||||
csvjsonMock.mockResolvedValue(parsedObject);
|
||||
await expect(importer.importServersFromFile(fileMock())).rejects.toEqual(new Error(expectedError));
|
||||
});
|
||||
])(
|
||||
'rejects with error if provided file does not parse to valid list of servers',
|
||||
async ({ parsedObject, expectedError }) => {
|
||||
csvjsonMock.mockResolvedValue(parsedObject);
|
||||
await expect(importer.importServersFromFile(fileMock())).rejects.toEqual(new Error(expectedError));
|
||||
},
|
||||
);
|
||||
|
||||
it('reads file when a CSV containing valid servers is provided', async () => {
|
||||
const expectedServers: Required<ServerData>[] = [
|
||||
|
||||
@@ -4,11 +4,12 @@ import { checkAccessibility } from '../__helpers__/accessibility';
|
||||
import { renderWithStore } from '../__helpers__/setUpTest';
|
||||
|
||||
describe('<Settings />', () => {
|
||||
const setUp = () => renderWithStore(
|
||||
<MemoryRouter>
|
||||
<Settings />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
const setUp = () =>
|
||||
renderWithStore(
|
||||
<MemoryRouter>
|
||||
<Settings />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
it('passes a11y checks', () => checkAccessibility(setUp()));
|
||||
});
|
||||
|
||||
@@ -17,13 +17,15 @@ describe('settings-helpers', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(migrateDeprecatedSettings(state)).toEqual(expect.objectContaining({
|
||||
settings: expect.objectContaining({
|
||||
visits: {
|
||||
defaultInterval: 'last180Days',
|
||||
},
|
||||
expect(migrateDeprecatedSettings(state)).toEqual(
|
||||
expect.objectContaining({
|
||||
settings: expect.objectContaining({
|
||||
visits: {
|
||||
defaultInterval: 'last180Days',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,10 @@ describe('TagColorsStorage', () => {
|
||||
describe('getTagColors', () => {
|
||||
it.each([
|
||||
[undefined, {}],
|
||||
[{ foo: 'red', var: 'green' }, { foo: 'red', var: 'green' }],
|
||||
[
|
||||
{ foo: 'red', var: 'green' },
|
||||
{ foo: 'red', var: 'green' },
|
||||
],
|
||||
])('returns colors from local storage', (colorsFromStorage, expectedValue) => {
|
||||
get.mockReturnValue(colorsFromStorage);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user