diff --git a/web/hwlab-cloud-web/auth.test.ts b/web/hwlab-cloud-web/auth.test.ts index 79cbebf8..a427c30b 100644 --- a/web/hwlab-cloud-web/auth.test.ts +++ b/web/hwlab-cloud-web/auth.test.ts @@ -67,6 +67,40 @@ test("login uses cloud-api auth instead of local storage fallback", async () => } }); +test("login submit is wired before the initial session probe resolves", async () => { + const sessionProbe = deferred(); + const harness = installAuthHarness({ + localSession: null, + responses: { + "/auth/session": sessionProbe.promise, + "/auth/login": { + authenticated: true, + user: { username: "admin" }, + expiresAt: futureIso() + } + } + }); + + try { + const pendingSession = ensureWorkbenchAuth({ loginShell: harness.loginShell, appShell: harness.appShell }); + await harness.waitForLoginReady(); + + harness.usernameInput.value = "admin"; + harness.passwordInput.value = "hwlab2026"; + await harness.submitLogin(); + + assert.deepEqual(harness.fetchCalls.map((call) => call.path), ["/auth/session", "/auth/login"]); + sessionProbe.resolve({ authenticated: false }); + const session = await pendingSession; + + assert.equal(session.authenticated, true); + assert.equal(harness.loginShell.hidden, true); + assert.equal(harness.appShell.hidden, false); + } finally { + harness.restore(); + } +}); + function installAuthHarness({ localSession, responses }) { const previous = { window: globalThis.window, @@ -108,13 +142,13 @@ function installAuthHarness({ localSession, responses }) { clearTimeout: () => {} }; globalThis.fetch = async (path, options = {}) => { - const response = responses[path] ?? { status: 404, authenticated: false }; fetchCalls.push({ path, method: options.method ?? "GET", body: options.body ?? null, credentials: options.credentials ?? null }); + const response = await (responses[path] ?? { status: 404, authenticated: false }); const status = Number(response.status ?? (response.authenticated === false && response.error ? 401 : 200)); return { status, @@ -153,6 +187,14 @@ function futureIso() { return new Date(Date.now() + 60 * 60 * 1000).toISOString(); } +function deferred() { + let resolve; + const promise = new Promise((nextResolve) => { + resolve = nextResolve; + }); + return { promise, resolve }; +} + function elementStub() { return { hidden: false, diff --git a/web/hwlab-cloud-web/auth.ts b/web/hwlab-cloud-web/auth.ts index 4149dc89..c736c71d 100644 --- a/web/hwlab-cloud-web/auth.ts +++ b/web/hwlab-cloud-web/auth.ts @@ -18,13 +18,7 @@ export async function ensureWorkbenchAuth({ loginShell, appShell }) { const config = resolveAuthConfig(); hideWorkbench(appShell); showLogin(loginShell); - - const session = await readActiveSession(config); - if (session.authenticated) { - return activateAuthenticatedWorkbench({ loginShell, appShell, session, config }); - } - - return new Promise((resolve) => { + const loginSession = new Promise((resolve) => { initLoginForm({ loginShell, appShell, @@ -34,6 +28,13 @@ export async function ensureWorkbenchAuth({ loginShell, appShell }) { } }); }); + + const session = await readActiveSession(config); + if (session.authenticated) { + return activateAuthenticatedWorkbench({ loginShell, appShell, session, config }); + } + + return loginSession; } export function initWorkbenchLogout(button) {