From fb14cace637066a6217dd83760d4f2fefd5118b5 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Tue, 25 Aug 2026 09:03:16 -0700 Subject: [PATCH] Revert "feat(locator): page-free `by` locators resolved with page.get() (#42157)" This reverts commit 7eae07322944dce17816af3a5c1f6536f6092824. --- docs/src/api/class-by.md | 254 ---------- docs/src/api/class-frame.md | 13 - docs/src/api/class-framelocator.md | 13 - docs/src/api/class-locator.md | 13 - docs/src/api/class-page.md | 13 - docs/src/api/class-playwright.md | 18 - docs/src/api/params.md | 32 -- docs/src/locators.md | 41 -- packages/isomorphic/by.ts | 145 ------ packages/playwright-client/types/types.d.ts | 473 ------------------ packages/playwright-core/index.mjs | 1 - packages/playwright-core/src/client/frame.ts | 6 - .../playwright-core/src/client/locator.ts | 10 - packages/playwright-core/src/client/page.ts | 5 - .../playwright-core/src/client/playwright.ts | 4 - packages/playwright-core/types/types.d.ts | 473 ------------------ packages/playwright/test.mjs | 1 - tests/page/locator-get.spec.ts | 127 ----- .../playwright-test/playwright.config.spec.ts | 27 - 19 files changed, 1669 deletions(-) delete mode 100644 docs/src/api/class-by.md delete mode 100644 packages/isomorphic/by.ts delete mode 100644 tests/page/locator-get.spec.ts diff --git a/docs/src/api/class-by.md b/docs/src/api/class-by.md deleted file mode 100644 index 6e3831443f5d7..0000000000000 --- a/docs/src/api/class-by.md +++ /dev/null @@ -1,254 +0,0 @@ -# class: By -* since: v1.63 -* langs: js - -[By] describes an element without being bound to a [Page] or a [Frame]. It is built with the -top-level [`property: Playwright.by`] object and turned into a regular [Locator] with -[`method: Page.get`], [`method: Frame.get`] or [`method: Locator.get`]. - -Since a [By] carries no page, it can be defined once at module scope and reused by every test, -which makes it a natural fit for page objects. - -**Usage** - -```js -import { by, expect, test } from '@playwright/test'; - -const saveButton = by.role('button', { name: 'Save' }); -const todoItems = by.testId('todo-list').role('listitem'); - -test('saves a todo', async ({ page }) => { - await page.get(saveButton).click(); - await expect(page.get(todoItems)).toHaveCount(1); -}); -``` - -A [By] chain resolves to the same element as the matching [Locator] chain, so -`page.get(by.testId('list').text('Row'))` and `page.getByTestId('list').getByText('Row')` are -interchangeable. Chaining composes rather than replaces: `page.get(outer.get(inner))` and -`page.get(outer).get(inner)` describe the same element. - -## method: By.altText -* since: v1.63 -- returns: <[By]> - -Matches a descendant element by its `alt` text. - -### param: By.altText.text = %%-locator-get-by-text-text-%% -* since: v1.63 - -### option: By.altText.exact = %%-locator-get-by-text-exact-%% -* since: v1.63 - -## method: By.and -* since: v1.63 -- returns: <[By]> - -Narrows down the match to elements that match both this and the given [By]. - -**Usage** - -```js -const saveButton = by.role('button').and(by.title('Subscribe')); -``` - -### param: By.and.by -* since: v1.63 -- `by` <[By]> - -Additional locator to match. - -## method: By.describe -* since: v1.63 -- returns: <[By]> - -Describes the element, the description is used in the trace viewer and the reports. - -### param: By.describe.description -* since: v1.63 -- `description` <[string]> - -Locator description. - -## method: By.filter -* since: v1.63 -- returns: <[By]> - -Narrows down the match according to the options, for example filters by text. It can be chained to -filter multiple times. - -**Usage** - -```js -const rowWithButton = by.get('tr') - .filter({ hasText: 'text in column 1' }) - .filter({ has: by.role('button', { name: 'column 2 button' }) }); -``` - -### option: By.filter.has -* since: v1.63 -- `has` <[By]> - -Narrows down the results to those which contain elements matching this relative [By]. The inner -[By] is queried starting with the outer match, not the document root. - -### option: By.filter.hasNot -* since: v1.63 -- `hasNot` <[By]> - -Matches elements that do not contain an element matching this relative [By]. The inner [By] is -queried starting with the outer match, not the document root. - -### option: By.filter.hasNotText = %%-locator-option-has-not-text-%% -* since: v1.63 - -### option: By.filter.hasText = %%-locator-option-has-text-%% -* since: v1.63 - -### option: By.filter.visible = %%-locator-option-visible-%% -* since: v1.63 - -## method: By.first -* since: v1.63 -- returns: <[By]> - -Matches the first matching element. - -## method: By.get -* since: v1.63 -- returns: <[By]> - -Matches a descendant element by a selector or by another [By]. - -**Usage** - -```js -const firstCell = by.get('table').get('td').first(); - -const listItem = by.role('listitem'); -const unread = by.testId('inbox').get(listItem).filter({ hasText: 'Unread' }); -``` - -**Details** - -Passing a [By] composes rather than replaces, so `outer.get(inner.get(innermost))` and -`outer.get(inner).get(innermost)` describe the same element. - -### param: By.get.selectorOrBy -* since: v1.63 -- `selectorOrBy` <[string]|[By]> - -A selector or a [By] to match inside this one. - -## method: By.label -* since: v1.63 -- returns: <[By]> - -Matches an input element by the text of the associated `