mirror of
https://github.com/sotashimozono/obsidian-remote-ssh.git
synced 2026-07-22 17:10:32 +00:00
* test: second coverage pass — Logger/RpcClient/RpcConnection/WindowSpawner Extended four existing test suites to cover previously-untested branches: Logger.test.ts: - setDebug / setMaxLines / clear API methods - wrapConsole: captures console.warn/error to the file sink as external lines, skips [RemoteSSH]-prefixed messages (own plugin traffic), idempotency guard - unwrapConsole: stops capturing after unwrap, is a no-op when unused - captureExternal: no-op when no file sink is installed - formatArg: Error → stack/message; non-JSON-serialisable → String() - installFileSink: mkdirSync failure → fallbackError + early return RpcClient.test.ts: - isClosed() false before / true after close - writeMessage throws → call() rejects with the thrown error (catch block) - onClose disposer removes the handler before close fires RpcConnection.test.ts: - auth RPC result ok:false → AuthInvalid (line 56-57 branch) - server.info error envelope → cleanupOnFailure (line 65-68 branch) WindowSpawner.test.ts: - default opener (no arg constructor) calls window.open with _blank vitest.config.ts: - raise thresholds to lines:76 / branches:69 / functions:73 Coverage delta (measured locally): Statements: 73.5 % → 74.8 % Branches: 68.7 % → 69.7 % Functions: 71.1 % → 73.2 % Lines: 75.1 % → 76.2 % Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fixup! test(Logger): afterEach closes file sink + strengthen captureExternal assertion * afterEach now awaits uninstallFileSink() to prevent fd leaks on test failure — especially important on Windows where open handles block rmSync * captureExternal no-op test: add getLines().toHaveLength(0) to verify the ring buffer was truly untouched, not just that no throw occurred Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
50 lines
2 KiB
TypeScript
50 lines
2 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest';
|
|
import { WindowSpawner, type UrlOpener } from '../src/shadow/WindowSpawner';
|
|
|
|
function recordingOpener() {
|
|
const calls: string[] = [];
|
|
const opener: UrlOpener = { openUrl(url) { calls.push(url); } };
|
|
return { opener, calls };
|
|
}
|
|
|
|
describe('WindowSpawner', () => {
|
|
it('builds an obsidian://open?path=… URL with the encoded vault path', () => {
|
|
const { opener, calls } = recordingOpener();
|
|
const spawner = new WindowSpawner(opener);
|
|
const url = spawner.spawn('C:\\Users\\alice\\.obsidian-remote\\vaults\\p1');
|
|
expect(calls).toHaveLength(1);
|
|
expect(calls[0]).toBe(url);
|
|
expect(url.startsWith('obsidian://open?path=')).toBe(true);
|
|
expect(url).toContain(encodeURIComponent('C:\\Users\\alice\\.obsidian-remote\\vaults\\p1'));
|
|
});
|
|
|
|
it('encodes characters that would otherwise break the URL', () => {
|
|
const { opener, calls } = recordingOpener();
|
|
const spawner = new WindowSpawner(opener);
|
|
spawner.spawn('/path/with spaces/and?question&');
|
|
expect(calls[0]).toContain(encodeURIComponent('/path/with spaces/and?question&'));
|
|
// Spaces / `?` / `&` must NOT appear unencoded after `path=`.
|
|
const after = calls[0].slice('obsidian://open?path='.length);
|
|
expect(after).not.toMatch(/[ ?&]/);
|
|
});
|
|
|
|
it('returns the URL it fired (so callers can log or surface it)', () => {
|
|
const { opener } = recordingOpener();
|
|
const url = new WindowSpawner(opener).spawn('/a/b');
|
|
expect(url).toBe('obsidian://open?path=' + encodeURIComponent('/a/b'));
|
|
});
|
|
|
|
it('default opener delegates to window.open with _blank target', () => {
|
|
const openSpy = vi.spyOn(window, 'open').mockReturnValue(null);
|
|
try {
|
|
const spawner = new WindowSpawner();
|
|
spawner.spawn('/vault/path');
|
|
expect(openSpy).toHaveBeenCalledTimes(1);
|
|
const [url, target] = openSpy.mock.calls[0];
|
|
expect((url as string).startsWith('obsidian://open?path=')).toBe(true);
|
|
expect(target).toBe('_blank');
|
|
} finally {
|
|
openSpy.mockRestore();
|
|
}
|
|
});
|
|
});
|