test(frontend): verify OIDC-only auto-redirect on the login page
Covers the four-way guard added in e5f8610d: redirects when OIDC is the sole login method, and stays on the form/setup screen when password login is still enabled, the IdP just bounced with ?error=, or the server hasn't been set up yet.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { it, expect, vi, beforeEach } from 'vitest';
|
import { it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||||
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
|
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
|
||||||
|
|
||||||
const { goto, pageState, session } = vi.hoisted(() => {
|
const { goto, pageState, session } = vi.hoisted(() => {
|
||||||
@@ -53,6 +53,24 @@ beforeEach(() => {
|
|||||||
m(auth.getAuthStatus).mockResolvedValue({ initialized: true });
|
m(auth.getAuthStatus).mockResolvedValue({ initialized: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// jsdom's `Location` can't be spied on in place (its setters trigger
|
||||||
|
// "not implemented" navigation errors), so swap the whole object for a
|
||||||
|
// stub around each test that needs to observe `window.location.replace`.
|
||||||
|
const originalLocation = window.location;
|
||||||
|
let replaceSpy: ReturnType<typeof vi.fn>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
replaceSpy = vi.fn();
|
||||||
|
Object.defineProperty(window, 'location', {
|
||||||
|
configurable: true,
|
||||||
|
value: { ...originalLocation, replace: replaceSpy }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
Object.defineProperty(window, 'location', { configurable: true, value: originalLocation });
|
||||||
|
});
|
||||||
|
|
||||||
it('logs in and redirects', async () => {
|
it('logs in and redirects', async () => {
|
||||||
m(auth.login).mockResolvedValue({ user: { id: '1' } });
|
m(auth.login).mockResolvedValue({ user: { id: '1' } });
|
||||||
render(LoginPage);
|
render(LoginPage);
|
||||||
@@ -179,3 +197,48 @@ it('renders an SSO sign-in link when an OIDC provider is configured', async () =
|
|||||||
const sso = await screen.findByTestId('login-oidc-btn');
|
const sso = await screen.findByTestId('login-oidc-btn');
|
||||||
expect(sso.getAttribute('href')).toBe('https://idp.test/auth');
|
expect(sso.getAttribute('href')).toBe('https://idp.test/auth');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('auto-redirects to the IdP when OIDC is the only login method', async () => {
|
||||||
|
m(auth.getOidcProviders).mockResolvedValue({
|
||||||
|
enabled: true,
|
||||||
|
password_login_enabled: false,
|
||||||
|
authorize_endpoint: '/api/auth/oidc/authorize'
|
||||||
|
});
|
||||||
|
render(LoginPage);
|
||||||
|
await waitFor(() => expect(replaceSpy).toHaveBeenCalledWith('/api/auth/oidc/authorize'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not auto-redirect when password login is also enabled', async () => {
|
||||||
|
m(auth.getOidcProviders).mockResolvedValue({
|
||||||
|
enabled: true,
|
||||||
|
password_login_enabled: true,
|
||||||
|
authorize_endpoint: '/api/auth/oidc/authorize'
|
||||||
|
});
|
||||||
|
render(LoginPage);
|
||||||
|
await screen.findByTestId('login-form');
|
||||||
|
expect(replaceSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not auto-redirect after the IdP already returned an error (loop guard)', async () => {
|
||||||
|
pageState.url = new URL('http://localhost/login?error=access_denied');
|
||||||
|
m(auth.getOidcProviders).mockResolvedValue({
|
||||||
|
enabled: true,
|
||||||
|
password_login_enabled: false,
|
||||||
|
authorize_endpoint: '/api/auth/oidc/authorize'
|
||||||
|
});
|
||||||
|
render(LoginPage);
|
||||||
|
await screen.findByTestId('login-form');
|
||||||
|
expect(replaceSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not auto-redirect during first-run setup', async () => {
|
||||||
|
m(auth.getAuthStatus).mockResolvedValue({ initialized: false });
|
||||||
|
m(auth.getOidcProviders).mockResolvedValue({
|
||||||
|
enabled: true,
|
||||||
|
password_login_enabled: false,
|
||||||
|
authorize_endpoint: '/api/auth/oidc/authorize'
|
||||||
|
});
|
||||||
|
render(LoginPage);
|
||||||
|
await screen.findByTestId('login-setup-form');
|
||||||
|
expect(replaceSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user