Migrate from ESLint to Oxlint and Oxfmt

This commit is contained in:
Alejandro Celaya
2026-07-26 09:12:18 +02:00
parent 2cf85a18b3
commit 54d4d9ebad
81 changed files with 2004 additions and 3790 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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,
}),
),
);
},
);
});

View File

@@ -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({

View File

@@ -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();
});

View File

@@ -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();

View File

@@ -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');

View File

@@ -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);

View File

@@ -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();
},
);
});

View File

@@ -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([
[

View File

@@ -66,7 +66,6 @@ describe('remoteServersReducer', () => {
url: 'http://localhost:8000',
apiKey: '7a531c75-134e-4d5c-86e0-a71b7167b57a',
},
},
},
{

View File

@@ -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}`],

View File

@@ -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);

View File

@@ -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();

View File

@@ -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>[] = [