Refine settings and panel preferences

This commit is contained in:
2026-04-02 00:58:43 +03:00
parent 69c97ea387
commit 760ab62c10
10 changed files with 853 additions and 286 deletions

View File

@@ -11,6 +11,7 @@ async function loginIntoPanel(user: ReturnType<typeof userEvent.setup>) {
beforeEach(() => {
window.sessionStorage.clear();
window.localStorage.clear();
});
describe('App login gate', () => {
@@ -50,6 +51,23 @@ describe('App login gate', () => {
expect(screen.queryByRole('button', { name: /open panel/i })).not.toBeInTheDocument();
});
it('stores panel language in localStorage and restores it after a remount', async () => {
const user = userEvent.setup();
const firstRender = render(<App />);
await loginIntoPanel(user);
await user.click(screen.getByRole('button', { name: /settings/i }));
await user.selectOptions(screen.getByLabelText(/panel language/i), 'ru');
expect(screen.getByRole('button', { name: /панель/i })).toBeInTheDocument();
firstRender.unmount();
render(<App />);
expect(screen.getByRole('button', { name: /панель/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /настройки/i })).toBeInTheDocument();
});
it('opens add-user flow in a modal and closes it on escape', async () => {
const user = userEvent.setup();
render(<App />);
@@ -107,26 +125,43 @@ describe('App login gate', () => {
expect(screen.queryByRole('dialog', { name: /delete user/i })).not.toBeInTheDocument();
});
it('saves system settings from the system tab and applies them to the local fallback state', async () => {
it('saves service settings from the settings tab and applies them to the local fallback state', async () => {
const user = userEvent.setup();
render(<App />);
await loginIntoPanel(user);
await user.click(screen.getByRole('button', { name: /system/i }));
await user.clear(screen.getByLabelText(/public host/i));
await user.type(screen.getByLabelText(/public host/i), 'ops-gateway.example.net');
await user.click(screen.getByRole('button', { name: /settings/i }));
const firstPortInput = screen.getAllByLabelText(/port/i)[0];
await user.clear(firstPortInput);
await user.type(firstPortInput, '1180');
await user.click(screen.getByRole('button', { name: /save system/i }));
expect(screen.getByText(/ops-gateway\.example\.net/i)).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: /save settings/i }));
await user.click(screen.getByRole('button', { name: /users/i }));
expect(screen.getAllByText(/ops-gateway\.example\.net:1180/i).length).toBeGreaterThan(0);
expect(screen.getAllByText(/edge\.example\.net:1180/i).length).toBeGreaterThan(0);
});
it('warns before deleting a service and removes linked users after confirmation', async () => {
const user = userEvent.setup();
render(<App />);
await loginIntoPanel(user);
await user.click(screen.getByRole('button', { name: /settings/i }));
await user.click(screen.getAllByRole('button', { name: /^remove$/i })[0]);
const dialog = screen.getByRole('dialog', { name: /delete service/i });
expect(dialog).toBeInTheDocument();
expect(within(dialog).getByText(/linked users to be removed/i)).toBeInTheDocument();
expect(within(dialog).getByText(/night-shift, ops-east/i)).toBeInTheDocument();
await user.click(within(dialog).getByRole('button', { name: /^remove$/i }));
await user.click(screen.getByRole('button', { name: /save settings/i }));
await user.click(screen.getByRole('button', { name: /users/i }));
expect(screen.queryByText(/night-shift/i)).not.toBeInTheDocument();
expect(screen.queryByText(/ops-east/i)).not.toBeInTheDocument();
});
});