web-testing-cypress-e2e-3be2d7 — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited web-testing-cypress-e2e-3be2d7 (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Quick Guide: Cypress runs inside the browser alongside the application. Commands are enqueued rather than executed, so nothing they produce can be read out of aconst— use.then()or an alias. Select withdata-cyattributes, wait oncy.intercept()aliases rather than on milliseconds, and cache authentication withcy.session(). Cypress 15 is current stable;cy.origin()has been required for any cross-origin navigation since 14, andCypress.env()is deprecated in favour ofcy.env()andCypress.expose().
Detailed Resources:
cy.session(), keys and focus
response modification, sequencing
declarations, cy.task(), cy.origin()
constants
cy.mount(), spies on props,intercepts in component specs
14/15 changes, troubleshooting
cypress/e2e, entered with cy.visit(),configured under the e2e key; follow examples/core.md.
cypress/component, entered with cy.mount(),configured under the component key with a dev server; follow examples/component-testing.md.
Both halves share the command API, the selectors and cy.intercept(); only the entry point and the config block differ.
<critical_requirements>
Alias every intercept and wait on the alias — cy.intercept(...).as("getUsers") then cy.wait("@getUsers"). The wait ends exactly when the response arrives, where a millisecond wait is either too short or wasted.
Select with a dedicated test attribute — [data-cy=submit-button]. It is the one hook in the markup that styling changes and DOM restructuring do not move.
Read a command's result through `.then()` or an alias. Commands are queued and run after the enclosing function returns, so a const captures a chainer rather than a value.
Wrap cross-origin navigation in `cy.origin()` — required since Cypress 14, because Chrome removed the document.domain setter Cypress previously used to reach another origin from the same agent cluster.
</critical_requirements>
Auto-detection: Cypress, cypress.config, cy.visit, cy.get, cy.contains, cy.intercept, cy.wait, cy.origin, cy.session, cy.fixture, cy.task, cy.mount, cy.env, Cypress.Commands.add, Cypress.Commands.overwriteQuery, data-cy, .cy.ts specs
Applies to:
cy.intercept()cy.session() and cy.task()cy.mount(), and the config both spec types shareHandled elsewhere:
result; the standard being audited against is settled elsewhere
is written
<philosophy>
Cypress commands do not execute where they are written. Each one is appended to a queue that runs after the surrounding function returns, which explains nearly every surprise: why a const is useless, why .then() exists, and why an assertion "waits" without anyone asking it to.
Retry-ability follows from the same model. Cypress re-runs the last query in a chain until the attached assertion passes, so cy.get(...).should(...) is self-waiting while cy.get(...).then(el => expect(el)...) is not — the .then() body runs once, on whatever the query found the first time.
</philosophy>
<decision_framework>
Which selector:
data-cy, always the first choice.cy.contains("Sign In"), so a copy change fails thetest deliberately.
name → input[name="email"].button[type="submit"]; classes and ids arethe last resort because both move with styling.
Stub the request or let it through:
cy.intercept().feature.
How to reach an authenticated state:
cy.session() with a validate callback; addcacheAcrossSpecs: true to keep it between spec files.
cy.request() to the login endpoint inside cy.session(), which isfaster and does not re-test the login form in every spec.
cy.task() to seed, called from beforeEach.</decision_framework>
<patterns>
describe groups the feature, context separates scenarios, beforeEach puts every test in the same starting state.
describe("Login Flow", () => {
beforeEach(() => {
cy.visit("/login");
});
context("with valid credentials", () => {
it("redirects to the dashboard", () => {
cy.getBySel("email-input").type(VALID_EMAIL);
cy.getBySel("password-input").type(VALID_PASSWORD);
cy.getBySel("submit-button").click();
cy.url().should("include", "/dashboard");
});
});
});Full code: examples/core.md
cy.get("[data-cy=submit-button]").click();
cy.getBySel("submit-button").click(); // same thing, via a custom command
cy.contains("button", "Submit").click(); // when the text is the subject
cy.getBySel("confirmation-modal").within(() => {
cy.getBySel("confirm-button").click(); // scoped, so a duplicate id elsewhere cannot match
});Full code: examples/core.md — the command itself in examples/custom-commands.md
cy.intercept()cy.intercept("GET", "/api/users", { statusCode: 200, body: MOCK_USERS }).as(
"getUsers",
);
cy.visit("/users");
cy.wait("@getUsers");
cy.getBySel("user-row").should("have.length", 2);
// The alias also carries the request, so the payload can be asserted on
cy.wait("@createUser")
.its("request.body")
.should("deep.include", { name: "New User" });Full code: examples/intercept.md
Wrap the flows every spec repeats, and declare their types so editors and tsc see them.
// cypress/support/commands.ts
Cypress.Commands.add("login", (email: string, password: string) => {
cy.session([email, password], () => {
cy.visit("/login");
cy.getBySel("email-input").type(email);
cy.getBySel("password-input").type(password);
cy.getBySel("submit-button").click();
cy.url().should("include", "/dashboard"); // guards the cache: session is saved after this
});
});Full code: examples/custom-commands.md
A fixture file for data that several specs share; a factory for data a single scenario shapes.
cy.intercept("GET", "/api/products", { fixture: "products.json" }).as(
"getProducts",
);
const users = createUsers(5);
cy.intercept("GET", "/api/users", { body: users }).as("getUsers");Full code: examples/fixtures-data.md
cy.origin()Anything on another scheme, host or port runs inside the callback, which is serialised into that origin — so it can only see values passed through args.
cy.visit("/login");
cy.getBySel("sso-button").click();
cy.origin(
IDENTITY_PROVIDER_URL,
{ args: { email, password } },
({ email, password }) => {
cy.get("#email").type(email);
cy.get("#password").type(password);
cy.get("#submit").click();
},
);
cy.url().should("include", "/dashboard"); // back on the original originFull code: examples/custom-commands.md
cy.mount()The same command API against a mounted component instead of a visited page. cy.spy().as() records prop callbacks; cy.intercept() works exactly as it does in an E2E spec.
const onSelect = cy.spy().as("onSelect");
cy.mount(<ProductList products={MOCK_PRODUCTS} onSelect={onSelect} />);
cy.getBySel("product-item").first().click();
cy.get("@onSelect").should("have.been.calledWith", MOCK_PRODUCTS[0]);Full code: examples/component-testing.md
cy.task()cy.task() runs in the Node process, which is the only place a test can reach a database, the filesystem, or anything else the browser cannot.
// cypress.config.ts — setupNodeEvents
on("task", { "db:seed": (data) => seed(data), "db:reset": () => reset() });
// in a spec
beforeEach(() => {
cy.task("db:reset");
cy.task("db:seed", { users: [TEST_USER] });
});Full code: examples/custom-commands.md
</patterns>
<red_flags>
Breaks at runtime:
const el = cy.get(...) then using el later — the command has not run; alias it with .as()and read it back with cy.get("@alias").
cy.fixture("users").as("users") read as this.users from an arrow function — this is not thetest context there; use function ().
cy.origin() — refused since Cypress 14.delayMs on cy.intercept() — removed in 14; the option is delay.cypress open-ct / run-ct — removed in 14; use the --component flag.cy.stub() form — removed in 15; use cy.stub(obj, "method").returns(value).Cypress.Commands.overwrite() against a query such as .get() or .contains() — queries needCypress.Commands.overwriteQuery() since 14.
.its("code") on cy.exec() — renamed to exitCode in 15.cy.exec() — the process never exits and the runhangs; start it from the CI step or webServer-style tooling instead.
Surprising behaviour:
cy.wait(5000) passes today and fails on a slower machine — wait on an intercept alias instead.it() starts from a reset browser: testIsolation clears cookies and both storages betweene2e tests, so a spec that signs in during its first test and assumes it in the second fails, and fails differently when run alone. Put the setup in beforeEach, and use cy.session() so restoring it costs nothing.
.then() runs once against astale element.
cy.readFile() where freshness matters.
cy.session() clears cached state when the spec file changes unless cacheAcrossSpecs: true isset.
after/afterEach is skipped when a run is interrupted — clean in beforeEach, whichalso leaves the final state on screen for debugging.
in beforeEach so no test inherits another's stub.
Cypress.env() is deprecated from 15.10 and removed in 16 — cy.env() (async, for secrets) andCypress.expose() (for public values) replace it.
--load-extension from 137 — run extension tests in Electron,Chrome for Testing or Chromium.
</red_flags>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.