Action Steps

Action steps are the minimum vocabulary a team needs to drive a page: press, click, follow, attach. They read like plain English, so product owners can review feature files without translation, yet each one maps to a real Playwright interaction underneath. Every action goes through Playwright's actionability checks - the element must be attached, visible, stable, and enabled before the click fires - so you almost never need an explicit wait before an action step.

Each step comes in two flavors. The text variants (press "Log In", click "Contact Us", follow "About") match the exact visible label, which keeps scenarios readable and resilient to markup changes. The attribute variants (... by attr) reach elements that have no readable text - icon buttons, generated markup - by id, class, name, placeholder, or any data-* attribute. Attribute targets also resolve through the selector registry, so a registered friendly name like "buy button" works anywhere a raw selector does.

When a text-based action fails, webship-js does not dump a raw Playwright stack trace. It raises a friendly error naming the step and the target, plus hints: check that the visible text matches exactly (matching is case-sensitive and anchored to the whole label), switch to the by attr variant if the element has no readable text, or add a wait for ... to appear step if the element renders late.

Quick reference

StepWhat it does
When I press "Log In"Press a button, submit input, or link by its visible text.
When I press "btn-pressid" by attrPress a button by its attribute (id, class, name, placeholder, data-*).
When I click "Contact Us"Click a link or button by its visible text.
When I click "#about-us-id" by attrClick a link or button by its attribute (id, class, name, data-*).
When I click "Edit" in the "John Smith" rowClick a clickable element inside a table row identified by text.
When I follow "Contact Us"Follow a link by its visible text.
When I attach the file "profile-icon.jpg" to "#profile-icon-upload"Attach a file from tests/assets/ to a file input.

Steps in detail

When I press "Log In"

Presses a button-like element - <button>, <input type="button">, <input type="submit">, anything with role="button", or a link styled as a button - whose visible text matches the quoted label exactly. The pronoun and the words "the" and "button" are optional, so When I press "Submit", And I press the "Save as" button, and When we press "Cancel" all hit the same definition. If several elements share the label, the first match wins.

Given I am on "/test--when--i-press-button.html"
 When I press the "Submit" button
 Then I should see "Button Pressed Successfully"

When I press "btn-pressid" by attr

Presses a button located by attribute rather than label. With a bare value like "btn-pressid", the step fans out across id, class, name, data-testid, data-test-id, data-test, data-cy, aria-label, value, placeholder, and title and clicks the first hit. Name a specific attribute - by "placeholder" attribute, by "data-selector" attr - to match only that attribute (case-insensitively). Verbatim CSS like #id, .class, or [attr=value] passes through untouched. Note that submit buttons usually carry their label in the value attribute, hence the common pattern I press "Submit" by "value" attr.

Given I am on "/test--when--i-attach-file-to-feild.html"
 When I press "Submit" by attr
  And I press "Register" by "value" attr

When I click "Contact Us"

Clicks a link or button by its visible text. The searched pool covers <a>, <button>, role="button", and button/submit inputs, so it is the general-purpose "activate whatever carries this label" step. The text must match the whole label exactly (case-sensitive); a partial like "Contact" will not match "Contact Us". Failures raise the friendly hint block described in the intro.

Given I am on "/test--when--i-click-link.html"
 When I click "About us link"
  And I wait max of 2 seconds
 Then I should see "About Us"

When I click "#about-us-id" by attr

The attribute-targeted counterpart of click, using the same selector fan-out as press ... by attr. Ideal for icon links, elements identified only by data-* hooks, and names registered in the selector registry. All of these are equivalent ways to name the same variant: by attr, by attribute, by "class" attr, by its "id" attribute.

Given I am on "/test--when--i-click-link.html"
 When I click "#aboutUsid" by attr
 When I click "aboutUsid" by its "id" attribute
 When I click "aboutUs" by "class" attr

When I click "Edit" in the "John Smith" row

Scopes the click to a single table row: it finds the first <tr> containing the row-identifier text, then clicks the link or button inside that row whose label matches exactly. If the row holds no matching clickable element, the step falls back to clicking the exact text itself - useful for cells that toggle behavior via a click handler. This is the step for admin listings and data grids, where a dozen rows each carry their own "Edit" and "Delete" actions.

Given I am on "/test--when--i-click-text-in-table-row.html"
 When I click "Edit" in the "John Smith" row
 Then I should see "Performed (edit) action on (John Smith)" in the "#action-message" element by attr
 When I click "Track" in the "Order #67890" row

When I follow "Contact Us"

Follows a link by its visible text. Unlike click, this step is accessibility-first: it tries Playwright's getByRole('link', { name }) with an exact accessible name, then falls back to an exact text match on <a> elements. Use it when you specifically mean "navigate via this link" - it will never accidentally press a button that happens to share the label.

Given I am on "/links.html"
 When I follow "Read more"
 Then I should be on "/about-us.html"

When I attach the file "profile-icon.jpg" to "#profile-icon-upload"

Uploads a file into an <input type="file">. The file name is resolved against the project's assets folder (default tests/assets/), so keep test fixtures there and reference them by bare name. The second argument is a CSS selector that must address the file input itself - #resume, input[name=logo], or [data-testid=csv-upload] all work. The word "the" is optional: attach file "resume.pdf" to "#resume" is equally valid.

Given I am on "/test--when--i-attach-file-to-feild.html"
 When I attach the file "webshipco.png" to "#fileUpload"
  And I press "Submit" by attr

Complete example

Adapted from the suite's own feature files, exercising every step in this group against the shipped fixture pages in examples/:

Feature: Drive a page with the core action steps
  As a tester
  I want to press, click, follow, and attach
  So that I can automate any interactive flow

  Scenario: Press a button by label and by attribute
    Given I am on "/test--when--i-press-button.html"
     When I press the "Submit" button
     Then I should see "Button Pressed Successfully"

  Scenario: Click a link by text, then by attribute
    Given I am on "/test--when--i-click-link.html"
     When I click "About us link"
      And I wait max of 2 seconds
     Then I should see "About Us"
    Given I am on "/test--when--i-click-link.html"
     When I click "#aboutUsid" by attr
     Then I should see "About Us"

  Scenario: Row-scoped actions in a data table
    Given I am on "/test--when--i-click-text-in-table-row.html"
     When I click "Edit" in the "John Smith" row
     Then I should see "Performed (edit) action on (John Smith)" in the "#action-message" element by attr
     When I click "Download" in the "Product A" row
     Then I should see "Performed (download) action on (Product A)" in the "#action-message" element by attr

  Scenario: Attach a file and submit
    Given I am on "/test--when--i-attach-file-to-feild.html"
     When I attach the file "webshipco.png" to "#fileUpload"
      And I press "Submit" by attr
      And I wait 2 seconds

Tips

  • Text matching is exact and case-sensitive. press "log in" will not find a button labeled Log In.
  • Regex metacharacters in labels are escaped automatically - click "View Details" in the "Order #12345" row and labels containing (, ., or ? just work.
  • If an element renders after an AJAX call, pair the action with a smart wait such as When I wait for "#dashboard" to appear; the BBR wait engine returns as soon as the page settles, never a fixed sleep.
  • Prefer follow for navigation links and press for form submission; keep click for mixed cases. The intent reads better in review.
  • Register long selectors once with I add "buy button" selector for "..." css selector and then use I click "buy button" by attr everywhere.

Back to all step groups