120 lines
4.9 KiB
TypeScript
120 lines
4.9 KiB
TypeScript
import { afterEach, beforeEach, expect, it, vi } from 'vitest';
|
|
import { flushSync, mount, unmount } from 'svelte';
|
|
import { writable } from 'svelte/store';
|
|
import LoginPage from '../../src/routes/login/+page.svelte';
|
|
import UsersPage from '../../src/routes/settings/users/+page.svelte';
|
|
|
|
const page = writable({
|
|
url: new URL('https://ec.test/login?next=/hosts'),
|
|
data: {
|
|
user: { id: 'admin', username: 'administrator', role: 'admin' },
|
|
rememberedSession: false,
|
|
setupRequired: false
|
|
}
|
|
});
|
|
vi.mock('$app/stores', () => ({
|
|
page: { subscribe: (run: Parameters<typeof page.subscribe>[0]) => page.subscribe(run) }
|
|
}));
|
|
vi.mock('$app/navigation', () => ({ invalidateAll: vi.fn() }));
|
|
|
|
let component: ReturnType<typeof mount> | undefined;
|
|
beforeEach(() => {
|
|
page.update((value) => ({ ...value, data: { ...value.data, rememberedSession: false } }));
|
|
});
|
|
afterEach(async () => {
|
|
if (component) await unmount(component);
|
|
component = undefined;
|
|
document.body.replaceChildren();
|
|
vi.restoreAllMocks();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
function enter(selector: string, value: string) {
|
|
const input = document.querySelector<HTMLInputElement>(selector)!;
|
|
input.value = value;
|
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
flushSync();
|
|
}
|
|
|
|
it.each([false, true])(
|
|
'leaves remembering unchecked by default and submits the selected choice: %s',
|
|
async (rememberMe) => {
|
|
const fetch = vi
|
|
.fn()
|
|
.mockResolvedValue(
|
|
new Response(JSON.stringify({ error: 'Try again' }), { status: 401 })
|
|
);
|
|
vi.stubGlobal('fetch', fetch);
|
|
component = mount(LoginPage, { target: document.body });
|
|
flushSync();
|
|
const checkbox = document.querySelector<HTMLInputElement>('input[name="rememberMe"]')!;
|
|
expect(checkbox.checked).toBe(false);
|
|
expect(document.body.textContent).toContain('30 days');
|
|
enter('#username', 'administrator');
|
|
enter('#password', 'my current password');
|
|
checkbox.checked = rememberMe;
|
|
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
|
|
flushSync();
|
|
document
|
|
.querySelector('form')!
|
|
.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
|
await vi.waitFor(() => expect(fetch).toHaveBeenCalledOnce());
|
|
expect(JSON.parse(fetch.mock.calls[0][1].body)).toEqual({
|
|
username: 'administrator',
|
|
password: 'my current password',
|
|
rememberMe
|
|
});
|
|
await vi.waitFor(() => expect(document.body.textContent).toContain('Try again'));
|
|
expect(document.querySelector<HTMLInputElement>('#password')!.value).toBe('');
|
|
expect(checkbox.checked).toBe(rememberMe);
|
|
}
|
|
);
|
|
|
|
it.each([false, true])(
|
|
'asks remembered administrators for their own password before creating an account: %s',
|
|
async (rememberedSession) => {
|
|
page.update((value) => ({ ...value, data: { ...value.data, rememberedSession } }));
|
|
const fetch = vi.fn(async (path: string, options?: RequestInit) => {
|
|
if (options?.method === 'POST')
|
|
return new Response(JSON.stringify({ error: 'Could not create user' }), {
|
|
status: 403
|
|
});
|
|
return new Response(
|
|
JSON.stringify(path.endsWith('/audit') ? { events: [] } : { users: [] })
|
|
);
|
|
});
|
|
vi.stubGlobal('fetch', fetch);
|
|
component = mount(UsersPage, { target: document.body });
|
|
flushSync();
|
|
const add = Array.from(document.querySelectorAll('button')).find(
|
|
(button) => button.textContent?.trim() === 'Add user'
|
|
)!;
|
|
add.click();
|
|
flushSync();
|
|
const confirmation = document.querySelector<HTMLInputElement>('#create-current-password');
|
|
expect(!!confirmation).toBe(rememberedSession);
|
|
if (rememberedSession) {
|
|
expect(confirmation!.required).toBe(true);
|
|
enter('#create-current-password', 'admin secret');
|
|
}
|
|
enter('#new-username', 'viewer');
|
|
enter('#new-name', 'Viewer');
|
|
enter('#temporary-password', 'temporary secret');
|
|
document
|
|
.querySelector('form')!
|
|
.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
|
await vi.waitFor(() =>
|
|
expect(fetch.mock.calls.some(([, options]) => options?.method === 'POST')).toBe(true)
|
|
);
|
|
const [, options] = fetch.mock.calls.find(([, options]) => options?.method === 'POST')!;
|
|
expect(JSON.parse(String(options!.body))).toMatchObject({
|
|
password: 'temporary secret',
|
|
currentPassword: rememberedSession ? 'admin secret' : ''
|
|
});
|
|
await vi.waitFor(() =>
|
|
expect(document.body.textContent).toContain('Could not create user')
|
|
);
|
|
if (confirmation) expect(confirmation.value).toBe('');
|
|
}
|
|
);
|