Project — a Real POM Framework With Custom Commands¶
What was run¶
A real, fluent Page Object module (plain JS classes, not a Cypress-specific API) combined with
cy.session() caching, run as a 3-test capstone against the local test app.
// cypress/support/pages.js
class LoginPage {
visit() { cy.visit("/login.html"); return this; }
fillUsername(text) { cy.get("#username").type(text); return this; }
fillPassword(text) { cy.get("#password").type(text); return this; }
submit() { cy.get("#submit-btn").click(); return this; }
login(username, password) { return this.fillUsername(username).fillPassword(password).submit(); }
getResult() { return cy.get("#result"); }
}
it("logs in via a fluent page object chain", () => {
new LoginPage().visit().login("realuser", "realpass123");
new LoginPage().getResult().should("have.text", "Login Successful");
});
it("logs in and reuses a cached cy.session instead of repeating the UI flow", () => {
cy.session("capstone-session", () => {
new LoginPage().visit().login("realuser", "realpass123");
new LoginPage().getResult().should("have.text", "Login Successful");
});
new TodosPage().visit();
new TodosPage().getTodoItems().should("have.length.at.least", 2);
});
✓ logs in via a fluent page object chain (433ms)
✓ logs in and reuses a cached cy.session instead of repeating the UI flow (442ms)
✓ adds a real todo via the page object and confirms it renders (242ms)
3 passing (1s)
How It Actually Works¶
This capstone's Page Object classes are not a Cypress feature — they're ordinary JavaScript classes
whose methods call real cy commands and return this for fluent chaining, the identical pattern this
network's own Selenium Mastery Path used in Python. That portability is itself a real, useful fact: the Page
Object pattern is language- and tool-agnostic, built entirely from each language's own object-oriented
features, while the methods inside it call whatever commands the specific tool (Cypress here, Selenium
there) actually provides. The one genuinely Cypress-specific piece in this capstone is wrapping the login
flow in cy.session() (Lesson 4) — a page object encapsulates how to perform
the login, while cy.session() controls how often that encapsulated flow actually needs to run, and the
two compose cleanly because the session's setup callback is just calling the identical page-object methods
other tests call directly.
Common mistakes¶
- Putting
cy.session()calls inside the Page Object class itself — this capstone keeps session caching at the test level, wrapping a call to the page object's ownlogin()method, which keeps the page object focused purely on "how to interact with this page" and leaves "how often to repeat this" as the test's own decision. - Returning a raw Cypress chain (
cy.get(...)) from a page-object method meant for fluent chaining (likelogin()), instead ofreturn this— mixing the two return styles in the same class makes it unclear from the call site whether a chained.method()call continues the page object or acycommand. - Assuming a Page Object needs to wrap every interaction —
getResult()in this lesson'sLoginPagedeliberately returns the rawcy.get(...)chain rather than wrapping it in another method, because the caller needs Cypress's own assertion chain (.should(...)) available directly, not a page-object abstraction over it.
Exercise¶
Add a logout() method to LoginPage that clears the real session (cy.clearAllSessionStorage() plus a
fresh cy.visit("/login.html")), and write a fourth capstone test that logs in via the cached
cy.session(), calls the new logout(), then attempts to visit /todos.html again. Determine from the
real result whether this test app's own current code actually enforces any authentication requirement on
that route, or whether — like several of this course's earlier real findings — the app simply doesn't
check, revealing a genuine gap rather than a Cypress limitation.