{"id":15599592,"url":"https://github.com/hypercubed/cypress-page-object-pattern","last_synced_at":"2025-07-11T14:09:16.647Z","repository":{"id":66193239,"uuid":"108669170","full_name":"Hypercubed/cypress-page-object-pattern","owner":"Hypercubed","description":"Cypress Page Object Pattern Example","archived":false,"fork":false,"pushed_at":"2018-08-10T08:58:25.000Z","size":12,"stargazers_count":65,"open_issues_count":2,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-28T10:26:24.760Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hypercubed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-28T17:23:21.000Z","updated_at":"2023-09-17T13:41:15.000Z","dependencies_parsed_at":"2023-02-25T07:00:18.265Z","dependency_job_id":null,"html_url":"https://github.com/Hypercubed/cypress-page-object-pattern","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypercubed%2Fcypress-page-object-pattern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypercubed%2Fcypress-page-object-pattern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypercubed%2Fcypress-page-object-pattern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hypercubed%2Fcypress-page-object-pattern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hypercubed","download_url":"https://codeload.github.com/Hypercubed/cypress-page-object-pattern/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251293853,"owners_count":21566159,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T02:00:25.759Z","updated_at":"2025-04-28T10:26:46.954Z","avatar_url":"https://github.com/Hypercubed.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cypress Page Object Pattern Example\n\nThis repo is a test/demonstration of three patterns and one anti-pattern for using Page-Objects  (reference needed) or Page-Object-like testing patterns in [Cypress](https://www.cypress.io/).\n\n*Disclaimer: I am a JavaScript developer not an experienced e2e tester and new to Cypress myself.. so take it for what it is.*\n\n# (Anti-)Patterns\n\n## [Pattern A: The anti-pattern](cypress/integration/po-pattern-a.js)\n\nPattern A is an anti-pattern.  When navigating from page to page within a single test flow, new page instances are created from page classes each time.  This breaks the Cypress' internal async queuing and necessitates excessive use of `.then`s and/or callbacks.\n\n**Do not do this!**\n\n### Page Module\n\n```js\nimport BasePage from './BasePageClass';\nimport QueryPage from './NavigationMenuClass';\n\nexport default class MainPage extends BasePage  {\n  constructor() {\n    super();\n    this.mainElement = 'body \u003e .banner';\n  }\n\n  verifyElements() {\n    return cy.get(this.mainElement).find('.container h1').should('be.visible').then(() =\u003e {\n      return this.navMenu.verifyElements();\n    });\n  }\n\n  switchToQueryingPage() {\n    return this.navMenu.switchToQueryingPage().then(() =\u003e {\n      cy.log('==\u003e Finding Query Page');\n      const queryPage = new QueryPage();\n      return queryPage.verifyElements()\n        .then(() =\u003e queryPage);\n    });\n  }\n};\n```\n\n### Integration Test\n\n```js\nimport MainPage from '../support/pageObjects-A/MainPageClass';\n\ndescribe('Page Object Pattern - A', () =\u003e {\n  context('Querying', () =\u003e {\n    let mainPage;\n\n    beforeEach(() =\u003e {\n      return cy.visit('https://example.cypress.io/')\n        .get('body \u003e .banner h1').should('be.visible').then(() =\u003e {\n          mainPage = new MainPage();\n          return mainPage.verifyElements();\n        });\n    });\n\n    it('cy.get() - query DOM elements', () =\u003e {\n      mainPage.switchToQueryingPage();\n    });\n  });\n});\n```\n\n## [Pattern B: page classes](cypress/integration/po-pattern-a.js)\n\nIn Pattern B we keep the page class definitions, which may be useful for inheritance, but each page class module exports a single page object instance of the class.  These instances can be used throughout the testing and within other classes.\n\n**Do this if you must have page classes and inheritance**.\n\n### Page Module\n\n```js\nimport { BasePage } from './BasePageClass'\nimport { navMenu } from './NavigationMenuClass';\nimport { queryPage } from './QueryPageClass';\n\nexport class MainPage extends BasePage  {\n  constructor() {\n    super();\n    this.mainElement = 'body \u003e .banner';\n  }\n\n  verifyElements() {\n    super.verifyElements();\n    cy.get(this.mainElement).find('.container h1').should('be.visible');\n  }\n\n  switchToQueryingPage() {\n    navMenu.switchToQueryingPage();\n    queryPage.verifyElements();\n  }\n};\n\nexport const mainPage = new MainPage();\n```\n\n### Integration Test\n\n```js\nimport { mainPage } from '../support/pageObjects-B/MainPageClass';\n\ndescribe('Page Object Pattern - B', () =\u003e {\n  context('Querying', () =\u003e {\n    beforeEach(() =\u003e {\n      cy.visit('https://example.cypress.io/')\n        .get('body \u003e .banner h1').should('be.visible');\n      mainPage.verifyElements();\n    });\n\n    it('cy.get() - query DOM elements', () =\u003e {\n      mainPage.switchToQueryingPage();\n    });\n  });\n});\n```\n\n## [Pattern C: page objects](cypress/integration/po-pattern-a.js)\n\nIn Pattern C we eliminate classes entirely.  Instead each page module creates and exports single page object instance. These instances are used in the same way as pattern B.\n\n**Do this if you don't need page classes and inheritance**.\n\n### Page Module\n\n```js\nimport { navMenu } from './navigationMenu';\nimport { queryPage } from './queryPage';\n\nconst bannerElement = 'body \u003e .banner';\n\nexport const mainPage = {\n  verifyElements() {\n    cy.get(bannerElement).find('.container h1').should('be.visible');\n    navMenu.verifyElements();\n  },\n  switchToQueryingPage() {\n    navMenu.switchToQueryingPage();\n    queryPage.verifyElements();\n  }\n}\n```\n\n### Integration Test\n\n```js\nimport { mainPage } from '../support/pageObjects-C/mainPage';\n\ndescribe('Page Object Pattern - C', () =\u003e {\n  context('Querying', () =\u003e {\n    beforeEach(() =\u003e {\n      cy.visit('https://example.cypress.io/')\n        .get('body \u003e .banner h1').should('be.visible');\n      mainPage.verifyElements();\n    });\n\n    it('cy.get() - query DOM elements', () =\u003e {\n      mainPage.switchToQueryingPage();\n    });\n  });\n});\n```\n\n## [Pattern D: page modules](cypress/integration/po-pattern-d.js)\n\nIn Pattern D we eliminate the objects themselves.  Instead each page module creates and exports public functions. These public function can be imported and used in an almost identical way the as pattern B and C.\n\n**Do this if you don't need page objects**.\n\n### Page Module\n\n```js\nimport * as navMenu from './navigationMenu';\nimport * as queryPage from './queryPage';\n\nconst bannerElement = 'body \u003e .banner';\n\nexport function verifyElements() {\n  cy.get(bannerElement).find('.container h1').should('be.visible');\n  navMenu.verifyElements();\n}\n\nexport function switchToQueryingPage() {\n  navMenu.switchToQueryingPage();\n  queryPage.verifyElements();\n}\n```\n\n### Integration Test\n\n```js\nimport * as mainPage from '../support/pageObjects-D/mainPage';\n\ndescribe('Page \"Object\" Pattern - D', () =\u003e {\n  context('Querying', () =\u003e {\n    beforeEach(() =\u003e {\n      cy.visit('https://example.cypress.io/')\n        .get('body \u003e .banner h1').should('be.visible');\n      mainPage.verifyElements();\n    });\n\n    it('cy.get() - query DOM elements', () =\u003e {\n      mainPage.switchToQueryingPage();\n    });\n  });\n});\n```\n\n## Pattern E: Cypress commands (to be done)\n\nIn Pattern D we (will) show how to emulate page object pattern using cypress commands. **To be completed later, contributions welcome**.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypercubed%2Fcypress-page-object-pattern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhypercubed%2Fcypress-page-object-pattern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhypercubed%2Fcypress-page-object-pattern/lists"}