1. Where does Cypress run your test code?
Answer
Inside the browser, in the same run loop as the app under test
Correct. Cypress runs in the browser next to your app. That is why it has direct access to the DOM and network.
Cypress runs in the browser, in the same loop as your app. This is the root reason for its retry-ability and direct DOM access.
Why the other answers are wrong
- In a separate Node.js process that controls the browser from outside. That is the Selenium/WebDriver model. Cypress runs inside the browser instead.
- On a remote server that streams screenshots back. Cypress runs locally in the browser; nothing is streamed from a server.
- In a web worker with no access to the page. Cypress has full access to the page, it runs in the same context as the app.
2. What does this code actually do?
cy.get('[data-testid="email"]')
cy.get('[data-testid="password"]')
Answer
It queues two commands; both run in order when the test function returns
Correct. cy.get does not run right away. It adds a command to a queue that Cypress runs in order afterwards.
Cypress commands are enqueued, then run in order. Understanding the queue explains why await does not work and why you chain instead.
Why the other answers are wrong
- It finds both elements immediately and returns them. cy.get does not return an element. It queues a command; the lookup happens later when the queue runs.
- It runs the two lookups at the same time. Cypress commands run one after another in queue order, not in parallel.
- Nothing, because the results are not stored in a variable. The commands still queue and run. Cypress yields their results to the next chained command, not to a variable.
3. What is wrong with writing const el = cy.get('.title') and then using el directly?
Answer
cy.get returns a Cypress chainable, not the element, el is not the DOM node
Correct. Commands yield their subject to the next chained command. You cannot store an element from cy.get and use it directly.
To work with the yielded value, chain a command or use .then((el) => ...). Assigning cy.get to a variable does not give you the element.
Why the other answers are wrong
- Nothing, el now holds the DOM element. It does not. cy.get yields a chainable object, and the element only exists later when the command runs.
- It works, but only for class selectors. The selector type is not the issue. cy.get never returns a usable element synchronously.
- el holds a promise you must await. Cypress commands are not promises and must not be awaited. You chain commands with .then() to work with the subject.
4. Why should you not use async/await with cy commands?
Answer
cy commands are queued, not promises, await does not wait for them and can break command order
Correct. Cypress runs its own command queue. Mixing await with it fights the queue and causes confusing failures.
Chain commands, or use .then() for the yielded value. Do not await cy commands. The most common Cypress mistake.
Why the other answers are wrong
- await makes tests run too fast. Speed is not the problem. The problem is that cy commands are not promises, so await does not do what you expect.
- Cypress does not support modern JavaScript. Cypress supports modern JavaScript. The issue is specifically the command queue, not the language.
- await only works in Playwright. await is standard JavaScript. It just does not fit the Cypress command queue.
5. What is the correct way to use the value a command yields?
Answer
cy.get('.total').then((el) => { /* work with el here */ })
Correct. .then() gives you the yielded subject once the command has run. This is how you reach the real element.
.then() is how you drop into the queue at the right moment and use what a command yielded.
Why the other answers are wrong
- const el = await cy.get('.total'). cy commands are not promises. await does not give you the element and can break the queue.
- let el; cy.get('.total').each(e => el = e); use(el). The assignment runs before the queued command, so el is still empty when you use it.
- cy.get('.total').return(). There is no .return() command. Use .then() to access the yielded subject.
6. What does cy.visit('/') do?
Answer
Queues a command that loads the page and waits for it to finish loading before the next command runs
Correct. cy.visit loads the page and waits for the load event, so later commands run against a ready page.
cy.visit loads the app and waits for the load event. It is almost always the first command in a test.
Why the other answers are wrong
- Opens the page in a new browser tab. cy.visit loads the app in the same Cypress-controlled frame, not a new tab.
- Only changes the URL bar without loading anything. It performs a real page load, not just a URL change.
- Sends an API request to '/' and returns JSON. cy.visit loads a page in the browser. It is not an API call.
7. In which file would Cypress end-to-end tests normally live?
Answer
A spec file under cypress/e2e/, e.g. login.cy.js
Correct. End-to-end specs live in cypress/e2e/ by default, with a .cy.js or .cy.ts name.
Default layout: specs in cypress/e2e/*.cy.js, config in cypress.config.js, reusable commands in cypress/support/.
Why the other answers are wrong
- Directly inside the app's src/ folder next to components. Cypress specs live in the cypress/ folder, kept separate from app source.
- In a single file called cypress.json. cypress.config.js holds config, not tests. Tests live in spec files under cypress/e2e/.
- Anywhere, as long as the name ends in .test.js. Cypress uses .cy.js/.cy.ts specs under cypress/e2e/, not the .test.js convention.
8. What is the purpose of cypress/support/commands.js?
Answer
To define custom commands like cy.login() that you reuse across specs
Correct. Custom commands live here. A cy.login() command keeps repeated setup in one place.
Custom commands (cy.login, cy.seedData) belong in the support folder so specs stay short and readable.
Why the other answers are wrong
- To list which tests are allowed to run. It does not control which tests run. It holds reusable custom commands.
- To store screenshots from failed runs. Screenshots go to an output folder, not to the support file.
- To configure the base URL. The base URL is set in cypress.config.js, not in the support file.
9. A test does cy.visit('/'), then cy.get('.spinner') fails saying the element does not exist, though it appears briefly on load. What is the likely cause?
Answer
The spinner had already disappeared by the time the command ran. It is a real-but-temporary element
Correct. cy.get retries until the element exists, but a spinner that is already gone will never be found. Assert on the state after loading instead.
Retry-ability waits for an element to appear, but cannot catch one that has already gone. Assert on the settled state, not a flash.
Why the other answers are wrong
- cy.visit did not load the page. If the page had not loaded, later commands would fail differently. The spinner is simply gone by the time you look.
- Class selectors do not work in Cypress. Class selectors work fine. The element is just no longer on the page.
- Cypress cannot see elements added by JavaScript. Cypress sees dynamically added elements. This one was removed before the command ran.
10. Why is it fine that a Cypress test has no explicit 'wait for page load' after cy.visit?
Answer
cy.visit already waits for the load event, and later commands retry until their target is ready
Correct. Between cy.visit waiting for load and commands retrying, most manual waiting is unnecessary.
cy.visit waits for load; every command retries until its target is actionable. That combination is why Cypress tests rarely need manual waits.
Why the other answers are wrong
- Because Cypress tests run so fast the page is always ready. Speed is not the reason. cy.visit waits for load, and commands retry. That is what makes manual waits unnecessary.
- Because the page is pre-rendered before the test starts. The page is loaded by cy.visit during the test, not before it. The waiting is built into the commands.
- Because you always add cy.wait(2000) anyway. You should not add fixed waits. The built-in waiting removes the need for them.