Skip to Content
ReferenceActionsBROWSER

Browser Action

The browser action drives a real Chrome through chromedp : it opens pages, reads and types into them, waits for elements, and takes screenshots. Chrome or Chromium has to be installed where Probe runs.

It is an external action, published in mozership/probe-browser ; it was built into Probe up to v1.21.0. Probe downloads it the first time a workflow uses it, and runs the executable whose SHA-256 the action.yml at the pinned commit names. It needs Probe v1.21.0 or later. The notes of each release  start with the uses line to copy.

The action cannot tell what a page will do, so it keeps to no guard: under --read-only or --allow-host, a step that uses it is refused unless --allow-action names it.

Basic Syntax

A browser step lists what to do under actions, in order. Every step starts a fresh browser, runs its actions, and closes it, so cookies and a login do not carry over to the next step: put a whole flow in one step.

steps: - name: Read the heading uses: github.com/mozership/probe-browser@42dda412d5d183c091f8baf071237cc090f16052 # v0.1.0 with: actions: - name: navigate url: "{{vars.url}}/" - name: text id: heading selector: h1 test: res.code == 0 && res.results.heading == "Welcome"

Parameters

These go directly under with.

ParameterTypeDefaultDescription
actionsListrequiredThe actions to run, in order. See Actions
timeoutDuration string or number of seconds5sLimit for the whole step: starting the browser and every action. 30s, 30 and "30" all mean 30 seconds; any other value, zero or less, is refused
headlessBooleantrueRun Chrome without a window
window_wInteger1920Window width in pixels
window_hInteger1080Window height in pixels
evidence_dirStringthe temporary directoryWhere the page is saved when the actions fail. See Page at failure

Starting Chrome takes part of timeout, often a second or more, so a short limit can run out before the first page opens.

Actions

Each entry of actions names its action in name and takes these fields:

FieldUsed byDescription
nameallThe action, from the tables below
idactions that return somethingThe key for the result in res.results or res.filepaths. Without it the action’s name is the key, so a later action of the same kind replaces the earlier result
urlnavigateThe address to open
selectoractions on an elementA CSS selector
valuetype, send_keys, selectThe text to use
attributeget_attributeThe attribute to read, as href or [href]. Of a list, only the first entry is read
qualityfull_screenshot1 to 99 saves JPEG at that quality. Anything else, including unset, 0, 100 and above, or a negative number, saves PNG
pathscreenshotsDeprecated: also write the image to this path. Use res.filepaths instead

An action that looks for an element waits until the element appears, and the step fails when timeout runs out first. Most of them also wait for it to be visible.

These open a page or hold the step until the page is in the state the next action needs.

ActionWhat it does
navigateOpens url and waits for the page to load. A network error the browser reports, such as net::ERR_CONNECTION_REFUSED, fails it at once; an address that never answers keeps it waiting until timeout
wait_visibleWaits until selector is visible
wait_not_visibleWaits until selector is not visible
wait_enabledWaits until selector is visible and enabled
wait_readyWaits until the page’s body is ready. selector is ignored

Reading the page

These put a string in res.results, under id or the action’s name.

ActionResult
textThe text content of selector
wait_textWaits until selector is visible, then its text content
valueThe value of a form field, such as an input
get_attributeThe first attribute in attribute of selector, or an empty string when the element does not have it
get_htmlThe outer HTML of selector, once it is visible

Interacting

These act on the page the way a user would. They return nothing.

ActionWhat it does
clickClicks selector once it is visible
double_clickDouble-clicks selector once it is visible
type, send_keysClears selector, then types value into it
submitSubmits the form selector belongs to
focusFocuses selector
scrollScrolls selector into view
selectSets the value attribute of selector to value. It does not choose an option of a <select>; click the option instead
hoverSends a mouseover event to selector. It does not wait, and does nothing when nothing matches
right_clickSends a contextmenu event to selector. It does not wait, and does nothing when nothing matches

Screenshots

These save an image file and put its path in res.filepaths, under id or the action’s name. The file is named for its format, .png or .jpg.

ActionImage
capture_screenshotThe visible part of the window, as PNG
full_screenshotThe whole page, as PNG, or as JPEG when quality is 1 to 99
screenshotOnly selector, once it is visible, as PNG

Response Object

When every action succeeds, the step sees:

FieldTypeDescription
res.codeInteger0
res.resultsObjectWhat the reading actions returned, by id or action name
res.filepathsObjectWhere the screenshots were saved, by id or action name
rt.durationStringHow long the step took, such as "663.268333ms"
statusInteger0

When an action fails there is no response to test: the step fails with an action error, as described in Error Handling.

Examples

Each example is one step, since a step’s actions share one browser and the next step starts a new one.

Logging in

A login and the check that it worked have to share one browser, so they are one step.

secrets: - PASSWORD vars: url: "{{APP_URL}}" user: "{{USERNAME}}" password: "{{PASSWORD}}" jobs: - name: Sign in steps: - name: Log in and reach the dashboard uses: github.com/mozership/probe-browser@42dda412d5d183c091f8baf071237cc090f16052 # v0.1.0 with: timeout: 30s actions: - name: navigate url: "{{vars.url}}/login" - name: type selector: "#username" value: "{{vars.user}}" - name: type selector: "#password" value: "{{vars.password}}" - name: click selector: "button[type='submit']" - name: wait_visible selector: "#dashboard" - name: text id: greeting selector: "#dashboard h1" test: res.code == 0 && res.results.greeting contains vars.user

Reading several values

Give each reading action an id so the results do not replace each other.

- name: Product page uses: github.com/mozership/probe-browser@42dda412d5d183c091f8baf071237cc090f16052 # v0.1.0 with: actions: - name: navigate url: "{{vars.url}}/products/42" - name: text id: title selector: "h1" - name: text id: price selector: ".price" - name: get_attribute id: image selector: "img.product" attribute: [src] test: | res.code == 0 && res.results.title != "" && res.results.price startsWith "$" outputs: image_url: res.results.image

Keeping a screenshot

The path of the saved image is in res.filepaths, ready to print or pass on.

- name: Checkout page uses: github.com/mozership/probe-browser@42dda412d5d183c091f8baf071237cc090f16052 # v0.1.0 with: window_w: 1280 window_h: 800 actions: - name: navigate url: "{{vars.url}}/checkout" - name: full_screenshot id: page test: res.code == 0 echo: "Saved {{res.filepaths.page}}"

Error Handling

An action that cannot finish makes the whole step fail with an action error, which exits the run with status 3. A selector that matches nothing is not an empty result: wait_visible, text, click and the other actions that look for an element keep waiting until the step’s timeout. A navigation fails as soon as the browser reports a network error, such as a refused connection, while an address that never answers also waits until timeout. In every case there is no res to test, and the failure message carries the browser’s error.

Page at failure

When the actions fail, Probe saves the page as it was at that moment: a full-page PNG screenshot and the HTML of the document, under one shared name such as probe-browser-failure-1947177907.png and .html. The failure message names both files along with the page’s URL:

action error in step_execute: action execution failed (caused by: ... context deadline exceeded (page at failure: url http://localhost:8090/, screenshot /tmp/probe-browser-failure-1947177907.png, html /tmp/probe-browser-failure-1947177907.html))

The same message is the failure’s message in the files --report writes. A test that evaluates to false is not an action failure, so the page is not saved then; add a capture_screenshot action to keep it.

The files go to the system’s temporary directory unless evidence_dir names another. The directory is created when needed, which suits uploading it as a CI artifact. The page can show private data, so the files are readable only by the user who ran Probe:

- name: Checkout page uses: github.com/mozership/probe-browser@42dda412d5d183c091f8baf071237cc090f16052 # v0.1.0 with: evidence_dir: out/browser actions: - name: navigate url: "{{vars.url}}/checkout" - name: wait_visible selector: "#pay"

The browser is kept for up to 10 seconds after the timeout so that the page can still be read. If it cannot be, for example because the browser never started or the page was still loading when time ran out, the message says so and nothing is saved.

Running in CI

A CI runner needs a browser and a little more time than a laptop.

  • Install Chrome or Chromium on the runner.
  • Keep headless: true, or provide a display such as Xvfb when a window is needed.
  • Chrome is started with --no-sandbox, as containers usually require, so point it only at sites you trust.
  • Give timeout room for Chrome to start, which is slower on a cold runner.
Updated at