Selectors & scoping
Dawn reimplements Dusk's ElementResolver semantics on Playwright locators. Selectors are compiled lazily - the DOM is only queried when an action runs, so Playwright's auto-waiting applies with no find-then-act race.
@dusk selectors
$browser->click('@login-button');
// → [dusk="login-button"]The HTML attribute is configurable, as in Dusk:
use Dawn\Dawn;
Dawn::selectorHtmlAttribute('data-testid');Field resolution
Dusk's resolution orders are preserved:
type('email', …)→#emailby id, elseinput[name='email'],textarea[name='email'], else the string as a selector;select('role', …)→ id, elseselect[name='role'];check('terms')→ id, elseinput[type=checkbox][name='terms'];press('Save')→ as a selector, else byname, else submitvalue, else button text.
One documented divergence: Dusk tries these candidates one by one; Dawn compiles them into a single CSS list resolved in DOM order. The two only differ when multiple candidates match different elements at the same time.
Scoping with within()
$browser->within('.modal', function (Browser $modal) {
$modal->assertSee('Confirm')
->press('OK');
});Scopes compose by selector-prefixing (body .modal .actions …), exactly like Dusk - including the quirk that #id field lookups bypass the scope (Dusk resolves ids document-wide). elsewhere() escapes the current scope; whenAvailable() waits for the selector, then scopes into it.
Page element aliases
ElementResolver::pageElements() supports Dusk page-object shorthand maps (['@email' => 'input#email-address']), replaced longest-key-first before @ translation - verified against test cases ported from laravel/dusk's own suite. The full Dusk Pages & Components object model (Dawn\Page, Dawn\Component, visit(Page), component()) is supported - see the compatibility table.