test(frontend): correct test to fit sign up/in
This commit is contained in:
@@ -454,10 +454,7 @@
|
|||||||
bind:value={username}
|
bind:value={username}
|
||||||
bind:this={loginIdentifierInput}
|
bind:this={loginIdentifierInput}
|
||||||
autocomplete="username"
|
autocomplete="username"
|
||||||
placeholder={t(
|
placeholder={t('auth.login_identifier_placeholder', 'Enter your username or email')}
|
||||||
'auth.login_identifier_placeholder',
|
|
||||||
'Enter your username or email'
|
|
||||||
)}
|
|
||||||
required
|
required
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
/>
|
/>
|
||||||
@@ -606,10 +603,7 @@
|
|||||||
{#if passwordLoginEnabled}
|
{#if passwordLoginEnabled}
|
||||||
<div class="auth-input-group">
|
<div class="auth-input-group">
|
||||||
<label class="auth-label" for="reg-password">
|
<label class="auth-label" for="reg-password">
|
||||||
{t(
|
{t('auth.password_optional', 'Password (optional — leave blank for a sign-in link)')}
|
||||||
'auth.password_optional',
|
|
||||||
'Password (optional — leave blank for a sign-in link)'
|
|
||||||
)}
|
|
||||||
</label>
|
</label>
|
||||||
<div class="auth-input-wrap auth-input-wrap--lock has-toggle">
|
<div class="auth-input-wrap auth-input-wrap--lock has-toggle">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -41,7 +41,15 @@ beforeEach(() => {
|
|||||||
pageState.url = new URL('http://localhost/login');
|
pageState.url = new URL('http://localhost/login');
|
||||||
session.user = null;
|
session.user = null;
|
||||||
m(auth.fetchMe).mockResolvedValue(null);
|
m(auth.fetchMe).mockResolvedValue(null);
|
||||||
m(auth.getOidcProviders).mockResolvedValue({ providers: [] });
|
// Default provider info: both password + magic-link enabled, OIDC off.
|
||||||
|
// The unified login form's magic-link submit path is only reachable
|
||||||
|
// when `magic_link_login_enabled === true` — without this pin the
|
||||||
|
// "sends a magic link" test can't reach `sendMagicLink()`.
|
||||||
|
m(auth.getOidcProviders).mockResolvedValue({
|
||||||
|
enabled: false,
|
||||||
|
password_login_enabled: true,
|
||||||
|
magic_link_login_enabled: true
|
||||||
|
});
|
||||||
m(auth.getAuthStatus).mockResolvedValue({ initialized: true });
|
m(auth.getAuthStatus).mockResolvedValue({ initialized: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,16 +83,21 @@ it('enters setup mode on a fresh install', async () => {
|
|||||||
await screen.findByTestId('login-setup-form');
|
await screen.findByTestId('login-setup-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends a magic link', async () => {
|
it('sends a magic link when the password field is left empty', async () => {
|
||||||
|
// Unified form: the same identifier input drives both flows. Filling
|
||||||
|
// the identifier and leaving password empty makes `submitAsMagicLink`
|
||||||
|
// derived resolve to true — the single submit button then dispatches
|
||||||
|
// to `sendMagicLink` instead of `login`.
|
||||||
m(auth.sendMagicLink).mockResolvedValue('sent');
|
m(auth.sendMagicLink).mockResolvedValue('sent');
|
||||||
render(LoginPage);
|
render(LoginPage);
|
||||||
await screen.findByTestId('login-form');
|
await screen.findByTestId('login-form');
|
||||||
await fireEvent.click(screen.getByTestId('login-magic-toggle-btn'));
|
await fireEvent.input(screen.getByTestId('login-username-input'), {
|
||||||
await fireEvent.input(screen.getByTestId('login-magic-email-input'), {
|
|
||||||
target: { value: 'a@b.test' }
|
target: { value: 'a@b.test' }
|
||||||
});
|
});
|
||||||
await fireEvent.click(screen.getByTestId('login-magic-send-btn'));
|
// Password intentionally NOT filled.
|
||||||
|
await fireEvent.click(screen.getByTestId('login-submit-btn'));
|
||||||
await waitFor(() => expect(auth.sendMagicLink).toHaveBeenCalledWith('a@b.test'));
|
await waitFor(() => expect(auth.sendMagicLink).toHaveBeenCalledWith('a@b.test'));
|
||||||
|
expect(auth.login).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registers a new account', async () => {
|
it('registers a new account', async () => {
|
||||||
|
|||||||
@@ -29,11 +29,22 @@ test.describe('SPA · authentication', () => {
|
|||||||
await expect(page.getByTestId('login-form')).toBeVisible();
|
await expect(page.getByTestId('login-form')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('magic-link panel toggles open', async ({ page }) => {
|
test('submit button dispatches to magic-link when password is empty', async ({ page }) => {
|
||||||
|
// Unified login form: one identifier + one optional password + one
|
||||||
|
// adaptive submit button. Filling the identifier and leaving the
|
||||||
|
// password blank flips the button label to "Send sign-in link" and
|
||||||
|
// routes to /api/auth/magic-link/send on click. The old two-form
|
||||||
|
// UX with `login-magic-toggle-btn` was retired 2026-07-14.
|
||||||
await page.goto('/login');
|
await page.goto('/login');
|
||||||
await page.getByTestId('login-magic-toggle-btn').click();
|
await expect(page.getByTestId('login-form')).toBeVisible();
|
||||||
await expect(page.getByTestId('login-magic-form')).toBeVisible();
|
await page.getByTestId('login-username-input').fill('someone@example.test');
|
||||||
await expect(page.getByTestId('login-magic-email-input')).toBeVisible();
|
// Password intentionally NOT filled — this drives the label swap.
|
||||||
|
const submit = page.getByTestId('login-submit-btn');
|
||||||
|
await expect(submit).toBeVisible();
|
||||||
|
// Label content differs per mode: password-empty → magic-link copy;
|
||||||
|
// password-filled → "Sign in". Assert the magic-link copy is what's
|
||||||
|
// shown so the dispatch is provably in the magic-link branch.
|
||||||
|
await expect(submit).toHaveText(/link|Link|Send/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('successful login reaches the files app shell', async ({ page }) => {
|
test('successful login reaches the files app shell', async ({ page }) => {
|
||||||
|
|||||||
@@ -58,13 +58,21 @@ test('an oidc callback code is exchanged on load', async ({ page }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('request a magic link from the login page', async ({ page }) => {
|
test('request a magic link from the login page', async ({ page }) => {
|
||||||
|
// Unified form: leave the password field empty and submit — the
|
||||||
|
// adaptive submit routes to /api/auth/magic-link/send with the
|
||||||
|
// identifier as-is (backend accepts email OR username via `@`
|
||||||
|
// dispatch). Old separate `login-magic-*` testids retired in the
|
||||||
|
// single-form refactor.
|
||||||
await page.goto('/login');
|
await page.goto('/login');
|
||||||
await page.getByTestId('login-magic-toggle-btn').click();
|
await expect(page.getByTestId('login-form')).toBeVisible();
|
||||||
await expect(page.getByTestId('login-magic-form')).toBeVisible();
|
|
||||||
|
|
||||||
await page.getByTestId('login-magic-email-input').fill('someone@example.test');
|
await page.getByTestId('login-username-input').fill('someone@example.test');
|
||||||
await page.getByTestId('login-magic-send-btn').click();
|
// Password intentionally NOT filled.
|
||||||
// A status message resolves (success or error); give the request time to run.
|
await page.getByTestId('login-submit-btn').click();
|
||||||
|
|
||||||
|
// A status message resolves (uniform 200 anti-enum success or error);
|
||||||
|
// give the request time to run.
|
||||||
await page.waitForTimeout(1_000);
|
await page.waitForTimeout(1_000);
|
||||||
await expect(page.getByTestId('login-magic-form').or(page.getByTestId('login-form')).first()).toBeVisible();
|
// Still on the login page either way — anti-enum success doesn't redirect.
|
||||||
|
await expect(page.getByTestId('login-form')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user