import { beforeEach, describe, expect, it, vi } from 'vitest' import { readConfig } from '../src/config' import { mountPasswordLogin } from '../src/login-password' const cfg = readConfig({ protocol: 'https:', host: 'alice.term.example.com', hostname: 'alice.term.example.com', }) function okFetch(): typeof fetch { return vi.fn(async () => ({ ok: true, status: 200, json: async () => ({}) }) as Response) as unknown as typeof fetch } function rejectFetch(): typeof fetch { return vi.fn(async () => ({ ok: false, status: 401, json: async () => ({}) }) as Response) as unknown as typeof fetch } describe('mountPasswordLogin — v0.8 gate (T3)', () => { let root: HTMLElement beforeEach(() => { root = document.createElement('div') document.body.append(root) }) it('correct token → "ok" and issues a credentialed cookie login request', async () => { const fetchImpl = okFetch() const onSuccess = vi.fn() const login = mountPasswordLogin(root, cfg, { fetchImpl, onSuccess }) await expect(login.submit('s3cret')).resolves.toBe('ok') expect(onSuccess).toHaveBeenCalledOnce() const call = (fetchImpl as unknown as ReturnType).mock.calls[0]! const init = call[1] as RequestInit expect(init.credentials).toBe('include') expect(JSON.parse(init.body as string)).toEqual({ clientToken: 's3cret' }) }) it('wrong token → "rejected", no onSuccess, error shown via textContent (no innerHTML)', async () => { const login = mountPasswordLogin(root, cfg, { fetchImpl: rejectFetch() }) await expect(login.submit('nope')).resolves.toBe('rejected') const err = root.querySelector('.login-error') as HTMLElement expect(err.textContent).toBe('Invalid access token.') expect(err.innerHTML).toBe('Invalid access token.') // textContent-set, no markup injected }) it('empty input keeps submit disabled (fail-fast) and submit("") is rejected without a fetch', async () => { const fetchImpl = okFetch() const login = mountPasswordLogin(root, cfg, { fetchImpl }) const button = root.querySelector('button') as HTMLButtonElement expect(button.disabled).toBe(true) await expect(login.submit('')).resolves.toBe('rejected') expect(fetchImpl).not.toHaveBeenCalled() }) it('does not persist the token to localStorage', async () => { const login = mountPasswordLogin(root, cfg, { fetchImpl: okFetch() }) await login.submit('s3cret') expect(JSON.stringify(localStorage)).not.toContain('s3cret') }) })