ScreenshotNeo

BlogHow-to

How to Test Salesforce with Cypress: Setup and Configuration

Configure Cypress for apps that use Salesforce, authenticate API requests, handle OAuth redirects, and keep tests reliable with repeatable data.

By the ScreenshotNeo team4 October 202611 min read

Short answer: Configure Cypress for the application you are testing, not for “Salesforce” as a single surface. Set e2e.baseUrl to your app’s controlled test environment, use a Developer Edition org or development sandbox for Salesforce API tests, authenticate API calls with an access token and that org’s instance URL, and use cy.origin() for browser commands on a second origin during OAuth or SSO. Combine a small number of meaningful browser journeys with API setup and assertions for repeatability.

This guide covers custom applications that integrate with Salesforce and browser flows that redirect through Salesforce. Salesforce Multi-Framework UI bundles have their own documented test templates; Salesforce currently describes Vitest/Angular testing and Playwright E2E for those bundles, so do not assume this Cypress recipe covers them. See the Salesforce Multi-Framework testing guide.

1. Decide what Cypress is testing

“Testing Salesforce” can mean several different things. Choose the surface before writing configuration:

Test target What Cypress covers Key setup
Custom app using Salesforce APIs Your app’s user-visible behavior and the app’s integration with a test org Run your app separately; authenticate API calls to the org
Custom app using Salesforce OAuth or SSO The login/consent redirect and the resulting app session Test the real redirect deliberately; use cy.origin() when issuing commands on the Salesforce origin
Salesforce-hosted UI A browser workflow only where you control or have permission to test the target Use an isolated test org and confirm the UI and org policy support the intended automation
Salesforce Multi-Framework UI bundle Its framework-specific unit and end-to-end test setup Follow the Salesforce guide for the bundle rather than assuming Cypress is its documented E2E template

Cypress is intended for testing applications you build and control. Avoid making an external Salesforce site or an org you do not control the foundation of a brittle test suite. See Cypress’s guidance on testing your app.

2. Install Cypress and configure the app URL

Start the application under test outside Cypress, then have Cypress visit it. Cypress recommends managing the application server separately rather than starting a web server inside a test. Install Cypress in the app repository:

npm install --save-dev cypress

Create or update cypress.config.js:

const { defineConfig } = require('cypress');

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
    supportFile: 'cypress/support/e2e.js',
  },
});

Change the port and paths to match your app. baseUrl is the URL Cypress visits for your application; it is not the Salesforce API host. With it configured, cy.visit('/login') resolves against your app. API calls to Salesforce must use the instance URL returned by the authentication flow.

Add scripts in package.json so the server and Cypress run as separate processes. For example, if your app’s existing start script serves the test build:

{
  "scripts": {
    "start:test": "your-existing-app-start-command",
    "cy:open": "cypress open",
    "cy:run": "cypress run"
  }
}

Start npm run start:test in one terminal, then run npm run cy:open or npm run cy:run in another. Replace the placeholder with your app’s actual command. For CI, point baseUrl at the controlled test deployment if it is not running locally.

3. Create a safe Salesforce test environment

Use a dedicated Developer Edition org or development sandbox for API and authentication tests. Salesforce’s REST API quick start uses a Developer Edition org or a development sandbox. Choose based on access, isolation, data policy, and the configuration your integration needs. Do not point repeatable tests at production data.

Use Salesforce CLI to authenticate to the chosen org. The following illustrates the CLI-based flow described in Salesforce’s REST API quick start; the exact command flags can depend on your installed CLI version and org login configuration:

sf org login web --alias cypress-test --instance-url https://login.salesforce.com
sf org display --target-org cypress-test

For a sandbox, use the sandbox login URL appropriate to your setup, commonly https://test.salesforce.com, instead of the production login URL. Confirm the target org in the CLI output before using credentials or creating test data. Salesforce documents this process in its REST API quick start.

Salesforce REST API requests require an access token obtained by authentication, and API calls must go to the org’s instance URL. Treat access and refresh tokens as secrets: do not commit them, print them in CI logs, put them in screenshots, or expose them to browser-side code.

4. Choose how authentication is tested

Use the login route that matches what the test needs to prove:

  • Test the user-facing login journey: drive the browser through the actual app login and OAuth/SSO redirect. Keep this as a focused test because it depends on identity-provider configuration and cross-origin behavior.
  • Set up authenticated state efficiently: obtain a test token through the supported Salesforce CLI/OAuth flow, then seed or inspect state through an API or a Node-side task. This tests integration behavior without repeating the interactive login in every spec.

Salesforce OAuth flows and client configuration depend on the application type and org policy. Use a flow supported by your connected or external client app and follow Salesforce’s current OAuth documentation; do not copy a flow configuration without confirming it applies to your app.

A successful authorization returns tokens. Keep credentials in environment variables or your CI secret store. Cypress can read environment configuration, but values available to browser test code should be treated as exposed to that test runtime. Prefer keeping privileged tokens in Node-side code such as cy.task() where practical.

5. Make authenticated Salesforce API requests

For focused API setup and assertions, use cy.request(). It sends real HTTP requests and lets the test check status, headers, and response data. One practical pattern is to obtain an access token and instance URL outside the browser test, store them as protected CI environment variables, and make the request from Cypress:

// cypress.config.js
const { defineConfig } = require('cypress');

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
  },
  env: {
    salesforceInstanceUrl: process.env.SF_INSTANCE_URL,
    salesforceAccessToken: process.env.SF_ACCESS_TOKEN,
  },
});
// cypress/e2e/salesforce-api.cy.js
describe('Salesforce API integration', () => {
  it('reads an authenticated resource from the test org', () => {
    const instanceUrl = Cypress.env('salesforceInstanceUrl');
    const accessToken = Cypress.env('salesforceAccessToken');

    expect(instanceUrl, 'Salesforce instance URL').to.be.a('string').and.not.be.empty;
    expect(accessToken, 'Salesforce access token').to.be.a('string').and.not.be.empty;

    cy.request({
      method: 'GET',
      url: `${instanceUrl}/services/data/vXX.X/`,
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
      failOnStatusCode: false,
    }).then((response) => {
      expect(response.status).to.eq(200);
      expect(response.body).to.be.an('array');
    });
  });
});

Replace vXX.X with an API version enabled for your org. The root REST resource returns available resources; for an actual application test, request the specific object or endpoint your integration uses and assert the fields and state that matter. Do not hard-code a token in the spec. The environment variable names above are examples; configure their values securely in the local shell or CI.

When the app’s own baseUrl is set, relative cy.request('/api/...') calls target the app. Salesforce requests need the full instance URL and bearer token, as shown. This distinction prevents accidentally directing an org API call to the web app.

6. Handle OAuth redirects and multiple origins

Cypress commands in a test normally stay on one origin. When a browser flow moves from your app to a Salesforce identity origin, wrap commands for the second origin in cy.origin(). Here is a structural example; selectors and page steps must match your org’s actual login screen and policy:

describe('OAuth login redirect', () => {
  it('returns to the app after Salesforce authentication', () => {
    cy.visit('/login');
    cy.get('[data-cy="salesforce-login"]').click();

    cy.origin('https://login.salesforce.com', () => {
      // Use selectors and steps appropriate to the configured test identity flow.
      cy.get('input[name="username"]').type(Cypress.env('sfUsername'));
      cy.get('input[name="password"]').type(Cypress.env('sfPassword'), { log: false });
      cy.get('input[name="Login"]').click();
    });

    cy.url().should('include', '/dashboard');
  });
});

This example is not a universal Salesforce login script. MFA, SSO, identity-provider pages, consent screens, page markup, and security policy vary. Use the correct origin for the flow, and keep the test limited to an account and environment explicitly set up for automated testing. Cypress documents the cy.origin() command. Cypress does not support cross-origin iframe automation; if the flow depends on a cross-origin iframe, redesign the test boundary or validate the behavior through an API or supported integration seam.

7. Combine browser tests with deterministic state

Use browser tests for outcomes a user sees and direct API requests for setup, contract checks, permission cases, and persisted state. Seed and reset data through supported test endpoints or Node-side cy.task() functions. Avoid tests that rely on records left by a previous run, real customer data, or org-wide mutable assumptions.

Test the login flow end to end where the login flow itself matters. For most authenticated app tests, use a reusable login command and cy.session() so the browser context can be reused and validated:

// cypress/support/commands.js
Cypress.Commands.add('login', (username, password) => {
  cy.session([username], () => {
    cy.visit('/login');
    cy.get('[name="username"]').type(username);
    cy.get('[name="password"]').type(password, { log: false });
    cy.get('button[type="submit"]').click();
    cy.url().should('include', '/dashboard');
  }, {
    validate() {
      cy.visit('/dashboard');
      cy.get('[data-cy="account-menu"]').should('be.visible');
    },
  });
});

Adapt the selectors and authentication route to your app. If the app stores session state differently, write a setup callback that establishes that state safely. Session caching reduces repeated login work, but validation matters: it catches expired or invalid cached sessions instead of allowing later assertions to fail mysteriously.

8. Keep the suite fast and reliable

  • Run the app and point baseUrl at a controlled environment with stable network access.
  • Keep the test org separate from production and make data setup idempotent: a rerun should create or reset the same test conditions.
  • Use API setup for records that are not the subject of the browser journey; reserve UI creation for tests whose purpose is to verify that workflow.
  • Use a small number of browser tests for critical user journeys and more direct API tests for specific backend behavior. API requests generally avoid browser rendering and give more focused failures.
  • Use cy.session() for reusable browser context, with an explicit validation step.
  • Set request timeouts and retries deliberately based on your controlled environment. A retry can help with transient infrastructure failures, but it cannot fix a deterministic selector, permission, or data problem.
  • Keep authentication secrets out of source control and logs. Avoid logging response headers containing tokens.
  • Use separate test identities or controlled data when concurrent jobs could otherwise update the same records.

Reliability comes primarily from controlling the app, org, identity configuration, and data. Tests against a service or Salesforce org your team does not control can be blocked by policy changes, MFA, throttling, page changes, or external availability. Cypress and Salesforce behavior can evolve, so verify current docs against the versions and org setup in use.

9. Troubleshooting common failures

Symptom Likely cause Fix
cy.visit('/...') cannot connect The app is not running, the port is wrong, or baseUrl points to another environment Start the test app separately, confirm its URL in a browser, and align e2e.baseUrl with that URL.
Salesforce API responds 401 Missing, expired, or wrong-org access token; malformed bearer header Authenticate again through the supported flow, use the matching instance URL, and send Authorization: Bearer TOKEN.
Salesforce API responds 403 The identity lacks permission, the app is not authorized for the requested operation, or org policy blocks it Check the test user’s permissions and the client app’s allowed OAuth configuration. Do not try to bypass org policy.
API request hits the app instead of Salesforce A relative URL resolved through Cypress baseUrl Use the full org instance URL for Salesforce API requests.
OAuth test fails after redirect Commands crossed origins without cy.origin(), or the test assumes a universal login page Wrap second-origin commands with the exact origin and adjust for the configured identity provider and test account flow.
Login automation stops at MFA or SSO The organization’s identity policy requires an interactive or external step Use an approved test identity flow; test the app integration through a supported API or controlled seam when full browser automation is not permitted.
Element not found on Salesforce-hosted page Markup, page timing, localization, or application surface differs from assumptions Confirm the target is controlled, wait on a meaningful state, and use stable selectors where the application allows them.
Tests pass alone but fail in a suite Shared mutable records, stale session state, or ordering assumptions Reset/seed each test’s data, validate cached sessions, and remove dependencies on prior tests.
Cross-origin iframe commands fail Cypress does not support automating cross-origin iframes Move the assertion to an API or supported app boundary, or redesign the flow to avoid that unsupported interaction.

10. Or skip the browser setup

If the task is to capture a clean screenshot of a page in your test workflow, ScreenshotNeo provides a website screenshot API and MCP server. A single GET request returns a PNG, JPEG, WebP, or PDF. For example:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for the request options. ScreenshotNeo accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies page verdict and billing status in headers. Its MCP server gives AI agents tools named take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots.

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

11. FAQ

Does Cypress test Salesforce itself?

Cypress can test a controlled browser surface and make authenticated HTTP requests, but the right setup depends on whether the target is your integration app, an OAuth login, or a Salesforce-hosted UI. It is not a universal Salesforce platform test harness.

Should I use a sandbox or Developer Edition org?

Either can be suitable for development tests. Choose the environment that provides the needed configuration and access with appropriate data isolation.

Can I skip the browser login in every test?

You can establish authenticated state programmatically for tests that do not aim to verify the login journey. Keep a focused end-to-end login test when that flow is part of the behavior you need to protect.

Is baseUrl the Salesforce URL?

Usually not. Set it to the app Cypress visits. Use the authenticated instance URL separately for Salesforce REST API calls.

What if my target is a Multi-Framework UI bundle?

Check Salesforce’s bundle-specific testing guide, which describes its template choices. Do not assume the integration-app Cypress setup applies to that product surface.

Official references