Workflows Actions

Link to Workflows Actions copied to clipboard

CLI workflow actions allow you to test complex workflows such as those used in forms and single-page web apps.

When running axe DevTools CLI with the spec command, you can specify actions to run against the page. Run these actions before or after CLI runs accessibility tests. Actions allow you to perform tasks like clicking a button, entering text into a form field, dismissing a popup, or waiting for a specific page state.

Action Example

It's helpful to see a complete action example. The following example logs into the Deque University page and runs an analysis on the logged-in user's dashboard. Both YAML and JSON versions are included.

First is the YAML version of the example:

---
projects:
- name: Deque University login flow
  id: deque-university-login-flow
  pageList:
  - name: homepage
    url: https://dequeuniversity.com/
    actions:
    - click element ".loginLink"
    - wait for element ".loginUsername" to be found
    - type "user@example.com" into element ".loginUsername"
    - type "secretpassword" into element "#loginPassword"
    - click element "input[type=submit]"
    - wait for element ".logoutLink" to be found
    - analyze page

Below is the equivalent JSON example:

{
  "projects": [
    {
      "name": "Deque University login flow",
      "id": "deque-university-login-flow",
      "pageList": [
        {
          "name": "homepage",
          "url": "https://dequeuniversity.com/",
          "actions": [
            "click element \".loginLink\"",
            "wait for element \".loginUsername\" to be found",
            "type \"user@example.com\" into element \".loginUsername\"",
            "type \"secretpassword\" into element \"#loginPassword\"",
            "click element \"input[type=submit]\"",
            "wait for element \".logoutLink\" to be found",
            "analyze page"
          ]
        }
      ]
    }
  ]
}

Action Types

There are two types of actions: page-based actions and global actions.

Page-based actions are procedural actions that run in the order specified on a page-by-page basis within a project. See Page Actions below for more information.

Global actions listen for state changes on all pages in a project and react accordingly. For example, the CLI global action, dismiss modal, detects state changes when a page displays a modal the user must dismiss before proceeding with any other task. See Global Actions for more information.

Selectors

Whenever a selector can be used to specify an element on the page, it can be specified as either a string or a list of strings, and you can use CSS selectors or XPath selectors.

note

Using a list selects elements within iframes if you use CSS selectors.

The array examples below select a submit button <input> element within an iframe with the id inner-frame inside an iframe with the id outer-frame. The examples are YAML and JSON and demonstrate CSS selectors and XPath selectors.

An array of CSS selectors is shown below in YAML:

click element [ "#outer-frame", "#inner-frame", "input[type=submit]" ]

Or as follows in JSON:

"click element [\"#outer-frame\", \"#inner-frame\", \"input[type=submit]\"]",

The equivalent using XPATH selectors in YAML is:

click element [ "//iframe[@id='outer-frame']", "//iframe[@id='inner-frame']", "//input[@type='submit']" ]

In JSON, the equivalent selector is:

"click element [\"//iframe[@id='outer-frame']\", \"//iframe[@id='inner-frame']\", \"//input[@type='submit']\"]",

Page actions

CLI supports nine page-based actions:

  1. analyze: run an accessibility analysis
  2. change: change the value of an <input> or <select> via JavaScript
  3. click: click an element
  4. dismiss: dismiss a popup (or modal)
  5. eval: evaluate arbitrary JavaScript
  6. press: press a key (with or without modifiers)
  7. select: select an option in a <select>
  8. type: type into an <input>
  9. wait: wait for a specific state

You may use any combination of these actions in any order, but analyze must be called at least once.

Analyze action

The analyze action performs an accessibility analysis. This action must be used at least once per page.

You can provide an optional ruleset. The default ruleset is wcag2. The available optional rulesets are wcag2, wcag21, wcag22, and 508. You may also use a custom ruleset.

The wcag21 ruleset is the default ruleset for other axe DevTools products. The ruleset includes WCAG2A, WCAG2AA, WCAG2.1A, and WCAG2.1AA rules with best practices turned off.

You may specify only to analyze specific elements or not to analyze elements.

For more information on including or excluding elements, see the "Context Parameter" section of the axe API documentation.

Provide an optional title string, useful when running multiple analyses on the same page.

Analyze examples

Analyze the page using the 508 ruleset (YAML):

analyze page with ruleset "508"

JSON:

"analyze page with ruleset \"508\""

Analyze the page using the default (WCAG2) ruleset (YAML):

analyze the page

JSON:

"analyze the page"

Analyze the page with fewer keystrokes (YAML):

analyze

JSON:

"analyze"

Analyze the page with a custom title (YAML):

analyze the page with title "custom title"

JSON:

"analyze the page with title \"custom title\""

Analyze only a specific element on the page (YAML):

analyze only element "#idOfElement"

JSON:

"analyze only element \"#idOfElement\""

Analyze only a specific element and elements with a specific class (YAML):

analyze only element "#idOfElement" and element ".classToAnalyze"

JSON:

"analyze only element \"#idOfElement\" and element \".classToAnalyze\""

Analyze everything except images that are immediate children of paragraphs (YAML):

analyze the page excluding element "p > img"

JSON:

"analyze the page excluding element \"p > img\""

Analyze everything except a specific element inside <frame> elements with a specific class (YAML):

analyze the page excluding element [ ".classOfFrameToExclude\", "#idOfElement\" ]

JSON:

"analyze the page excluding element [\".classOfFrameToExclude\", \"#idOfElement\"]"

Set a Custom Export Directory

Setting the export directory enables you to specify where to save analysis results.

Follow these examples to specify a custom export directory.

The following syntax saves analysis results in the directory homepage-team (YAML):

analyze the page and save in "./homepage-team/"

JSON:

"analyze the page and save in \"./homepage-team/\""

The following syntax saves analysis results in both the default location for saved results as well as homepage-team (YAML):

analyze the page and save a copy in "./homepage-team/"

JSON:

"analyze the page and save a copy in \"./homepage-team/\""

Save the results for this in the project-wide folder and save a copy in a different folder (YAML):

analyze the page and save a copy in "some/other/directory"

JSON:

"analyze the page and save a copy in \"some/other/directory\""

The following example saves analysis results in both the default location for saved results as well as homepage-team (YAML):

analyze the page and save a copy in "./homepage-team/"

JSON:

"analyze the page and save a copy in \"./homepage-team/\""

Use the default ruleset for the version of axe in use instead of wcag2 (YAML):

analyze the page with the source default ruleset

JSON:

"analyze the page with the source default ruleset"

Putting everything together: Analyze only images within iframe elements with the class third-party and forms that aren't validated on submission, excluding elements with the class old-api, using the 508 ruleset, with "What is this testing" as the title and saving in the folder Results for Some test.

First, the example in YAML:

analyze only element [ "#third-party", "img"] and element "form[novalidate]" excluding element "#old-api" with ruleset "508" with title "What is this testing" and save in "Results for Some test"

The same example in JSON is as follows:

"analyze only element [\"#third-party\", \"img\"] and element \"form[novalidate]\" excluding element \"#old-api\" with ruleset \"508\" with title \"What is this testing\" and save in \"Results for Some test\""

Change Action

The change action changes the value of <input>, <textarea> or <select> elements using JavaScript. The change action is useful for cases where "regular" DOM events are prohibited.

Change example

Here is an example of changing the value of the <input> element (YAML):

change the value of "input[name=song]" to "too many puppies"

JSON:

"change the value of \"input[name=song]\" to \"too many puppies\""

Click action

The click action instructs the browser to click an element (specified by a CSS selector).

Click examples

Click the first element which matches the .myButton CSS selector (YAML):

click element ".myButton"

JSON:

"click element \".myButton\""

Click the body (YAML):

click "body"

JSON:

"click \"body\""

Dismiss action

The dismiss action closes the page's popup or modal element. Provide a CSS selector for the modal and its close button. The action fails gracefully if either the modal or close button is missing.

This action does not dismiss native alert() or confirm() calls.

Dismiss example

Close the modal matching the .myModal CSS selector using the button matching .myModal .close (YAML):

dismiss modal ".myModal" with close button ".myModal .close"

JSON:

"dismiss modal \".myModal\" with close button \".myModal .close\""

Eval action

The eval action executes arbitrary JavaScript on the page and is useful for performing custom actions or manipulating the DOM.

Eval examples

Change the page's title (YAML):

eval "document.title = 'hello world'"

JSON:

"eval \"document.title = 'hello world'\""

Scroll an element into view (YAML):

eval "document.querySelector('.someElement').scrollIntoView()"

JSON:

"eval \"document.querySelector('.someElement').scrollIntoView()\""

Scroll to the bottom of the page (YAML):

eval "window.scrollTo(0, document.body.scrollHeight)"

JSON:

"eval \"window.scrollTo(0, document.body.scrollHeight)\""

Press action

The press action performs a single key down (with or without modifiers) on an element.

Find the supported key names in the Selenium documentation.

Press examples

Press H on the body element (YAML):

press "H" on "body"

JSON:

"press \"H\" on \"body\""

Press Shift+Tab on the .navigation element:

press "shift+tab" on element ".navigation"

JSON:

"press \"shift+tab\" on element \".navigation\""

Press Shift+Control+7 on the .foo element (YAML):

press "shift+control+7" on element ".foo"

JSON:

"press \"shift+control+7\" on element \".foo\""

Select action

The select action selects an <option> of a <select> element by its visible text, not its value.

Select examples

Assuming the DOM structure:

<select class="mySelect">
  <option></option>
  <option value="1">dog</option>
  <option value="2">cat</option>
  <option value="3">fish</option>
</select>

Select the "dog" option (YAML):

select the "dog" option in ".mySelect"

JSON:

"select the \"dog\" option in \".mySelect\""

Select the "cat" option (YAML):

select the "cat" option in element ".mySelect"

JSON:

"select the \"cat\" option in element \".mySelect\""

Type action

The type action types a string into an <input> element and is useful for filling out forms and populating search bars, for instance.

Type examples

Type "user@example.com" into the email address input (YAML):

type "user@example.com" into element "input[type=email]"

JSON:

"type \"user@example.com\" into element \"input[type=email]\""

Type "hello world" into the <textarea> matching .Message (YAML):

type "hello world" into "textarea.Message"

JSON:

"type \"hello world\" into \"textarea.Message\""

Wait action

The wait action does one of two things:

  1. Waits for a specific element state.
  2. Sleeps for a specified amount of time.

When used to wait for an element to enter a state, provide both the element's CSS selector and the state. Supported wait states include:

  • visible: the element is visible on the page.
  • hidden: the element is hidden, but exists on the page.
  • selected: the element is selected.
  • enabled: the element is enabled.
  • disabled: the element is disabled.
  • found: the element exists on the page.

When used to sleep, the wait action accepts a timeout value. Milliseconds correspond to numeric values. When provided as a string, the CLI attempts to convert the string to milliseconds. For example, if provided 3m, CLI sleeps for 180,000 milliseconds (3 minutes); if provided 1000, CLI sleeps for 1,000 milliseconds.

note

The ms package provides string-to-millisecond parsing.

Wait examples

Wait for 1 minute (YAML):

wait for 1m

JSON:

"wait for 1m"

Wait for 30 milliseconds (YAML):

wait for 30

JSON:

"wait for 30"

Wait for 1 second (YAML):

wait for 1s

JSON:

"wait for 1s"

Wait for the first element matching the CSS selector .myElement to be hidden (YAML):

wait for element ".myElement" to be hidden

JSON:

"wait for element \".myElement\" to be hidden"

Wait for the first element matching the CSS selector .myElement to be found (YAML):

wait for element ".myElement" to be found

JSON:

"wait for element \".myElement\" to be found"

Type "sloth" into the search box with a specified key delay (to mimic human typing) (YAML):

type "sloth" into "input[type=search]" with a 150ms key delay

JSON:

"type \"sloth\" into \"input[type=search]\" with a 150ms key delay"

Global Actions

There are some essential points to remember about the CLI global dismiss modal action:

  • Global actions run on every page included in a CLI project running in spec mode.
  • Global actions are not procedural and do not happen in any specific order. Global actions respond to events and page state changes. For example, the dismiss modal action waits for a page to display a modal that the user must dismiss before any further page-based procedural actions may continue.
  • CLI global actions work in the CLI's spec and headless URI mode.

A site where every page contains random popup modal dialogs requiring users to dismiss the dialogs manually is problematic. The CLI provides a global action that listens for and dismisses the random modal popups as the CLI tests the page-specific actions.

Add the CLI dismiss modal global action to your projects after the projects name and before the pagelist properties. The following example shows the YAML version:

---
projects:
- id: demo
  name: CLI demo
  globalActions:
  - dismiss modal "#__next .survey" with close button ".survey button.close"
  pageList:
  - name: homepage
    url: https://dequelabs.github.io/aget-demo-site
  - name: popup
    url: https://dequelabs.github.io/aget-demo-site
    actions:
    - wait for element "#__next header nav" to be visible
    - click element "#__next header nav a[href*=popup]"
    - wait for element ".content button" to be found
    - analyze with title "before popup"
    - click element ".content button"
    - analyze with title "with popup"
    - dismiss modal ".ReactModal__Content" with close button ".ReactModal__Content
      .close"
    - analyze with title "after popup"
  - name: contact
    url: https://dequelabs.github.io/aget-demo-site/contact
    actions:
    - analyze with title "form disabled"
    - wait for element "#__next .toggle" to be found
    - click element ".toggle button"
    - wait for element "input[name=name]" to be enabled
    - analyze with title "form enabled"
    - type "stephen" into element "input[name=name]"
    - type "555-555-5555" into element "input[name=phone]"
    - type "stephen@deque.com" into element "input[name=email]"
    - type "hello world" into element "textarea[name=message]"
    - click element "button[type=submit]"
    - wait for element ".thanks" to be found
    - analyze with title "thanks message"

The equivalent JSON version is shown below:

{
  "projects": [
    {
      "id": "demo",
      "name": "CLI demo",
      "globalActions": [
        "dismiss modal \"#__next .survey\" with close button \".survey button.close\""
      ],
      "pageList": [
        {
          "name": "homepage",
          "url": "https://dequelabs.github.io/aget-demo-site"
        },
        {
          "name": "popup",
          "url": "https://dequelabs.github.io/aget-demo-site",
          "actions": [
            "wait for element \"#__next header nav\" to be visible",
            "click element \"#__next header nav a[href*=popup]\"",
            "wait for element \".content button\" to be found",
            "analyze with title \"before popup\"",
            "click element \".content button\"",
            "analyze with title \"with popup\"",
            "dismiss modal \".ReactModal__Content\" with close button \".ReactModal__Content .close\"",
            "analyze with title \"after popup\""
          ]
        },
        {
          "name": "contact",
          "url": "https://dequelabs.github.io/aget-demo-site/contact",
          "actions": [
            "analyze with title \"form disabled\"",
            "wait for element \"#__next .toggle\" to be found",
            "click element \".toggle button\"",
            "wait for element \"input[name=name]\" to be enabled",
            "analyze with title \"form enabled\"",
            "type \"stephen\" into element \"input[name=name]\"",
            "type \"555-555-5555\" into element \"input[name=phone]\"",
            "type \"stephen@deque.com\" into element \"input[name=email]\"",
            "type \"hello world\" into element \"textarea[name=message]\"",
            "click element \"button[type=submit]\"",
            "wait for element \".thanks\" to be found",
            "analyze with title \"thanks message\""
          ]
        }
      ]
    }
  ]
}