---
title: "How to Test Code Written by Windsurf"
excerpt: "Windsurf's Cascade agent edits across files and runs terminal commands, but it cannot see whether the UI it just changed actually works. This guide covers adding a browser layer through MCP, turning Cascade's verifications into regression tests, and running them in CI."
metaDescription: "Windsurf testing guide: give Cascade a browser through MCP, verify changes in a real app, and turn those verifications into regression tests that run in CI."
publishedAt: 2026-08-03
author: Will
categories:
 - Guides
 - AI Testing
tags:
 - windsurf
 - windsurf-testing
 - windsurf-cascade
 - cascade
 - mcp
 - agent-skills
 - e2e-testing
 - ai-coding-agents
 - browser-testing
 - shiplight-ai
metaTitle: "Windsurf Testing: How to Test Code Written by Cascade"
featuredImage: ./cover.png
featuredImageAlt: "Shiplight blog cover, light gradient, indigo accents, showing a loop diagram from a Windsurf Cascade tile through a browser verification tile to a CI check tile, connected by curved arrows with a green pass badge"
---
To test code written by Windsurf, give its Cascade agent a browser it can drive through MCP, have it verify each change against the running application, and save those verifications as regression tests that run in CI. That is the whole method. The rest of this guide is the mechanics: what Cascade can already check on its own, where its native checks stop, and how to wire the browser layer in so verification happens inside the same session that wrote the code.

The organizing principle is worth stating before any tooling: an agent that edits your code should not be graded on whether the code looks right. It should be graded on whether the application behaves right. Cascade can run your unit tests in the terminal and fix lint errors as it goes, so the first half of that grading is already handled. The second half, opening the app, clicking through the flow that just changed, and confirming the UI does what the prompt asked, is not something an IDE agent does by default. Someone has to close that loop. If it is you, clicking through screens after every Cascade session, you are the slowest step in an otherwise fast pipeline. If it is nobody, you find out about breakage from users.

This guide closes the loop with three moves. First, understand precisely which checks Cascade performs natively, so you do not duplicate them. Second, add browser verification through MCP, which Windsurf supports as a first-class integration. Third, make each verification permanent: a test file in your repo that CI runs on every pull request, so a flow verified once stays verified.

## What Windsurf and Cascade Actually Do

Windsurf is an agentic IDE, originally from the Codeium team and now part of Cognition. Its documentation now lives alongside Cognition's Devin docs, where current builds are presented under the Devin Desktop name, but the agent inside the editor is still called Cascade and the configuration paths still use the windsurf name. If you are still deciding between agentic IDEs, [Windsurf vs Cursor](/blog/windsurf-vs-cursor) covers that comparison; this guide assumes you have picked Windsurf and want to trust what it ships.

Cascade runs in two modes. Code mode creates and modifies files across your codebase; Chat mode answers questions without editing. In Code mode, Cascade plans multi-step tasks, edits multiple files in one pass, executes terminal commands, searches the web, and applies lint fixes to its own output automatically. It persists project knowledge through Memories and Rules, and it extends its toolset in two standard ways: MCP servers, configured through the in-editor marketplace or `~/.codeium/windsurf/mcp_config.json`, and Agent Skills, which are `SKILL.md` procedure files placed in `.windsurf/skills/` in your repo.

Windsurf also ships a Previews feature: the local deployment of your app renders in an editor tab or your browser, and you can click an element or forward a console error straight into Cascade's context as an @-mention. Previews matter for this guide because they are Windsurf's own answer to "did it work?", and the honest section below covers exactly how far that answer goes.

## Why Cascade's Speed Creates a Verification Gap

A Cascade session in Code mode can touch a dozen files in a few minutes: a schema change, the API route that serves it, three components that render it, and the test file it updated along the way. Every one of those edits can pass the checks Cascade runs natively, the type checker, the linter, the unit suite, and the feature can still be broken in the browser.

That is because the failures that survive fast agent edits are mostly integration failures, not logic errors. A component renders fine in isolation but breaks against real API data. A form validates in a unit test but the submit handler was detached during a refactor. A route redirect works except when the user arrives from the changed entry point. None of these are visible in a diff, and none of them fail a unit test that mocks the boundary where the breakage lives.

The gap scales with the tool's speed. When implementation took a day, an hour of manual clicking was proportionate overhead. When Cascade finishes in minutes, manual verification becomes the dominant cost of every change, so it gets skipped, and skipped verification is how agent-written regressions reach production. Whether an agent can be trusted to check its own output is a fair question with a real answer, and we take it up separately in [can coding agents test their own code?](/blog/can-coding-agents-test-their-own-code)

## What Cascade Verifies Natively vs. What Needs a Browser Layer

Be precise about where the gap starts, because Cascade is genuinely strong on the first half of this table:

| Check | Cascade out of the box | With a browser layer added |
|---|---|---|
| Type errors and lint | Yes, with automatic fixes on generated code | No change needed |
| Unit tests | Yes, writes them and runs them in the terminal | No change needed |
| Backend integration tests | Yes, when your test runner covers them | No change needed |
| Build and compile checks | Yes, via terminal commands | No change needed |
| "Does this screen render and behave correctly?" | No. Previews show it to a human; nothing asserts it | Agent drives the flow and asserts the outcome itself |
| Multi-step user journeys (signup, checkout, settings) | No | Agent walks the journey end to end and reports pass or fail |
| Regressions in flows the current task did not touch | No | Saved tests re-run in CI on every pull request |

The dividing line is observation. Everything above it produces a terminal exit code Cascade can read. Everything below it requires operating a browser and judging what happens on screen, which is a different capability from writing code, and the reason [verifying AI-written UI changes](/blog/verify-ai-written-ui-changes) is its own discipline rather than a subset of code review.

## Adding a Browser Layer to Windsurf via MCP

Windsurf's MCP support is the extension point. Cascade natively integrates with MCP servers over stdio, Streamable HTTP, and SSE, and exposes their tools alongside its built-in ones, with a ceiling of 100 tools active at once, so a focused browser server fits comfortably.

Shiplight is our product, so read this section as the worked example from its makers: it installs into Windsurf as a browser MCP server plus skills, no account needed for local use. Add it to `~/.codeium/windsurf/mcp_config.json` (or through the MCP panel in Cascade):

```json
{
  "mcpServers": {
    "shiplight": {
      "command": "npx",
      "args": ["-y", "@shiplight/mcp"]
    }
  }
}
```

With the server active, Cascade gains eyes and hands in a real browser. It can open your running app, navigate to the feature it just changed, fill forms, click through the flow, assert that the expected state appears, and capture screenshots as evidence. The verification happens in the same session that wrote the code, so a failed assertion becomes an immediate fix rather than a bug report next week.

Because Windsurf supports the Agent Skills standard, the procedures install as skills too: a verify skill that checks a UI change in the browser after an edit, a test-generation skill that walks the app and writes the regression suite, and a fix skill that reproduces a failing test and reports an app bug instead of quietly rewriting the test to pass. In Cascade they live under `.windsurf/skills/` and can be invoked by @-mention or picked up automatically when the task matches. The same server-plus-skills setup works in any MCP-capable agent, which is the point of [the browser layer for coding agents](/coding-agents): the verification workflow is portable across whatever agent your team runs, as [adding testing to Cursor, Copilot, and Codex](/blog/add-testing-to-ai-coding-tools-cursor-copilot-codex) shows for the neighbors.

## Turning Verifications into Regression Tests That Run in CI

A verification that lives only in the session transcript protects exactly one change. The durable value comes from saving it. Shiplight captures each verified flow as an intent-based YAML test committed to your repo:

```yaml
goal: Verify checkout completes with a saved card
base_url: http://localhost:3000
statements:
  - URL: /cart
  - intent: Click the "Checkout" button
  - intent: Select the saved card ending in 4242
  - VERIFY: Order confirmation page shows the order number
```

Each step is an intent, not a DOM selector, so when Cascade refactors the component next month, the test self-heals around markup changes instead of breaking, and it transpiles to standard Playwright whenever you want to eject. Prompt for the artifact explicitly: "after verifying the checkout flow, save it as a YAML test in tests/."

Then gate merges on the suite. Cascade sessions end in pull requests, and [running E2E tests in GitHub Actions](/blog/github-actions-e2e-testing) covers the setup: the suite runs on every PR, so a Cascade change that breaks a previously verified flow is flagged before merge, not after deploy. That completes the loop the opening described: implement, verify in the browser, commit the test, let CI hold the line.

## Prompting Patterns That Make Cascade Verify Its Work

Cascade verifies when the prompt makes verification part of the task. Patterns that hold up:

- **Define done as a verified state, not an edit.** "Implement the password reset flow, then verify it in the browser: request a reset, follow the link, set a new password, confirm login works." Not "implement the password reset flow."
- **Scope verification to user journeys.** Ask Cascade to check what the user does, not what the code does. Journey-level checks survive refactors; selector-level checks do not.
- **Ask for the artifact.** "Save the verification as a test" turns a one-time check into permanent coverage. Without that sentence, the verification evaporates when the session ends.
- **On failure, demand a diagnosis before a retry.** "If a step fails, state whether the app or the test is wrong before changing anything" prevents the failure mode where the agent edits the assertion until it passes.
- **Move repeated instructions into a skill or a Rule.** If you paste the same verification paragraph every session, it belongs in `.windsurf/skills/` or your Cascade Rules, where it applies without anyone remembering it.

## When Windsurf's Built-In Checks Are Enough, and When They Are Not

Honest scoping: not every project needs the browser layer on day one.

Cascade's native checks plus Previews are enough when you are prototyping solo and looking at every change anyway, since Previews put the running app one tab away and pipe console errors straight into context. They are enough for backend-only work where the terminal test suite is the whole truth, and for throwaway scripts and internal tools where a regression costs minutes, not customers.

They stop being enough at three thresholds. First, when flows outlive the session that built them: Previews have no memory, so yesterday's verified checkout is unprotected today. Second, when more than one person, or one agent, ships to the same surface, because nobody re-clicks every existing flow after each merge. Third, when Cascade runs long tasks while you are not watching, which is precisely when its speed advantage is largest and a human-in-the-loop preview is not in the loop at all. Previews are a feedback channel for a watching developer; they assert nothing on their own. The moment "someone looked at it" needs to become "something checked it," you need the browser layer and the CI gate.

## Frequently Asked Questions

### Does Windsurf support MCP?

Yes, natively. Cascade connects to MCP servers over stdio, Streamable HTTP, and SSE, configured through the in-editor MCP marketplace or `~/.codeium/windsurf/mcp_config.json`, with tools, resources, and prompts supported and a limit of 100 active tools. That is the mechanism this guide uses to add browser verification.

### Can Windsurf write end-to-end tests?

It can write E2E test code, but by itself it cannot run a browser to observe whether the UI actually behaves, so it is generating tests blind. With a browser MCP server attached, Cascade verifies flows in a real browser first and saves what it observed as regression tests, which is the difference between writing tests and operating them.

### What is Cascade in Windsurf?

Cascade is Windsurf's built-in agent. In Code mode it plans tasks, edits multiple files, runs terminal commands, searches the web, and auto-fixes lint on its own output; Chat mode answers questions without editing. It is extended through MCP servers and Agent Skills.

### Does Windsurf support Agent Skills?

Yes. Cascade follows the SKILL.md standard: workspace skills live in `.windsurf/skills/`, global ones in `~/.codeium/windsurf/skills/`, each with name and description frontmatter. Cascade invokes them automatically when a task matches the description, or manually via @-mention.

### Is the Previews feature the same as testing?

No. Previews renders your local app in an editor tab or browser and lets you send elements and console errors to Cascade, which is excellent feedback for a developer who is watching. It asserts nothing and remembers nothing, so it cannot catch a regression in a flow nobody is currently looking at.

### Do Shiplight's YAML tests lock me into Shiplight?

No. The tests are plain YAML files in your own repo, and they transpile to standard Playwright, so you can eject at any time and keep the suite. Shiplight is built on Playwright, but writing or knowing Playwright is not required to use it.

## Related Reading

- [How to add automated testing to Cursor, Copilot, and Codex](/blog/add-testing-to-ai-coding-tools-cursor-copilot-codex): the same browser-layer setup applied across the other major agents
- [Can coding agents test their own code?](/blog/can-coding-agents-test-their-own-code): the trust question behind agent self-verification
- [How to verify AI-written UI changes](/blog/verify-ai-written-ui-changes): why UI verification is a separate discipline from code review
- [Running E2E tests in GitHub Actions](/blog/github-actions-e2e-testing): the CI half of the loop this guide builds
- [The browser layer for coding agents](/coding-agents): how one MCP server and skill set serves every agent your team runs
- [Cursor testing guide](/blog/cursor-testing-guide): the equivalent walkthrough for Cursor

References: [Windsurf/Devin Desktop documentation](https://docs.devin.ai), Cascade MCP and Agent Skills sections.
