This module contains common patterns for using Cypress with Cucumber (via @badeball/cypress-cucumber-preprocessor
).
yarn add @silverstripe-bespoke/cypress-bespoke-shared --dev
This module will add generic Cucumber steps to your cypress project.
The steps contained in this module is designed to be used with a Page Object Model so you will nee to supply at least one Page object and call the follwing in your global.cy.js
file:
import createGenericSteps from '@silverstripe-bespoke/cypress-bespoke-shared';
import pageObjects from './your-project-somewhere';
createGenericSteps(pageObjects);
you can then start using the Steps included in this module.
Page objects mediate between the test code and your application. Think of if as where the natural language of a Cucumbers step is translated into code.
To do this Page objects have two required properties url
and elements
as below:
type PageObject = {
readonly url: string,
elements: {
[index: string]: string
}
}
The url
will be used by Cypress to navigate to this page (via cy.visit()
).
The elements
object is a map of element names as they appear in steps to a valid JavaScript selector. Eg {'Main navigation': 'nav[role="main"]'}
. Test steps then only need to refer to the element name eg Then the "Main navigation" is visible
.
Step | Parameters | Description | Example |
---|---|---|---|
I am on the {string} |
Page object name | This will set the current page object context | Given I am on the "HomePage" |
I navigate to the {string} |
Page Object Name | This will set the current page object context and navigate to that page. This is normally the first step in a test. | Given I navigate to the "HomePage" |
I am testing the {string} |
Page Object Name | This will set the current page object context, useful when testing distinct features on another page | Given I am testing the "Header" |
I visit {string} |
url string | This will navigate to a given url | Given I visit "/" |
I request {string} |
url string | This will make a get request to the given url | Given I request "/api" |
I am on desktop |
none | This will change the viewport to a desktop size | |
I am on tablet |
none | This will change the viewport to a tablet size | |
I am on mobile |
none | This will change the viewport to a mobile size |
Step | Parameters | Description | Example |
---|---|---|---|
I should see the title is {string} in the browser |
title text | Checks the page title | Then I should see the title is "Home" in the browser |
I should see the url includes {string} |
url fragment | Checks the url contains a substring | Then I should see the url includes "/home" |
Step | Parameters | Description | Example |
---|---|---|---|
I should see the {string} is visible |
page element name | checks the given page element is visible | Then I should see the "Main navigation" is visible |
I should see the {string} of the {string} is visible |
ordinal position, page element name | checks the first, second, third etc. of a given page element is visible | Then I should see the "first" of the "Main navigation items" is visible |
I should see the last of the {string} is visible |
page element name | checks the last of a given page element is visible | Then I should see the last of the "Main navigation items" is visible |
I should see the {string} is not visible |
page element name | checks the given page element is not visible | Then I should see the "Main navigation" is not visible |
I should see the {string} of the {string} is not visible |
ordinal position, page element name | checks the first, second, third etc. of a given page element is not visible | Then I should see the "second" of the "Main navigation items" is not visible |
I should see the last of the {string} is not visible |
page element name | checks the last of a given page element is not visible | Then I should see the last of the "Main navigation items" is not visible |
I should see the {string} is in the viewport |
page element name | checks the given page element is in the viewport. Requires the isInViewport assertion | Then I should see the "tool tip" is in the viewport |
I should see the {string} is not in the viewport |
page element name | checks the given page element is not in the viewport. Requires the isInViewport assertion | Then I should see the "tool tip" is not in the viewport |
I should see {int} {string} |
number and page element name | counts how many of a page element are present | `Then I should see 5 "list items" |
Step | Parameters | Description | Example |
---|---|---|---|
I should see the {string} exists |
page element name | checks the given page element exists | Then I should see the "Main navigation" exists |
I should see the {string} of the {string} exists |
ordinal position, page element name | checks the first, second, third etc. of a given page element exists | Then I should see the "first" of the "Main navigation items" exists |
I should see the last of the {string} exists |
page element name | checks the last of a given page element exists | Then I should see the last of the "Main navigation items" exists |
I should see the {string} does not exist |
page element name | checks the given page element does not exist | Then I should see the "Main navigation" does not exist |
I should see the {string} of the {string} does not exist |
ordinal position, page element name | checks the first, second, third etc. of a given page element does not exist | Then I should see the "fourth" of the "Main navigation items" does not exist |
I should see the last of the {string} does not exist |
page element name | checks the last of a given page element does not exist | Then I should see the last of the "Main navigation items" does not exist |
Step | Parameters | Description | Example |
---|---|---|---|
I should see the {string} contains {string} |
page element name, text | Check if an page element contains a given string | Then I should see the "button" contains "Read More" |
I should see the {string} has attribute {string} |
page element name, attribute name | Checks a page element has a given attribute | Then I should see the "menu" has attribute "hidden" |
I should see the {string} does not have attribute {string} |
page element name, attribute name | Checks a page element does not have a given attribute | Then I should see the "menu" does not have attribute "hidden" |
I should see the {string} has attribute {string} with value {string} |
page element name, attribute name, attribute value | Checks a page element has a given attribute with a given value | Then I should see the "menu" has attribute "aria-expanded" with value "false" |
Step | Parameters | Description | Example |
---|---|---|---|
I should see the {string} form field has value {string} |
page element name, field value | Checks a page element has a given attribute with a given string value | Then I should see the "email" form field has value "test@test.com" |
Step | Parameters | Description | Example |
---|---|---|---|
I wait {int} seconds |
seconds | This will make the test wait for a given length of time | Given I wait 5 seconds |
I wait a bit |
none | Adds a 500ms wait step to the test, useful for quick animations or interactions | Then I wait a bit |
coming soon
Step | Parameters | Description | Example |
---|---|---|---|
I should see the {string} element receive focus |
page element name | Checks an element is in the focus state | Then I should see the "button" element receive focus |
Step | Parameters | Description | Example |
---|---|---|---|
I press the {string} element |
page element name | Clicks or touches a page element | When I press on the "button" element |
I press the first {string} element |
page element name | Clicks or touches the first of a list of page elements | When I press the first "button" element |
I press the second {string} element |
page element name | Clicks or touches the second of a list of page elements | When I press the second "button" element |
Step | Parameters | Description | Example |
---|---|---|---|
I press the Enter key on {string} element |
page element name | Presses the <enter> key on the keyboard |
When I press the Enter key on "button" element |
I press the tab key |
none | Presses the <tab> key on the keyboard |
When I press the tab key |
I press the tab key on {string} |
page element name | Presses the <tab> key on a particular element |
When I press the tab key on "link" |
I type {string} into the {string} field |
field value, page text field | Types the content into the field element | When I type "This is a text field" into the "input" field |
The following shows a basic cypress setup using this module:
Setup re-usable components inside cypress/page_objects/components
directory:
e.g. Header.js
export default {
'Header': '.header',
'Header logo': '.header__logo',
}
Setup an page object as follows in your cypress/page_objects
directory:
import Header from '../components/Header';
export class TestPage {
static url = '/test-page/';
static elements = {
...Header,
'Cta Block Container': '.cta-block',
'Cta Block Header': '.cta-block .cta-block__title',
'Cta Block Links': '.cta-block .cta-block__links'
}
}
Add this page to the index file cypress/page_objects/index.js
:
import TestPage from './testPage';
const pages = {
TestPage: TestPage,
};
export default pages;
Import the page objects to your cypress/common/global.cy.js
file:
import Pages from '../page_objects';
import createSharedSteps from '@silverstripe-bespoke/cypress-bespoke-shared'
createSharedSteps(Pages);
You can now use these steps in a feature file e.g. cypress/e2e/TestPage.feature
Feature: Test Page feature
@desktop
Scenario: A Test page has a CTA block
Given I am on desktop
And I navigate to the "TestPage"
Then I should see the "Cta Block Container" is visible
And I should see the "Cta Block Header" is visible
And I should see the "Cta Block Header" contains "Example title"
And I should see the "third" of the "Cta Block Links" is visible
Add this to the cypress/support/assertions.js
file:
const isInViewport = (_chai, utils) => {
function assertIsInViewport(options) {
const subject = this._obj;
const bottom = Cypress.$(cy.state('window')).height();
const rect = subject[0].getBoundingClientRect();
// Keeping our "is in viewport" check simple. If the top of the element is anywhere in our viewport, and if the
// bottom of the element is lower than the top of our viewport, then we will consider this to be "in view"
this.assert(
rect.top > 0 && rect.bottom > 0 && rect.top <= bottom,
"expected #{this} to be in viewport",
"expected #{this} to not be in viewport",
this._obj
)
}
_chai.Assertion.addMethod('inViewport', assertIsInViewport)
};
chai.use(isInViewport);