> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.doc-detective.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.doc-detective.com/_mcp/server.

# closeSurface

> Close one or more surfaces, such as background processes or browser tabs and windows.

The `closeSurface` action closes one or more surfaces. A surface is anything a step can target: a background process, a browser window or tab, or a [native app surface](/docs/actions/startsurface). `closeSurface` replaces the earlier `stopProcess` action.

For native apps, `{ "closeSurface": { "app": "notepad" } }` ends the app surface, terminating the app if Doc Detective launched it. `{ "closeSurface": { "app": "notepad", "window": -1 } }` closes just one window, a dialog say, and keeps the app open. Window selectors use the shared grammar of title, `/regex/`, and `-1` for the newest window. See [App windows](find#app-windows). Doc Detective refuses to close an app's **last** window and points at the bare form instead. A selector that matches nothing is a no-op.

Provide a surface as the value for the `closeSurface` key. You can identify a surface in any of these ways:

* **String name:** The `name` of the surface.
* **Object:** An object that identifies the surface by type: `{ "process": … }` for a background process, `{ "browser": …, "tab": … }` / `{ "browser": …, "window": … }` for a browser tab or window, or `{ "app": … }` for a native app surface.
* **Array:** A list of names or objects to close several surfaces in one step.

Doc Detective trims leading and trailing whitespace from the surface name before matching.

Closing a surface that isn't open, because it was already closed or never started, always passes. Doc Detective never treats a missing surface as a failure, so you can call `closeSurface` defensively without first checking whether the surface is still open.

You don't have to close every surface explicitly. Doc Detective closes any surfaces that are still open when the run finishes. Use `closeSurface` when you want to close a surface before the run ends, such as to free a port for a later test.

The step records which surfaces it closed and which were already absent in its `outputs`: `closed` and `absent` are arrays of surface names, and `closedCount` and `absentCount` are their counts.

> For comprehensive options, see the [`closeSurface`](/reference/schemas/closesurface) reference.

## Examples

Here are a few ways you might use the `closeSurface` action:

### Close a process by name

This example starts a background server and then closes it by name.

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Start a server in the background.",
          "runShell": {
            "command": "npm start",
            "background": {
              "name": "web",
              "waitUntil": {
                "port": 3000
              }
            }
          }
        },
        {
          "description": "Close the server.",
          "closeSurface": "web"
        }
      ]
    }
  ]
}
```

### Close several surfaces at once

Pass an array of surface identifiers to close more than one surface in a single step.

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Close the web and API servers.",
          "closeSurface": ["web", { "process": "api" }]
        }
      ]
    }
  ]
}
```

### Close a process that might not be running

Because closing an absent surface passes, you can call `closeSurface` defensively without checking first whether the process is still running.

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Close the server if it's still running.",
          "closeSurface": "web"
        }
      ]
    }
  ]
}
```

### Close a browser tab or window

A browser reference with a `tab` selector closes that tab. A `window` selector closes the window and its tabs. Selectors accept a name, an index in creation order (`-1` is the newest), or `{ title, url }` criteria. See [Test across multiple tabs, windows, and browsers](/docs/test-docs/multiple-tabs-and-windows).

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Close the cart tab.",
          "closeSurface": { "browser": "chrome", "tab": "cart" }
        },
        {
          "description": "Close the admin window and all its tabs.",
          "closeSurface": { "browser": "chrome", "window": "admin" }
        },
        {
          "description": "Close the newest tab.",
          "closeSurface": { "browser": "chrome", "tab": -1 }
        }
      ]
    }
  ]
}
```

One guardrail applies. Doc Detective refuses to close the **last open tab** of a browser. Closing a tab isn't how you end a session; closing the **whole browser** is.

### Close a whole browser

A browser reference with no `window`/`tab` selector closes that entire browser session: a bare surface name, an engine keyword, or the `{ "browser": …, "name": … }` object form. Closing a browser that isn't open is a PASS no-op, and the active surface falls back to the most recently focused remaining browser. A browser with an active recording refuses to close until you [`stopRecord`](/docs/actions/record). See [Test across multiple tabs, windows, and browsers](/docs/test-docs/multiple-tabs-and-windows).

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Close the named admin browser.",
          "closeSurface": "admin"
        },
        {
          "description": "Close the chrome browser.",
          "closeSurface": "chrome"
        },
        {
          "description": "Close several surfaces — browsers and processes mix freely.",
          "closeSurface": ["admin", { "browser": "firefox" }, { "process": "web" }]
        }
      ]
    }
  ]
}
```

### Close an app surface

Reference an [app surface](/docs/actions/startsurface) with `{ "app": … }` to close it, or with its bare name. Closing an app surface ends its session, which terminates the app Doc Detective launched.

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Close the Notepad app surface.",
          "closeSurface": { "app": "notepad" }
        }
      ]
    }
  ]
}
```

Window-scoped app closes work on Windows and macOS app surfaces. Android and iOS surfaces are single-window, so a `window` selector fails there. Omit it to close the app.

On Windows, index selectors other than `-1` aren't supported, because the Windows driver can't enumerate an app's windows in creation order. Select by title or `/regex/` instead.