The web capability is browser automation on Playwright. There is no separate ctx.web object. The surface is the
Playwright objects the runner puts on the run context. The capability token is the declaration an automation makes
when it uses them.
#The browser surface
Three members of RunContext are the browser:
ctx.pageis the single PlaywrightPagean automation drives. It carries thebaseURL, soctx.page.goto('/orders')resolves against the automation'surl.ctx.contextis theBrowserContext, created with a 1440 by 900 viewport and anen-USlocale.ctx.browseris the launchedBrowser.
The runner launches Chromium headless by default (options.headless ?? true). ctx.page gets a default timeout of
15 seconds and a default navigation timeout of 20 seconds before any automation code runs.
Tracing is on by default. The runner starts a Playwright trace at the beginning of the run and writes trace.zip
beside the run summary. A failure captures a screenshot of the page into the run's screenshots folder without the
automation asking for one.
#Addressing elements by name
An automation does not write a CSS selector. It resolves a named Target through the Target Repository. A target carries an ordered list of authored strategies with a reason on each one. When the first strategy stops matching, the resolver falls through to the next rather than failing the run.
import type { RunContext, Transaction } from '../framework';
import { useTarget } from '../targets';
async function submitOrder(ctx: RunContext, tx: Transaction): Promise<void> {
await ctx.page.goto('/orders');
const submit = await useTarget(ctx, 'orders.submit');
await submit.locator.click();
}
A target strategy is a function of the page, such as
(page: Page) => page.getByRole('button', { name: 'Submit Order' }), so it is a semantic locator rather than a
recorded path. useTarget logs which priority matched, so the run log says whether the fallback was used and why.
#Native dialogs
Playwright's own default is to auto-dismiss an unhandled alert, confirm or prompt, which turns "the user never
confirmed" into a green run. TaskSultan refuses instead. With no declared policy, a dialog fails the transaction as a
BusinessException and records the dialog's kind and message. Declaring a policy makes the decision explicit:
import { defineAutomation } from '../framework';
export default defineAutomation({
id: 'process-payments',
displayName: 'Process payments',
capabilities: ['web'],
url: 'http://localhost:4300',
dialogs: { on: 'accept', kinds: ['confirm'] },
getTransaction: async () => null,
processTransaction: async () => {},
});
on is accept, dismiss or refuse. An absent policy means refuse. Both accept and dismiss are recorded in the
run log, so a run never carries out a confirmation the application never gave without saying so.
#Things that catch people out
Declare 'web' in the automation. It does not gate a facade the way the engine-backed capabilities do, so a missing
declaration will not fail on its own, but the Orchestrator uses the token to place the job on a robot that can run a
browser.
The page timeout is 15 seconds. A step that legitimately waits longer, such as a slow submit, should pass its own
timeout to waitForResponse or waitFor rather than change the default for the whole run.
A web target is only as good as the strategies someone authored. Add a named strategy with a reason; do not add a selector a machine guessed, because it breaks the first time the page is rebuilt.