Start Debugging

Playwright .NET 1.64 добавляет Locator.Within(), и это цепочка Locator, прочитанная задом наперёд

Microsoft.Playwright 1.64 добавляет Locator.Within(), чтобы можно было написать 'эта кнопка внутри того диалога'. Быстрая проверка показывает, что он строит ровно тот же локатор, что и parent.Locator(child), включая разрешение Nth() для каждого родителя.

Microsoft.Playwright 1.64.0 появился в NuGet 2026-10-21, а через день вышел 1.64.1 с обновлением встроенного Node.js до 24.22.1. В релизе Chromium 156, Firefox 157 и WebKit 27.2, тестирование WebMCP и скринкасты в VP9, но API, с которым большинство тестовых наборов столкнётся первым, это Locator.Within().

Сначала дочерний элемент, потом родитель

Within(ILocator) возвращает локатор, который находит элементы текущего локатора внутри каждого элемента, подходящего под аргумент. Главное здесь порядок чтения. Если у вас уже есть два локатора, теперь можно сказать “эта кнопка внутри того диалога”, а не строить цепочку снаружи внутрь:

var save = page.GetByRole(AriaRole.Button, new() { Name = "Save" });
var dialog = page.GetByTestId("settings-dialog");

// 1.64+
await save.Within(dialog).ClickAsync();

// Before 1.64
await dialog.Locator(save).ClickAsync();

Относительные локаторы вроде Nth() и First разрешаются отдельно внутри каждого родителя, и именно благодаря этому работают запросы по столбцам:

var thirdColumn = page.GetByRole(AriaRole.Cell).Nth(2)
    .Within(page.GetByRole(AriaRole.Row));

await Expect(thirdColumn).ToHaveTextAsync(new[] { "Apple", "Banana", "Cherry" });

Во что это превращается

Я запустил обе формы в Chromium 156 с Microsoft.Playwright 1.64.1 на .NET SDK 10.0.302, на таблице из трёх строк и странице с двумя кнопками “Save” (одна в диалоге, другая в форме). Результаты:

ЛокаторСовпадения
cells.Nth(2)Apple
cells.Nth(2).Within(rows)Apple, Banana, Cherry
rows.Locator(cells.Nth(2))Apple, Banana, Cherry
rows.Locator("td").Nth(2)Apple
saveSave, Save
save.Within(dialog)Save

ToString() ставит точку: cells.Nth(2).Within(rows) выводит GetByRole(AriaRole.Row).Locator(GetByRole(AriaRole.Cell).Nth(2)), символ в символ как старая цепочка. Within() не новый механизм сопоставления. Это существующая перегрузка Locator(ILocator) с переставленными аргументами, и сообщения об ошибках, и записи в trace viewer будут показывать форму цепочки.

Отсюда два практических следствия:

Breaking change в том же релизе

1.64 также меняет видимость: элементы внутри iframe, который сам не виден, например из-за visibility: hidden, теперь считаются скрытыми для действий, IsVisibleAsync() и ToBeVisibleAsync(). Если тест случайно кликал через скрытый фрейм, теперь он упадёт по таймауту в ожидании видимости. Это стоит проверить перед обновлением в первую очередь, раньше, чем Within().

Обновление:

dotnet add package Microsoft.Playwright --version 1.64.1
pwsh bin/Debug/net10.0/playwright.ps1 install

Учтите, что шаг установки удаляет сборки браузеров от старых версий Playwright, которые он считает неиспользуемыми, так что другому проекту на более старой версии может понадобиться снова запустить свою установку. Если вы используете Playwright для UI-тестов под управлением агентов, дисциплина селекторов из статьи о самовосстанавливающихся E2E-тестах, когда агент переименовывает селекторы хорошо сочетается с такими ограниченными по области локаторами.

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Назад