import { describe, expect, it } from 'vitest' import { readConfig } from '../src/config' import { ConfigError } from '../src/errors' /** Build a Location-like object from a URL string. */ function loc(url: string): Pick { const u = new URL(url) return { protocol: u.protocol, host: u.host, hostname: u.hostname } } describe('readConfig — subdomain + scheme-following same-origin URL (T1, M6)', () => { it('derives subdomain and wss: URL on https', () => { const cfg = readConfig(loc('https://alice.term.example.com')) expect(cfg.subdomain).toBe('alice') expect(cfg.wsUrl('/term')).toBe('wss://alice.term.example.com/term') expect(cfg.apiBase).toBe('') }) it('follows the page scheme to ws: on http (no mixed-content on TLS)', () => { const cfg = readConfig(loc('http://alice.term.localhost:3000')) expect(cfg.subdomain).toBe('alice') expect(cfg.wsUrl('/term')).toBe('ws://alice.term.localhost:3000/term') }) it('throws ConfigError on a bare host with no subdomain label (fail-fast, never defaults)', () => { expect(() => readConfig(loc('https://example.com'))).toThrow(ConfigError) expect(() => readConfig(loc('https://localhost'))).toThrow(ConfigError) expect(() => readConfig(loc('https://term.example.com'))).toThrow(ConfigError) }) it('keeps wsUrl same-origin — a path cannot inject a foreign host', () => { const cfg = readConfig(loc('https://alice.term.example.com')) const injected = cfg.wsUrl('//evil.com') expect(injected.startsWith('wss://alice.term.example.com/')).toBe(true) expect(injected).not.toContain('evil.com/') // even a scheme-looking path stays anchored to our host expect(new URL(cfg.wsUrl('/x')).host).toBe('alice.term.example.com') }) })