Skip to content

test(cypress): register intercept response rewrites as response events - #42327

Open
wyattwalter wants to merge 1 commit into
releasefrom
ww-flake/intercept-response-abort
Open

wyattwalter wants to merge 1 commit into
releasefrom
ww-flake/intercept-response-abort

Conversation

@wyattwalter

@wyattwalter wyattwalter commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Description

getConsolidatedDataApi registers, for every test, a cy.intercept on GET /api/v1/consolidated-api/*?* that rewrites the response through req.reply((res) => ...). Cypress treats a request with that kind of response callback as one the test is waiting on. When the browser aborts the request while its response is still arriving, which is what cy.visit, cy.reload and in-app navigation do to any request in flight, Cypress fails the running test or hook with a network error that names no spec code.

This change registers the same rewrites with req.on("response", ...) followed by req.continue(), through one helper, rewriteUpstreamResponse. No error is filtered and no assertion changes:

  • A completed response is rewritten exactly as before.
  • req.continue() still stops propagation, so the most recent intercept on a route still wins.
  • An aborted request is dropped, the way every request without a response callback already is. A request that really fails still breaks the page, and the test fails at its next assertion.

Evidence, first-attempt logs of the scheduled release image test

Four retry events in 3 of the last 9 enterprise runs, none in 8 community runs. Each has a navigation command immediately before the error and recovers when the spec is repeated alone:

Run (enterprise repository) Date Shard Spec What preceded the error
36368107963 2026-09-28 41 ME_CustomEnv_spec.ts, before all a page reload
36657696691 2026-09-30 11 Audit_logs_EEAccess_spec.js, test 2 cy.reload() then cy.visit()
36657696691 2026-09-30 38 FrameworkFunctions_NavigateToFunctions_spec.ts, test 3 in-app navigateTo
36804072608 2026-10-01 11 Audit_logs_EEAccess_spec.js, test 2 cy.reload() then cy.visit()

Mechanism, read from the Cypress 13.13.0 driver

  • req.reply(callback) and req.continue(callback) subscribe the callback as response:callback. req.on("response", callback) subscribes it as response. Both run through the same response handler, so res.send(...) behaves the same in either.
  • On a network error the driver throws into the running test only when the request has a response:callback subscription and no response has been handed to it yet.
  • The blanket Cypress.on("uncaught:exception", () => false) in support/e2e.js does not apply: Cypress consults those listeners only for errors raised in the application frame, and this one is raised in the spec frame.

Reproduced outside the suite

A standalone spec on Cypress 13.13.0 against a local HTTP server whose endpoint sends headers and part of the body, then stalls. The test starts a fetch, then navigates with cy.visit.

Case Result
req.reply(callback), navigation mid-response fails with the same error as the scheduled runs
the same, plus an uncaught:exception handler returning false still fails
req.on("response", callback) + req.continue(), same navigation passes
req.on("response", callback) + req.continue(), completed response body is rewritten; cy.wait("@alias") yields the rewritten body
two intercepts on one route, either form only the most recent rewrite applies

A request aborted before any response byte arrives does not trigger the error in either form, which is why the failure is intermittent in the suite.

Repro spec and server
// server.js
const http = require("http");
const body = () => JSON.stringify({ data: { featureFlags: { data: { server_flag: true } }, other: "kept" } });
http.createServer((req, res) => {
  const url = req.url.split("?")[0];
  if (url === "/slow") {
    const b = body();
    res.writeHead(200, { "content-type": "application/json" });
    res.write(b.slice(0, 20));
    setTimeout(() => res.end(b.slice(20)), 4000);
  } else if (url === "/fast") {
    res.writeHead(200, { "content-type": "application/json" });
    res.end(body());
  } else {
    res.writeHead(200, { "content-type": "text/html" });
    res.end("<html><body><h1>page</h1></body></html>");
  }
}).listen(3111);
// abort.cy.js
const rewrite = (flags) => (res) => {
  const updated = JSON.parse(JSON.stringify(res.body));
  updated.data.featureFlags.data = { ...flags };
  return res.send(updated);
};

const abortByNavigation = () => {
  cy.visit("/");
  cy.window().then((win) => {
    win.fetch("/slow?x=1");
  });
  cy.wait(500);
  cy.visit("/?second");
  cy.wait(1500);
  cy.get("h1").should("have.text", "page");
};

it("req.reply(callback): the abort fails the test", () => {
  cy.intercept("GET", "/slow?*", (req) => {
    req.reply(rewrite({ a: true }));
  });
  abortByNavigation();
});

it("req.on('response') + req.continue(): the abort does not fail the test", () => {
  cy.intercept("GET", "/slow?*", (req) => {
    req.on("response", rewrite({ a: true }));
    req.continue();
  });
  abortByNavigation();
});

What the CI run on this PR can and cannot show

Every test in the suite goes through the consolidated-api rewrite, so a green @tag.All run shows the rewrites still apply everywhere. It cannot show that the retries are gone, because the abort depends on request timing. That is read from the scheduled runs after merge: the error should stop appearing in first-attempt logs.

One path is new: a test that calls cy.wait("@getConsolidatedData") after its own navigation aborted a consolidated-api request can now be handed that aborted request by the wait. Before this change the same test had already failed at the abort.

Call sites checked

Every cy.intercept handler under app/client/cypress that passes a callback to req.reply or req.continue:

Site Route Registered In this PR
FeatureFlags.ts, getConsolidatedDataApi consolidated-api every test, through featureFlagIntercept yes
FeatureFlags.ts, featureFlagIntercept with preserveOtherFlags users/features Anvil and AI tests yes
FeatureFlags.ts, featureFlagInterceptForLicenseFlags (2) users/features, consolidated-api specs that call it yes
commands.js, startServerAndRoutes product-alert/alert every test yes
LicenseCommands.js (2) license API, consolidated-api enterprise repository only no, the file does not exist here; it follows there once this change has synced

prettier and eslint (the cypress/.eslintrc.json config) are clean on both files, and the helper type-checks against the Cypress 13.13.0 typings.

Fixes https://linear.app/appsmith/issue/APP-16069

Automation

/ok-to-test tags="@tag.All"

🤖 Generated with Claude Code

Tip

🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/36982861836
Commit: 375a9cc
Cypress dashboard.
Tags: @tag.All
Spec:


Fri, 02 Oct 2026 08:57:20 UTC

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of intercepted feature-flag and product-alert responses while preserving their existing response behavior.

An intercept whose handler calls req.reply(callback) or
req.continue(callback) makes Cypress fail the running test or hook when
the browser aborts that request mid-response. cy.visit, cy.reload and
in-app navigation do that to any request still in flight, and
getConsolidatedDataApi registers such a handler on the consolidated-api
route for every test.

Register the rewrites with req.on("response") followed by req.continue()
through one helper. A completed response is rewritten exactly as before
and the most recent intercept on a route still wins; an aborted request
is dropped instead of failing a test that did not wait on it.

Covers the five response-callback intercepts in the shared support code:
four in FeatureFlags.ts and the product-alert intercept in commands.js.

https://linear.app/appsmith/issue/APP-16069

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: appsmithorg/appsmith/.coderabbit.yaml

Review profile: CHILL

Plan: Essentials

Run ID: 02a2cfcb-8261-4959-9f7c-73886e421b10

📥 Commits

Reviewing files that changed from the base of the PR and between cb181e3 and 375a9cc.

📒 Files selected for processing (2)
  • app/client/cypress/support/Objects/FeatureFlags.ts
  • app/client/cypress/support/commands.js

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


Walkthrough

Cypress support code adds rewriteUpstreamResponse to register response handlers and continue requests upstream. Existing feature-flag and product-alert intercepts use the helper. Their response-rewriting logic remains unchanged.

Changes

Upstream response rewriting

Layer / File(s) Summary
Add the response helper
app/client/cypress/support/Objects/FeatureFlags.ts
Adds a typed helper that registers a response handler and continues the request upstream.
Update existing intercepts
app/client/cypress/support/Objects/FeatureFlags.ts, app/client/cypress/support/commands.js
Feature-flag and product-alert intercepts use the helper. Their response-rewriting logic remains unchanged.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: subrata71

Merge Risk: ⚪ Minimal · up to 375a9

This test-support change preserves completed-response rewrites while allowing aborted requests to avoid failing unrelated tests. No actionable merge-blocking risk is established.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: registering Cypress intercept response rewrites as response events.
Description check ✅ Passed The description is detailed and covers the motivation, implementation, scope, testing evidence, limitations, affected call sites, and issue reference. The template's explicit validation checkbox and C…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Requests travel upstream, then replies return.
A handler waits for the response.
Feature flags keep their rewrite.
Product alerts keep theirs, too.
Cypress follows the new route.

Comment @coderabbitai help to get the list of available commands.

@linear-code

linear-code Bot commented Oct 2, 2026

Copy link
Copy Markdown

APP-16069

@wyattwalter wyattwalter added the ok-to-test Required label for CI label Oct 2, 2026
@wyattwalter

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@wyattwalter
wyattwalter marked this pull request as ready for review October 2, 2026 20:44
@wyattwalter
wyattwalter requested a review from a team as a code owner October 2, 2026 20:44

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ok-to-test Required label for CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant