Transport modes
The transport determines how the library talks to Obsidian. Configure it through your runner’s transport options (see Getting started).
| Type | Platform | Mechanism |
|---|---|---|
obsidian-cdp (default) | Desktop | Obsidian Chrome DevTools Protocol (CDP) |
obsidian-android-appium | Mobile | Obsidian Android Appium WebView injection |
This guide covers the desktop CDP transport; the mobile one has its own
Android testing guide.
The owned CDP instance
Section titled “The owned CDP instance”By default the library launches and owns an isolated Obsidian instance in a temporary
--user-data-dir on a free --remote-debugging-port, and talks to it over CDP. The owned instance
never touches your real Obsidian — config, vault registry, running window and auto-update are all left
alone — and it runs in parallel with your everyday Obsidian.
Nothing needs configuring; the owned CDP instance is the default:
export default defineConfig({ test: { fileParallelism: false, globalSetup: ['obsidian-integration-testing/vitest-global-setup-plugin'] }});Pin an Obsidian version
Section titled “Pin an Obsidian version”To run against a specific Obsidian version, set obsidianVersion and/or obsidianInstallerVersion. Each
accepts an explicit 'x.y.z', 'public-latest', or 'catalyst-latest'. Downloaded asars and installer
shells are cached under the system temp directory for reuse.
environmentOptions: { obsidianTransport: { type: 'obsidian-cdp', // The Obsidian app version (asar). At or above the installed shell version // it is applied as a fast asar swap; an older version transparently // downloads the matching installer. obsidianVersion: '1.8.10' }}obsidianVersionpins the app code (asar). When omitted, the owned instance runs the same version your installed Obsidian currently runs.obsidianInstallerVersionpins the Electron shell (installer build), downloaded and extracted from the matching GitHub release. Windows installers require 7-Zip onPATH. Public releases only — catalyst and beta builds have no public installer, so a catalyst version can only be pinned at the asar level.
To run the whole suite across the supported range instead of one pinned version, see Version matrix.
Dead-boot fast-fail
Section titled “Dead-boot fast-fail”If you pin an app version that cannot run on the launched Electron shell — an obsidianInstallerVersion
too old for the obsidianVersion — Obsidian loads a black screen: the renderer finishes loading but the
app never bootstraps (empty <body>, no window.app). Rather than waiting out the full readiness
timeout, the harness detects this terminal state and throws a RendererFailedToInitializeError as
soon as it has held for a short grace window:
import { RendererFailedToInitializeError } from 'obsidian-integration-testing';
try { // ... register a vault against an incompatible version pair} catch (error) { if (error instanceof RendererFailedToInitializeError) { // The installer/Electron version is too old for this Obsidian app version. }}deadBootGraceInMilliseconds(default10000) — how long the renderer must sit in the dead state (documentcomplete, empty<body>, nowindow.app) before fast-failing. The grace clock starts when the renderer first reportsreadyState: 'complete', so a slow-but-valid boot is never misjudged. Set0to disable the fast-fail and restore the plain wait-out-the-readiness-timeout behavior. Owned mode only; ignored when attaching.
Window visibility
Section titled “Window visibility”By default the owned Obsidian window is shown. Integration setup explicitly hides its owned window so test runs do not steal focus:
environmentOptions: { obsidianTransport: { type: 'obsidian-cdp', isObsidianAppVisible: false // hide the window for this run }}isObsidianAppVisible(defaulttrue) — whenfalse, the harness launches the owned instance with keep-alive Chromium flags and moves its window off-screen once Electron’s remote bridge is up. Off-screen (not minimized) keeps the renderer fully live, sosetTimeout,requestAnimationFrame,:hoverand trusted keyboard/pointer input behave exactly as they would for a visible window — tests are unaffected. Set it explicitly tofalsein any automated run that should not show a window. Ignored when attaching: the harness never moves your own running Obsidian.
Attach to a running Obsidian
Section titled “Attach to a running Obsidian”To attach to an already-running Obsidian instead of owning one, launch Obsidian with
--remote-debugging-port=<port> and set port to that same port. The version-pinning options do not
apply in attach mode.
# Windows (PowerShell) — uses Obsidian from PATH (e.g. scoop), falling back to the installer location$obsidian = (Get-Command Obsidian.exe -ErrorAction SilentlyContinue).Sourceif (-not $obsidian) { $obsidian = "$env:LOCALAPPDATA\Programs\Obsidian\Obsidian.exe" }Start-Process $obsidian -ArgumentList '--remote-debugging-port=8315'environmentOptions: { obsidianTransport: { type: 'obsidian-cdp', port: 8315, // must match the --remote-debugging-port Obsidian was launched with
// default values can be omitted host: 'localhost', commandTimeoutInMilliseconds: 30000 }}Run several platforms from one config
Section titled “Run several platforms from one config”Vitest projects let the same tests run on both transports:
import { defineConfig } from 'vitest/config';
export default defineConfig({ test: { projects: [ { test: { name: 'integration-tests:desktop-cdp', fileParallelism: false, globalSetup: ['obsidian-integration-testing/vitest-global-setup-plugin'], include: ['src/**/*.integration.test.ts'], exclude: ['src/**/*.android.integration.test.ts'], // default transport, can be omitted environmentOptions: { obsidianTransport: { type: 'obsidian-cdp' } } } }, { test: { name: 'integration-tests:android-appium', fileParallelism: false, globalSetup: ['obsidian-integration-testing/vitest-global-setup-plugin'], include: ['src/**/*.android.integration.test.ts'], environmentOptions: { obsidianTransport: { type: 'obsidian-android-appium', appiumUrl: 'http://localhost:4723', avdName: 'obsidian_test' } } } } ] }});# All testsnpx vitest run
# Desktop CDP onlynpx vitest run --project integration-tests:desktop-cdp
# Android only (requires Appium + emulator running)npx vitest run --project integration-tests:android-appium
# All platformsnpx vitest run --project integration-tests:*Related
Section titled “Related”ObsidianCdpTransportOptionsAPI referenceRendererFailedToInitializeErrorAPI reference- Ad-hoc debugging — the same knobs outside a test run.