QA Interview Hub · Knowledge base · Quizzes
Cypress
Outdated-answer traps
what the internet still says, and what is right
Does Cypress run tests in parallel and does it retry failed tests automatically?
Both statements are false.
Parallelism: on one machine Cypress runs specs sequentially: one process, one browser. In parallel only across several machines: through Cypress Cloud (--record --parallel) or for free through a CI matrix and a plugin like cypress-split.
Retries: off by default. They must be turned on explicitly in the config, usually only for CI.
// cypress.config.ts
export default defineConfig({
retries: { runMode: 2, openMode: 0 },
});
In an interview: No. On one machine Cypress runs specs sequentially, and parallelism exists only across several machines, through Cloud or by splitting specs in CI. And rerunning failed tests is off by default, I turn it on in the config for runMode, and I investigate every test that passed on a retry separately.
And in Playwright:In Playwright both are built in: workers parallelise tests on one machine (half the cores by default), and --shard splits between machines. Retries are also off by default and set in the config (retries: process.env.CI ? 2 : 0), but the on-first-retry trace immediately shows why a test failed.
How do you keep login and cookies between tests?
Cypress.Cookies.preserveOnce was removed in Cypress 12, and copying cookies by hand is a brittle workaround. The modern answer is cy.session: it caches cookies, localStorage and sessionStorage after login and restores them in later tests, and validate checks that the session is still valid.
More detail is in the question about cy.session in the "State, sessions, isolation" section.
In an interview: The modern way is cy.session. It performs the login once, caches cookies and storages, and restores them in later tests. Copying cookies by hand and the old preserveOnce are approaches from versions before twelve.
And in Playwright:The equivalent is storageState: a setup project logs in and saves the state to JSON, and other projects pick up the file through dependencies.
How do you make a pause (sleep) in Cypress?
Technically cy.wait(ms) really does pause, but the right answer in an interview is to explain why you shouldn't: a fixed pause makes the test both slow and unstable.
Instead: an assertion that is retried itself (should('be.visible')), or waiting for a specific request through cy.intercept and cy.wait('@alias'). Justified use of cy.wait(ms) is rare, for example checking a debounce, where the time itself is the requirement.
In an interview: Formally it is cy.wait with milliseconds, but I don't do that, because it is a guessed number: the test either waits for nothing or fails. I wait for a concrete state: an assertion on an element or the completion of a request through an intercept with an alias.
And in Playwright:In Playwright the same antipattern is page.waitForTimeout(). Instead use web-first assertions and waitForResponse.
How do you use XPath in Cypress?
There is no native XPath support, and the official plugin @cypress/xpath is no longer maintained by the Cypress team. You can still see it on old projects, but recommending it as a solution is a sign of outdated knowledge.
The tasks for which XPath is used are covered by built-in means: search by text with cy.contains, moving through the tree with .closest(), .parents(), .siblings(), .next(), semantic search with Testing Library and cy.findByRole.
// XPath: //td[text()='Order #1042']/parent::tr//button
cy.contains('td', 'Order #1042').closest('tr').find('button').click();
In an interview: Out of the box Cypress has no XPath, and the plugin for it is no longer maintained. In practice it isn't needed either: I search by text through contains, and go from an element to its parent or sibling through closest, parents or siblings.
And in Playwright:Playwright supports XPath natively (page.locator('xpath=...'), and a string with // is recognised automatically), but recommends getByRole, getByText and getByTestId.
How do you install Cypress correctly?
Locally in the project, as a dev dependency: npm install --save-dev cypress. Then the version is pinned in package.json and the lock file, it is the same for all developers and on CI, and it is run through npx cypress.
A global install gives different versions on different machines and breaks reproducibility. Only the Cypress binary is stored separately, in the system cache, and it is checked with npx cypress verify.
In an interview: Locally in the project as a dev dependency, so the version is pinned and the same for everyone and on CI. A global install gives a version mismatch between machines.
And in Playwright:The same rule: npm i -D @playwright/test in the project, plus npx playwright install for the browsers.
The element is hidden and the click doesn't go through. What do you do?
First understand why it is hidden. If it is covered by a modal, a loader or a cookie banner, the test has found a real problem, or has to close the obstacle first itself. If the element appears after an action, you need to wait for the state with should.
{ force: true } turns off the actionability checks, and the test may pass where a user couldn't click. It is justified only for deliberate cases such as a hidden native checkbox under a custom one, and with a comment.
In an interview: First I find out the cause: whether the element is covered, hasn't appeared yet, or it is a bug. Force turns off the checks, and a test can turn green where a user would be stuck, so I use it only in rare justified cases and with a comment.
How does requestTimeout differ from responseTimeout?
requestTimeout (5 s) is how long cy.wait('@alias') waits for the application to send a request. If the request didn't go out within 5 seconds, the error is "No request ever occurred".
responseTimeout (30 s) is how long to wait for the response: to an intercepted request in cy.wait and to cy.request.
So these are two different stages: "did the request go out" and "did the response come". The diagnosis differs: the first timeout usually means the action in the UI didn't fire or the intercept was registered after it, and the second means a slow backend.
In an interview: They are two stages. requestTimeout is five seconds for the request to be sent at all, and if it runs out, the problem is usually in the test or the UI. responseTimeout is thirty seconds for the server's response, and that is already about the backend.
How do you recognise an outdated answer about Cypress structure?
| Outdated (before v10) | Current |
cypress.json | cypress.config.js / .ts |
cypress/integration | cypress/e2e, files *.cy.ts |
testFiles | specPattern |
cypress/plugins/index.js | setupNodeEvents in the config |
cy.server(), cy.route() | cy.intercept() |
Cypress.Cookies.preserveOnce | cy.session() |
| Cypress Dashboard | Cypress Cloud |
| Video is always recorded | Off by default since v13 |
Any of the terms on the left in your answer signals that your experience ended before version 10.
In an interview: Since version ten the config is cypress.config, tests are in the e2e folder, instead of testFiles there is specPattern, and plugins moved into setupNodeEvents. The network is intercepted through intercept instead of the old server and route, and sessions are kept through cy.session.