Understanding the Cypress Server's Role in Test Execution

The Cypress server is a full-stack Node.js orchestrator that creates an HTTP server, proxies network traffic, handles cross-origin communication, and drives the browser via socket connections to provide a deterministic test environment.

The cypress-io/cypress repository implements a sophisticated server architecture that powers end-to-end testing. The Cypress server operates as a full-stack Node.js application living in the @packages/server package, coordinating everything from serving test files to intercepting network requests and managing browser communication through a tightly coupled stack of specialized components.

Core Server Architecture

The server architecture centers on a small set of core classes that work together to provide deterministic control over the application under test (AUT).

ServerBase - The Central Orchestrator

The ServerBase<TSocket> class in packages/server/lib/server-base.ts serves as the central orchestrator. It creates the HTTP server, file server, and optional HTTPS proxy, while also owning the socket that communicates with the Cypress driver and the remote-state manager that tracks ports and URLs.

When Cypress starts, the ServerBase instance performs the initialization sequence:

  1. Creates an Express app
  2. Instantiates the HTTP server via this._createHttpServer(app)
  3. Attaches socket.io for driver communication (this.server.on('upgrade', …))
  4. Starts the file server (fileServer.create) for fixtures and screenshots
  5. Optionally creates an HTTPS proxy to handle Chrome's automatic HTTPS upgrades
  6. Begins listening on the configured port via this._listen(port)

NetworkRuntime and Proxy Infrastructure

The NetworkRuntime (exposed via createProxyRuntime in packages/server/lib/network-runtime.ts) sets up the NetworkProxy from @packages/proxy together with net-stubbing state, network-policy registration, and the interception core. This layer enables cy.intercept, automatic handling of redirects, and credential forwarding.

All outbound HTTP requests that the application under test makes flow through this NetworkProxy, which intercepts requests via the handleHttpRequest hook, applies Cypress-defined stubbing rules by consulting the NetStubbingState, and injects cookies and Chrome-specific headers.

Request Handling Wrapper

The Request class in packages/server/lib/request.ts provides a thin wrapper around @cypress/request that adds Cypress-specific defaults including keep-alive headers (Connection: keep-alive), TLS trust configuration, and retry logic for network failures. It also serializes request/response data for the driver using the pick method.

Server Initialization and Boot Sequence

From CLI to HTTP Server

The entry point in packages/server/lib/cypress.ts provides the CLI wrapper that parses arguments and boots the server. When cypress start executes, the Cypress.start function creates a new ServerBase instance and calls createServer to spin up the main HTTP server:

// Inside cypress.ts → start()
await server.createServer(app, config, onWarning)

The ServerBase.createServer method (see lines 62-94 of server-base.ts) performs the initialization steps. When a baseUrl is supplied, the server validates that the URL is reachable or emits a warning to the user.

You can also start the server programmatically:

import { ServerBase } from '@packages/server/lib/server-base'
import express from 'express'

async function launchServer() {
  const app = express()
  const server = new ServerBase({/* config */})

  // Create and start the HTTP server
  await server.createServer(app, config, onWarning)

  console.log(`Cypress server listening on ${await server._port()}`)
}
launchServer()

Routing and Control Endpoints

The Routes module in packages/server/lib/routes.ts (specifically createCommonRoutes) wires up Express endpoints for Cypress-specific functionality. Key routes include:

  • /<namespace>/tests – Serves test files to the runner
  • /socket.io.js – Serves the Socket.io client for driver-server communication
  • /__cypress-studio/* – Exposes internal Studio APIs to child processes

A special middleware (lines 70-100 of routes.ts) detects when Chrome automatically upgrades an http: request to https: and replies with a 301 redirect back to the original http: URL. This prevents the "Chrome HTTPS-upgrade loop" (issue #25891) that would otherwise cause infinite redirects during test execution.

Network Traffic Management

Intercepting Requests with NetworkProxy

The NetworkProxy sits between the browser and external network, enabling deterministic control over all traffic. Here is how cy.intercept works internally:

import { createProxyRuntime } from '@packages/server/lib/network-runtime'

const runtime = createProxyRuntime({
  config,
  remoteStates,
  getFileServerToken,
  getCookieJar,
  socket,
  request: new Request(),
  serverBus,
  getCurrentBrowser,
})

// Example: a stub for GET /api/users
runtime.networkProxy.addRequestHandler({
  method: 'GET',
  url: '/api/users',
  handler: (req, res) => {
    res.statusCode = 200
    res.body = [{ id: 1, name: 'Alice' }]
  },
})

The proxy handles request serialization, redirect chains, and credential forwarding while maintaining the stubbing state that makes cy.intercept possible.

Cross-Origin Communication and Socket Bridge

Socket-Based Driver Communication

ServerBase creates either a SocketE2E (for end-to-end testing) or SocketCt (for component testing) instance exposed via this.socket. This socket layer bridges the test runner (Node) and the browser (driver), forwarding commands (cy.*) and emitting events such as cross-origin cookies and protocol manager updates.

The server manages cross-origin cookie synchronization through socket events:

// Cross-origin cookie sync (simplified)
server.socket.localBus.on('cross:origin:cookies:received', () => {
  // driver notifies server that cookies have been set
  server._eventBus.emit('cross:origin:cookies:received')
})

// The server forwards the cookie data to the driver
server.socket.toDriver('cross:origin:cookies', cookies)

This mechanism ensures that cookies set across different origins during test execution are properly tracked and synchronized between the browser and the Node server.

Lifecycle Management and Cleanup

When a spec finishes execution, ServerBase calls reset on the NetworkProxy to clear the net-stubbing state, shuts down the file server, and prepares for the next test file. Graceful shutdown handling is provided by utilities like graceful-exit.ts and graceful-crash-handling.ts in the server package.

Summary

  • ServerBase in packages/server/lib/server-base.ts orchestrates the HTTP server, file server, HTTPS proxy, and socket communication.
  • createProxyRuntime in packages/server/lib/network-runtime.ts initializes the NetworkProxy that enables cy.intercept and traffic interception.
  • Request in packages/server/lib/request.ts wraps HTTP calls with keep-alive, retry logic, and serialization for the driver.
  • createCommonRoutes in packages/server/lib/routes.ts defines control endpoints and fixes Chrome HTTPS-upgrade loops.
  • The socket layer bridges Node and the browser, handling cross-origin cookie sync and command forwarding.
  • The server provides deterministic control over the AUT by proxying all network traffic and managing the browser lifecycle.

Frequently Asked Questions

What does the Cypress server do during test execution?

The Cypress server creates a full-stack Node.js environment that serves test files, proxies all network traffic from the browser, intercepts requests for stubbing via cy.intercept, and manages cross-origin communication through a socket bridge. It runs in the @packages/server package and coordinates with the browser driver to execute commands and collect results.

How does Cypress handle network interception?

Cypress routes all outbound application traffic through the NetworkProxy (initialized via createProxyRuntime in packages/server/lib/network-runtime.ts). This proxy intercepts requests using the handleHttpRequest hook, applies rules from the NetStubbingState, and injects authentication headers before forwarding requests to the actual destination.

Why does Cypress need an HTTPS proxy?

The HTTPS proxy handles Chrome's automatic HTTPS upgrade behavior. When Chrome upgrades an http: URL to https: automatically, the proxy (configured in ServerBase) rewrites these requests back to the HTTP server. The routes middleware in packages/server/lib/routes.ts (lines 70-100) also implements a 301 redirect fix to prevent infinite loops during these upgrades.

How does the server communicate with the browser?

The server uses Socket.io via the SocketE2E or SocketCt classes created by ServerBase. This socket connection forwards commands from the Node runner to the browser driver and emits events back to the server, including cross-origin cookie updates and request lifecycle events. The socket attaches to the HTTP server during the upgrade event in createServer.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →