├── README.md ├── cypress.json ├── cypress.scaffold.framework.png ├── cypress ├── fixtures │ └── example.json ├── integration │ ├── entryCentralLogin.feature │ └── entryCentralLogin │ │ └── entryCentralLogin.js ├── pages │ ├── accountPage.js │ ├── basePage.js │ └── loginPage.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # Overview of Cypress 2 | 3 | ## Page Object Model 4 | Cypress does not recommend using the Page Object Model pattern that most folk will be used to from the Selenium based 5 | frameworks (see the article by Martin Fowler [Page Object](https://martinfowler.com/bliki/PageObject.html) ) the 6 | preferred option is to use the Cypress Custom Commands, this POM version has been added to provide a comparison. 7 | 8 | 9 | # Installing Cypress from Scratch 10 | Create a project directory 11 | Open a Terminal in the project root directory 12 | 13 | `$ npm init` 14 | 15 | `$ npm install cypress --save-dev` 16 | 17 | Further details see [Cypressio npm install](https://docs.cypress.io/guides/getting-started/installing-cypress.html#npm-install) 18 | 19 | ## Opening Cypress 20 | 21 | You can now open the Cypress console by running: 22 | 23 | `$ node_modules/.bin/cypress open` 24 | 25 | or 26 | 27 | `$ npx cypress open` 28 | 29 | from the project root folder. 30 | 31 | This will also generate the following scaffold directory structure 32 | 33 | ![alt text](./cypress.scaffold.framework.png) 34 | 35 | To run from a command line add a Script to the Package JSON file 36 | 37 | `cyrun": "node_modules/.bin/cypress run --browser chrome"` 38 | 39 | Tests can then be run from a Terminal 40 | 41 | `$ npm run cyrun` 42 | 43 | 44 | 45 | ## Plugins 46 | 47 | ### Cucumber 48 | 49 | `$ npm install cypress-cucumber-preprocessor --save-dev` 50 | 51 | Now configure Cypress by adding the [Cucumber Plugin](https://github.com/TheBrainFamily/cypress-cucumber-preprocessor) 52 | to the cypress/plugins/index.js file: 53 | 54 | ``` 55 | const cucumber = require('cypress-cucumber-preprocessor').default 56 | 57 | module.exports = (on, config) => { 58 | on('file:preprocessor', cucumber()) 59 | } 60 | ``` 61 | 62 | and add support for feature files to your Cypress configuration file cypress.json which was generated 63 | when Cypress was initially opened as part of the scaffold structure: 64 | 65 | ` 66 | { 67 | "testFiles": "**/*.feature" 68 | }` 69 | 70 | 71 | The Cypress-Cucumber-Preprocessor docs recommend using the [Cosmic Config module](https://github.com/davidtheclark/cosmiconfig) installed via: 72 | 73 | `$ npm install cosmiconfig --save-dev` 74 | 75 | and then added as a section to the package.json file as follows: 76 | 77 | `"cypress-cucumber-preprocessor": { 78 | "nonGlobalStepDefinitions": true 79 | }` 80 | 81 | By setting this to true, the Cypress Cucumber Preprocessor Style pattern for placing step definitions files will be 82 | used instead of the "oldschool" i.e. everything is global Cucumber style. 83 | 84 | Environment variables can be added via a cypress.env.json file and accessed 85 | within the code so 86 | 87 | `Cypress.env('keyValue')` 88 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "testFiles": "**/*.feature" 3 | } 4 | -------------------------------------------------------------------------------- /cypress.scaffold.framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrharry/cypress-framework-pageObject/ef819ac110960c6917464d1baa0db086fbbeb744/cypress.scaffold.framework.png -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/integration/entryCentralLogin.feature: -------------------------------------------------------------------------------- 1 | Feature: Validate the login page 2 | 3 | Background: 4 | Given I navigate to the Entry Central login page 5 | 6 | Scenario: When I navigate to the login page 7 | Then I should see "EntryCentral.com" displayed as the page title 8 | 9 | Scenario: When I log in with an incorrect email/password combination 10 | When I login with an "invalid" credential combination 11 | Then I should see the "Invalid credentials" login error message 12 | 13 | Scenario: When I log in with a valid registered email/password combination 14 | When I login with a "valid" credential combination 15 | Then I should see "Account - EntryCentral.com" displayed as the page title 16 | 17 | -------------------------------------------------------------------------------- /cypress/integration/entryCentralLogin/entryCentralLogin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by stuart1 on 31/10/2019. 3 | */ 4 | import { Given, When, Then} from "cypress-cucumber-preprocessor/steps"; 5 | import LoginPage from '../../pages/loginPage'; 6 | const loginPage = new LoginPage(); 7 | 8 | 9 | Given('I navigate to the Entry Central login page', () => { 10 | loginPage.navigate('/login'); 11 | }); 12 | 13 | When('I login with a/an {string} credential combination', (credType) => { 14 | loginPage.fillLoginCredentials(credType) 15 | }); 16 | 17 | Then('I should see {string} displayed as the page title', (pageTitle) => { 18 | loginPage.getPageTitle().should('eq', pageTitle) 19 | }); 20 | 21 | Then('I should see the {string} login error message', (message) => { 22 | loginPage.getAlertMessage().should('contain.text', message) 23 | }); 24 | -------------------------------------------------------------------------------- /cypress/pages/accountPage.js: -------------------------------------------------------------------------------- 1 | import BasePage from './basePage.js' 2 | 3 | export default class AccountPage extends BasePage { 4 | 5 | constructor() { 6 | super() 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /cypress/pages/basePage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by stuart1 on 05/11/2019. 3 | */ 4 | export default class BasePage { 5 | 6 | baseUrl = "https://www.entrycentral.com"; 7 | cookieMessage = "#ccc-close"; 8 | 9 | navigate(path) { 10 | cy 11 | .visit(this.baseUrl + path) 12 | .get(this.cookieMessage) 13 | .click(); 14 | } 15 | 16 | getPageTitle() { 17 | return cy.title() 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /cypress/pages/loginPage.js: -------------------------------------------------------------------------------- 1 | import BasePage from './basePage.js' 2 | 3 | export default class LoginPage extends BasePage { 4 | 5 | constructor() { 6 | super() 7 | } 8 | 9 | username = "#username"; 10 | password = "#password"; 11 | alertMessage = ".alert"; 12 | submitButton = "#_submit"; 13 | 14 | fillLoginCredentials(credType) { 15 | let field = cy.get(this.username); 16 | field.clear(); 17 | field.type(Cypress.env(credType + 'User')); 18 | 19 | field = cy.get(this.password); 20 | field.clear(); 21 | field.type(Cypress.env(credType + 'Password')); 22 | 23 | this.submit(this.submitButton) 24 | } 25 | 26 | getAlertMessage() { 27 | return cy.get(this.alertMessage) 28 | } 29 | 30 | submit(buttonId) { 31 | const button = cy.get(buttonId); 32 | button.click(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const cucumber = require('cypress-cucumber-preprocessor').default; 15 | 16 | module.exports = on => { 17 | on('file:preprocessor', cucumber()) 18 | }; 19 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cypress-framework", 3 | "version": "1.0.0", 4 | "description": "Cypress using Cucumber with Page Objects", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "cyrun": "node_modules/.bin/cypress run --browser chrome" 9 | }, 10 | "keywords": [ 11 | "Cypress", 12 | "Cucumber", 13 | "BDD" 14 | ], 15 | "author": "Stuart Robertson", 16 | "license": "ISC", 17 | "cypress-cucumber-preprocessor": { 18 | "nonGlobalStepDefinitions": true, 19 | "cucumberJson": { 20 | "generate": true, 21 | "outputFolder": "cypress/cucumber-json", 22 | "filePrefix": "", 23 | "fileSuffix": ".cucumber" 24 | } 25 | }, 26 | "devDependencies": { 27 | "cosmiconfig": "^5.2.1", 28 | "cypress": "^3.6.0", 29 | "cypress-cucumber-preprocessor": "^1.16.2" 30 | } 31 | } 32 | --------------------------------------------------------------------------------