Skip to content

DesktopCdpTransport

Transport that communicates with Desktop Obsidian via Chrome DevTools Protocol.

Connects to Obsidian’s CDP WebSocket endpoint, sends Runtime.evaluate commands, and routes expressions to the correct vault target.

Import:

import { DesktopCdpTransport } from 'obsidian-integration-testing';

Signature:

export class DesktopCdpTransport implements ObsidianTransport

Implements: ObsidianTransport

Constructor

new DesktopCdpTransport(config?: DesktopCdpTransportConfig | undefined)

Creates a new CDP transport.

Properties

PropertyTypeDescription
beginConsoleCapture?() => Promise<ConsoleCaptureHandle | undefined>Begins capturing the target's native console/error stream so a later ObsidianTransport.readConsoleCaptureSince can return everything logged since this call.

Used to surface the *real* plugin-load error when Obsidian swallows it before the harness's loadPlugin monkey-patch sees it (the error then only exists in the renderer/WebView console). Optional and platform-specific: implemented by AppiumTransport (tails adb logcat); absent on DesktopCdpTransport (desktop errors are surfaced in-renderer, and a developer can open DevTools directly).
(Inherited from ObsidianTransport)
captureScreenshot?(params: CaptureScreenshotParams) => Promise<Uint8Array>Captures a PNG screenshot of the running Obsidian instance.

Optional and platform-specific, like the other members here. Implemented by DesktopCdpTransport (CDP Page.captureScreenshot, optionally with the viewport pinned to an exact size) and by AppiumTransport (takeScreenshot, always the device's native framebuffer — the size knobs are ignored, so a mobile capture is sized by choosing an AVD with the wanted screen geometry).
(Inherited from ObsidianTransport)
dispose?() => Promise<void>Disposes of transport resources (e.g. WebSocket connections, Appium sessions).
(Inherited from ObsidianTransport)
disposeSync?() => voidSynchronous disposal for use in process.on('exit') handlers where async work is not possible.

Implementations should perform only synchronous cleanup here (e.g. killing child processes). Async operations like unregistering vaults are skipped.
(Inherited from ObsidianTransport)
evaluate(expression: string, options: TransportEvalOptions) => Promise<string>Evaluates a JavaScript expression string inside Obsidian and returns the raw string result.

The transport normalizes the output — stripping transport-specific prefixes and handling transport-specific errors — so callers receive a clean result string (e.g. a JSON string, or (no output)).
(Inherited from ObsidianTransport)
isMobilefalseIndicates whether this transport is for a mobile platform. Always false for this transport.
preflightCheck(vaultPath: string) => Promise<void>Runs transport-specific preflight checks before evaluation.

For example, the CLI transport verifies that the vault is registered, the CLI is enabled, and the CLI binary is in PATH.
(Inherited from ObsidianTransport)
pushFiles?(vaultPath: string, files: Record<string, Uint8Array>) => Promise<void>Pushes files into a vault directory on the target device.

On desktop this is a no-op (files are written to the local filesystem directly). On mobile this uses the device's file transfer mechanism (e.g. Appium pushFile).
(Inherited from ObsidianTransport)
readConsoleCaptureSince?(handle: ConsoleCaptureHandle | undefined) => Promise<string | undefined>Reads the native console/error output captured since the matching ObsidianTransport.beginConsoleCapture call.

A bounded, post-hoc, failure-path-only dump — not a live monitor.
(Inherited from ObsidianTransport)
registerVault(vaultPath: string) => Promise<void>Registers a vault path so Obsidian can target it.

On desktop: uses Electron IPC to open the vault and polls for readiness. On mobile: pushes only a minimal .obsidian marker so the folder is recognized as a vault, points the app's localStorage at it, and reloads.

It does **not** carry the vault's contents across on either platform — that is ObsidianTransport.pushFiles' job, which TemporaryVault.register runs first. A caller driving a transport directly has to push before registering, or the app opens an empty vault with nothing raised to say so.
(Inherited from ObsidianTransport)
unregisterVault(vaultPath: string) => Promise<void>Unregisters a vault path from the running Obsidian instance.

On desktop: closes the vault window and removes it from the registry. On mobile: removes vault files from the device.
(Inherited from ObsidianTransport)

Methods

MethodReturnsDescription
captureScreenshot(params)Promise<Uint8Array>Captures a PNG screenshot of the Obsidian window showing the given vault.

When a size is requested the viewport is pinned to it with Emulation.setDeviceMetricsOverride for the duration of the capture, so the emitted PNG is exactly that size whatever size the window happens to be — and the override is always cleared afterwards, including when the capture throws, so a failed capture cannot leave the window stuck at the override.
dispose()Promise<void>Disposes of the active WebSocket connection and, in owned-instance mode, kills the owned Obsidian process and removes its isolated user-data directory.

The removal is retried because Windows briefly holds the just-killed process's file handles, which would otherwise fail rmSync with EPERM.
disposeSync()voidSynchronous disposal — kills the owned instance and makes a best-effort removal of its user-data directory. Safe to call from a process exit handler (where async retries are impossible; a leftover temp directory is acceptable).
evaluate(expression, options)Promise<string>Evaluates a JavaScript expression inside Obsidian via CDP Runtime.evaluate.

Routes to the correct vault target based on options.cwd.
getAsarFallback()AsarFallback | undefinedReturns the silent-asar-fallback verdict for this owned instance — whether the app version it is actually running matches the swapped-in pin, or the installer silently reverted to its own bundled asar (read live post-boot). Returns undefined when this is not an owned instance, the instance has not booted yet, or the verdict could not be determined (no asar was swapped, or the live version was unreadable). A 'fallback' verdict reaches this surface only when the throw is disabled (DesktopCdpTransportConfig.shouldThrowOnSilentAsarFallback false); otherwise it throws SilentAsarFallbackError.
getCompatibility()InstallerCompatibility | undefinedReturns the resolved installer↔app compatibility verdict for this owned instance, so callers can assert on it. Returns undefined when this is not an owned instance, or the verdict could not be determined (e.g. an undetectable shell version, or the app version is absent from the table).
getElectronCompatibility()ElectronCompatibility | undefinedReturns the runtime Electron compatibility verdict for this owned instance — whether the Electron version it is actually running is new enough for the running app version (read live post-boot; see ObsidianVersionMetadata.minRecommendedElectronVersion). Returns undefined when this is not an owned instance, the instance has not booted yet, or the verdict could not be determined (the live version was unreadable, or the app version carries no recommended Electron version).
getOwnedInstanceEndpoint()OwnedInstanceEndpoint | undefinedReturns the CDP endpoint of the owned, launched instance so the global setup can hand it to test workers (which then **attach** to it instead of launching their own). Returns undefined when this transport is not an owned instance, or its instance has not been launched yet.
preflightCheck(vaultPath)Promise<void>Verifies that the CDP endpoint is reachable and has Obsidian targets.

If Obsidian is not running, attempts to auto-start it via URI protocol and polls until CDP becomes available.
registerVault(vaultPath)Promise<void>Registers a vault via Electron IPC evaluated through CDP.

Uses an existing Obsidian target to send the vault-open IPC command, then polls until the new vault's target appears.
unregisterVault(vaultPath)Promise<void>Unregisters a vault by destroying its window and removing it from the registry.

Refuses when this transport does not own what it would be tearing down — see shouldTearDownVaultWindow for which of the two ownership flags means what, and why they are not interchangeable.

Links to this page: