Cypress Scenario Runner
Run Gherkin scenarios in Cypress without a single line of code.
Cypress Scenario Runner enables you to run Gherkin scenarios like this one:
Feature: Login
===
Scenario: Successful login
---
Given I navigate to "login"
And I set "email input" to "name@example.com"
And I set "password input" to "abc123"
When I click "login button"
Then I should be on "home"
…without needing to write any Cypress glue code like cy.visit()
, cy.click()
, etc. All you need to do is tag HTML elements:
<input … data-test="email input" />
<input … data-test="password input" />
<button … data-test="login button">Login</button>
and map route names to URIs:
{
"login": "/login"
}
Table of contents
Installation
Requires:
- Node.js 8.0+
cypress
cypress-cucumber-preprocessor
npm install --save-dev cypress cypress-cucumber-preprocessor cypress-scenario-runner
$(npm bin)/install-cypress-scenario-runner
The installer will create or modify a handful of files. You should review and commit those changes.
Usage
Writing test scenarios
Test scenarios are written in Gherkin syntax:
Feature: Login
===
Scenario: Successful login
---
Given I navigate to "login"
And I set "email input" to "name@example.com"
And I set "password input" to "abc123"
When I click "login button"
Then I should be on "home"
Each line in the scenario is called a step. cypress-scenario-runner
works by using a predefined set of reusable step templates, but you can also add your own (see Customization):
Actions
Step | Description | Examples |
---|---|---|
I navigate to {route} |
Navigates the browser to a preconfigured route (see Mapping routes) or an absolute URL | navigation.feature |
I click {element} |
Clicks the first element with a matching tag (see Tagging elements) | pointer-events.feature |
I set {element} to {string} |
Sets the first matching input to the given value (see Working with inputs) | input/ |
I set: |
Same as the step above, but for setting multiple inputs using an inline data table (see Using data tables) | input/ |
I wait for {element} to disappear |
Waits for all matching elements to be invisible (ie. is(':visible') returns false), checking every 500ms |
visibility.feature |
I wait {float} seconds |
Pauses test execution for the specified number of seconds; fractional seconds allowed | miscellaneous.feature |
I pause |
Pauses test execution until manually resumed (see cy.pause() ) |
And I pause |
I debug |
Sets a debugger breakpoint (see cy.debug() ) |
And I debug |
Assertions
Step | Description | Examples |
---|---|---|
I should be on {route} |
Asserts that the current page URL matches the specified route (see Mapping routes), an absolute URL, or a regular expression | navigation.feature |
I should not be on {route} |
Asserts the inverse of the step above | navigation.feature |
{element} should be visible |
Asserts that the first matching element is visible, using .should('be.visible')
|
visibility.feature |
{element} should not be visible |
Asserts that the first matching element is not visible, using .should('not.be.visible')
|
visibility.feature |
{element} should have {int} occurrences |
Asserts that the number of matching elements (visible and invisible) is exactly some value | counting.feature |
{element} should have at least {int} occurrences |
Asserts that the number of matching elements (visible and invisible) is greater than or equal to some value | counting.feature |
{element} should have at most {int} occurrences |
Asserts that the number of matching elements (visible and invisible) is less than or equal to some value | counting.feature |
{element} should be set to {string} |
Asserts that the value of an input element (<input> , <select> , <textarea> ) matches the given string; for inputs that accept multiple values (eg. checkboxes, multi-selects), the value used for comparison is the string value of each input, concatenated with , (eg. one, two, three ) |
input/ |
{element} text should be {string} |
Asserts that a non-input element's text content matches the given string, ignoring case and surrounding whitespace | text-content.feature |
elements text should be: |
Same as the step above, but for asserting multiple elements using an inline data table (see Using data tables) | text-content.feature |
{element} text should not be {string} |
Asserts the inverse of the step above | text-content.feature |
elements text should not be: |
Same as the step above, but for asserting multiple elements using an inline data table (see Using data tables) | text-content.feature |
{element} text should contain {string} |
Asserts that a non-input element's text content contains the given string, ignoring case and surrounding whitespace | text-content.feature |
elements text should contain: |
Same as the step above, but for asserting multiple elements using an inline data table (see Using data tables) | text-content.feature |
{element} text should not contain {string} |
Asserts the inverse of the step above | text-content.feature |
elements text should not contain: |
Same as the step above, but for asserting multiple elements using an inline data table (see Using data tables) | text-content.feature |
Text in {brackets}
above are parameters whose values must be (double) quoted in the scenario. For example, this step template:
I set {element} to {string}
should be written like this in a test scenario:
And I set "email input" to "name@example.com"
The full Gherkin specification is supported along with additional enhancements by cypress-cucumber-preprocessor
. For instance, you can use scenario templates/outlines, data tables, and tags in your scenarios.
See the cypress/integration/
directory for more examples.
Tagging elements
HTML attributes are used to map {element}
step parameters to their corresponding HTML elements. data-test
attributes is used by default, but this is configurable.
<!-- login.html -->
<input name="email" data-test="email input" />
<input name="password" data-test="password input" />
<button type="submit" data-test="login button">Login</button>
Element options
Many Cypress commands accept an optional options
object that can be used to customize how the command is executed (eg. cy.type(text, options)
). These options can be set on a per-element basis via a data-options
attribute. Example:
<input
name="search"
type="text"
data-test="search input"
+ data-options="{ force: true, log: true }"
>
Mapping routes
Routes need to be provided for navigation steps like these to work:
Given I navigate to "login"
A map of all route names to URIs should be provided to addSteps()
in the cypress/support/step_definitions/index.js
file created during installation. Route URIs can be absolute URLs, relative to the web root, or regular expressions.
const { addSteps } = require('cypress-scenario-runner')
addSteps({
+ routes: {
+ login: '/login',
+ 'a specific product': '/products/acme-widget',
+ 'any product': '\/products\/.*'
+ }
})
Working with inputs
Like other HTML elements, input elements are selectable by their data-test
attribute (or whichever attribute you've configured).
Supported types
The step I set {element} to {string}
can be used to set the value of nearly any type of input:
<input type="checkbox">
<input type="color">
<input type="date">
<input type="datetime-local">
<input type="email">
<input type="file">
<input type="hidden">
<input type="image">
<input type="month">
<input type="number">
<input type="password">
<input type="radio">
<input type="range">
<input type="search">
<input type="tel">
<input type="text">
<input type="time">
<input type="url">
<input type="week">
<select></select>
<textarea></textarea>
Input value and options
TBD
Wrapped inputs
When using UI frameworks, it may not be practical to add data-test
and other attributes directly to the input elements themselves. In such cases, those attributes can be added to an ancestor element that wraps the input. For example:
<my-custom-input data-test="some input"></my-custom-input>
This is convenient when checkboxes are wrapped with their labels:
<label data-test="color options">
<input type="checkbox" name="colors" value="red" />
<input type="checkbox" name="colors" value="green" />
<input type="checkbox" name="colors" value="blue" />
</label>
Selects
<select>
options can be selected by their value or by their label. For example, given:
<select name="select" data-test="select input">
<option value="Value A">Label A</option>
<option value="Value B">Label B</option>
<option value="Value C">Label C</option>
</select>
The second <option>
can be selected by its value Value B
or by its label Label B
:
# By value:
I set "select input" to "Value B"
# By label:
I set "select input" to "Label B"
For more example usage, see input/select.feature.
Multi-selects
For multi-selects (ie. <select multiple>
), multiple options can be selected by stringing together their labels or values with commas. For example, given:
<select multiple name="select" data-test="select input">
<option value="Value A">Label A</option>
<option value="Value B">Label B</option>
<option value="Value C">Label C</option>
</select>
The second and third <option>
s can be selected by their values or by their labels:
# By values:
I set "select input" to "Value B, Value C"
# By labels:
I set "select input" to "Label B, Label C"
For more example usage, see input/select.feature.
Checkboxes
Checkboxes can be checked by their value or by their data-value
attributes (or whichever attribute you've configured for input values). For example, given:
<input type="checkbox" name="color" value="f00" data-test="colors" data-value="red" />
<input type="checkbox" name="color" value="0f0" data-test="colors" data-value="green" />
<input type="checkbox" name="color" value="00f" data-test="colors" data-value="blue" />
The second checkbox can be set by its data-value
attribute green
or by its value 0f0
:
# By data-value:
I set "colors" to "green"
# By value:
I set "colors" to "0f0"
Multiple checkboxes can be checked individually by data-value
or by value:
# By data-value:
I set "colors" to "green"
I set "colors" to "blue"
# By value:
I set "colors" to "0f0"
I set "colors" to "00f"
Multiple checkboxes can also be checked together by stringing together their data-value
or value
attributes with commas:
# By data-value:
I set "colors" to "green, blue"
# By value:
I set "colors" to "0f0, 00f"
NOTE: Setting one or more checkboxes does not clear the other checkboxes.
For more example usage, see input/checkbox.feature.
Using data tables
TBD
For more example usage, see input/tables.feature.
Running scenarios
Scenario files can be run directly with Cypress:
$(npm bin)/cypress run [files]
or by using the Cypress UI:
$(npm bin)/cypress open
Customization
TBD
- Options
- Custom steps
- API