Persistent Debug Session

Leave the AUT open after a run, and reconnect to that same live instance next time — without blocking the test runner.

← Back to overview · 🇩🇪 Deutsch · ← Run and Debug · Enable Self-Healing →


What it does

By default, every run starts a fresh browser (or Electron app) and closes it again when the run ends. A persistent debug session changes that for local debugging: the AUT stays open after the run finishes, and the next run reconnects to that same live instance instead of relaunching it — picking up in whatever state the previous run left it in (same page, same login, same form state).

The first run with the feature enabled launches the AUT as its own, independent process and then exits normally — your terminal gets its prompt back immediately, nothing blocks. Every following run detects the still-open instance and attaches to it over the Chrome DevTools Protocol (CDP) instead of starting a new one.

💡 Why this is useful. Iterating on a flaky or half-written TestCase usually means: run test, watch it fail, tweak a locator, run test again, wait for the whole app to boot again, click back to the same screen by hand, run test again… A persistent debug session removes the “boot the app and navigate back” tax from that loop — the app is already sitting exactly where the last run left it.


Enable it

Two equivalent ways, following the same priority chain as Self-Healing: an environment variable, when set, always wins over the config file, which wins over the default (off).

Environment variable — the literal string true enables it; any other value, including the literal string false, explicitly disables it (and overrides a config file that enables it):

export CC_DEBUG_SESSION=true

Config file — add debugSession as an additional top-level key in .cc-testframework.local.json at your project’s root (pm/), alongside any existing selfHealing settings that file might already hold:

{
  "schemaVersion": 1,
  "debugSession": true
}

There is no dedicated CLI setter for this key (unlike npx cc-testframework config self-healing enable) — create or edit the file directly. It holds no secrets, but it’s a personal, local runtime preference — add it to your project’s .gitignore if you haven’t already (the shipped template does this for you).

Off by default: with neither the environment variable nor the config key set, every run behaves exactly as it does today — a managed browser (or Electron app) that starts fresh and closes at the end of the run.


Lifecycle: launch once, reconnect every time after

# Run 1 — no session recorded yet: launches the AUT detached, then attaches to it.
# The runner exits normally; the AUT keeps running.
CC_DEBUG_SESSION=true npx playwright test 3_Cases/TC_YourTest.spec.ts --workers=1

# Run 2 — a live session is recorded: reconnects instead of relaunching.
# The page is exactly as run 1 left it.
CC_DEBUG_SESSION=true npx playwright test 3_Cases/TC_YourTest.spec.ts --workers=1

A reconnect prints a line like this to the console, so you always know which path a run took:

[DebugSession] Reconnected to existing session (pid 41822, endpoint http://127.0.0.1:9222).

If you close the window yourself (or the process otherwise dies) between runs, the next run detects the recorded session is no longer reachable, discards it, and launches a fresh one — you never have to clean anything up by hand for that case.

💡 Single instance, single worker. Only one persistent session is tracked at a time. Running two debug-session-enabled Playwright workers in parallel — or debugging a second, different App while the first one’s session is still alive — is not supported yet; the second run reconnects to the first App’s instance instead of starting its own. Pass --workers=1 while a debug session is enabled.


Manage the session from the command line

npx cc-testframework session status
npx cc-testframework session close

status reports whether a session is recorded and whether it’s still reachable:

$ npx cc-testframework session status
Debug session: LIVE
  kind:      web
  endpoint:  http://127.0.0.1:9222
  pid:       41822
  startedAt: 2026-08-12T09:14:03.000Z
STATUS=live ENDPOINT=http://127.0.0.1:9222 PID=41822 KIND=web

The last line is a single machine-parseable summary, alongside the human-readable block above it, for a script or another tool to check without parsing the formatted text.

close stops the persistent AUT and clears the recorded session — the next debug-session-enabled run then starts fresh:

$ npx cc-testframework session close
Closed the persistent debug session (pid 41822, endpoint http://127.0.0.1:9222).
STATUS=closed

Both commands are safe to run when no session is recorded, and safe to run twice in a row.


Explicit Close in a debug session

While a debug session is active, an explicit TS_Execution_Close step inside a TestCase does end it — for either a Web app or an Electron app, since both use the same plain step name (see Add a New App — Register an Electron app): it kills the detached AUT process and clears the recorded session, exactly like npx cc-testframework session close (see above) — in fact it’s the same teardown under the hood. A TestCase that ends with a Close step does not persist; the next run starts a fresh instance rather than reconnecting.

This is the opposite of how a regular (non-debug-session) close() behaves — normally it’s a soft, logical close (Web: navigate to about:blank; the underlying browser stays open for the rest of the run). In debug-session mode it becomes a real, explicit teardown instead, because “I called Close” is the clearest signal a tester can give that they’re done debugging.

To keep the reconnect workflow going across runs, omit the Close step from the TestCase — this is how the feature is meant to be used day-to-day: run, inspect, tweak, run again, and only add a Close step (or call npx cc-testframework session close from the terminal) once you’re genuinely finished and want the AUT to go away.


Web and Electron

Both Web (Chromium) and Electron Apps support a persistent debug session — see Add a New App — Register an Electron app for how an Electron App is registered in the first place.

Electron caveat. A reconnected Electron session is driven entirely over CDP, the same way a reconnected Web session is — every Control and TestStep that operates on the renderer DOM works unchanged. Playwright’s separate Electron main-process API (electronApp.evaluate(...) and similar) is not available on a reconnected instance, since that API requires the original, in-process _electron.launch() handle. If a TestStep needs main-process access, it needs a managed (non-debug-session) run.


Never enable this in CI

A persistent debug session is a local debugging aid, not a CI setting. Enabling it in CI leaves a detached AUT process running on the CI runner after the job finishes — nothing tears it down automatically, since that’s the entire point of the feature for local use. Keep CC_DEBUG_SESSION unset (or explicitly false) in CI, and don’t check a debugSession: true config file into a shared repo without confirming CI doesn’t pick it up.


Where the state lives

  • .cc-testframework-session.local.json, at your project’s root (pm/) — the recorded session (endpoint, process id, kind, start time). Git-ignored by the shipped template.
  • .cc-testframework/, also at your project’s root — the persistent browser profile (cookies, local storage) for a detached Web session, so login state survives across runs too. Also git-ignored.

Neither file needs to be committed or shared — they describe a single local process on your own machine.


Where to go next


📧 Questions? Contact: jens.szelag@itsbusiness.ch

itsbusiness AG · Bern · Switzerland