[{"data":1,"prerenderedAt":73},["ShallowReactive",2],{"wiki-test-automation-ui-test-locators-en":3},{"meta":4,"html":8,"headings":9,"words":72},{"title":5,"description":6,"published":7,"updated":7},"Locators in UI tests","Locators in UI tests: by role, label, placeholder, test id, text, CSS and XPath, resilience to changes, the order of choice and waiting for elements.","2026-11-03","\u003Cp>A \u003Cstrong>locator\u003C/strong> is a description of how an automated UI test finds an element of the user interface: the button it clicks, the field it fills, the message it checks. A locator consists of a strategy and a value: &quot;the button whose accessible name is Sign in&quot;, &quot;the element with the attribute \u003Ccode>data-testid\u003C/code> equal to \u003Ccode>cart-count\u003C/code>&quot;, &quot;the CSS selector \u003Ccode>form &gt; button.primary\u003C/code>&quot;. The test refers to elements only through locators, so locators are the point where the test depends on the markup of the page.\u003C/p>\n\u003Cp>The browser automation standard, W3C WebDriver, defines five location strategies; its Level 1 became a W3C Recommendation on 5 June 2018, and Level 2 is a Working Draft (the version of 2 July 2026). Selenium supports eight traditional strategies, among them id, CSS selector and XPath. Playwright, since version 1.27, and Testing Library offer locators by user-facing attributes: role, label, text. Playwright's documentation recommends them over CSS and XPath. The roles and accessible names they rely on are defined by WAI-ARIA 1.2, a W3C Recommendation of 6 June 2023.\u003C/p>\n\u003Ch2 id=\"the-problem-locators-solve\" class=\"wiki-heading\">The problem locators solve\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"the-problem-locators-solve\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>A test must refer to elements of the page, and the page changes. Developers rename CSS classes, wrap elements in new containers, move blocks, change texts. A test should fail when the behavior of the product breaks and should keep passing when only the markup around the behavior changes.\u003C/p>\n\u003Cp>Each kind of locator ties the test to a different property of the element. A long CSS chain ties it to the structure of the document. Playwright's documentation shows such a chain as an example of bad practice that leads to unstable tests:\u003C/p>\n\u003Cdiv class=\"wiki-code\" data-language=\"typescript\">\u003Cdiv class=\"wiki-code__header\">\u003Cspan class=\"wiki-code__language\">typescript\u003C/span>\u003Cbutton type=\"button\" class=\"wiki-code__copy\" data-wiki-copy data-copied-label=\"Copied\">\u003Csvg class=\"wiki-code__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z\"/>\u003C/svg>\u003Csvg class=\"wiki-code__icon wiki-code__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003Cspan class=\"wiki-code__label\">Copy\u003C/span>\u003Cspan class=\"wiki-code__label wiki-code__label--done\">Copied\u003C/span>\u003C/button>\u003C/div>\u003Cpre>\u003Ccode>page.locator('#tsf &gt; div:nth-child(2) &gt; div.A8SBwf &gt; div.RNNXgb &gt; div &gt; div.a4bIc &gt; input');\u003C/code>\u003C/pre>\u003C/div>\n\u003Cp>Any new wrapper \u003Ccode>div\u003C/code> or renamed class breaks this locator, although the input field itself is still on the page and works. The choice of locator kind decides which changes of the page break the test and which do not.\u003C/p>\n\u003Ch2 id=\"kinds-of-locators\" class=\"wiki-heading\">Kinds of locators\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"kinds-of-locators\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>The examples in this section refer to one login form.\u003C/p>\n\u003Cdiv class=\"wiki-code\" data-language=\"html\">\u003Cdiv class=\"wiki-code__header\">\u003Cspan class=\"wiki-code__language\">html\u003C/span>\u003Cbutton type=\"button\" class=\"wiki-code__copy\" data-wiki-copy data-copied-label=\"Copied\">\u003Csvg class=\"wiki-code__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z\"/>\u003C/svg>\u003Csvg class=\"wiki-code__icon wiki-code__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003Cspan class=\"wiki-code__label\">Copy\u003C/span>\u003Cspan class=\"wiki-code__label wiki-code__label--done\">Copied\u003C/span>\u003C/button>\u003C/div>\u003Cpre>\u003Ccode>&lt;form&gt;\n  &lt;h1&gt;Sign in&lt;/h1&gt;\n  &lt;label for=&quot;email&quot;&gt;Email&lt;/label&gt;\n  &lt;input id=&quot;email&quot; type=&quot;email&quot; placeholder=&quot;name@example.com&quot;&gt;\n  &lt;label for=&quot;password&quot;&gt;Password&lt;/label&gt;\n  &lt;input id=&quot;password&quot; type=&quot;password&quot;&gt;\n  &lt;img src=&quot;/logo.svg&quot; alt=&quot;Shop logo&quot;&gt;\n  &lt;span title=&quot;Items in cart&quot; data-testid=&quot;cart-count&quot;&gt;0&lt;/span&gt;\n  &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&gt;Sign in&lt;/button&gt;\n&lt;/form&gt;\u003C/code>\u003C/pre>\u003C/div>\n\u003Ch3 id=\"by-role\" class=\"wiki-heading\">By role\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"by-role\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>A \u003Cstrong>locator by role\u003C/strong> finds an element by its ARIA role and its \u003Cstrong>accessible name\u003C/strong>. The role says what the element is: \u003Ccode>button\u003C/code>, \u003Ccode>link\u003C/code>, \u003Ccode>textbox\u003C/code>, \u003Ccode>checkbox\u003C/code>, \u003Ccode>heading\u003C/code>. HTML elements have implicit roles: according to the W3C specification ARIA in HTML, a \u003Ccode>button\u003C/code> element has the role \u003Ccode>button\u003C/code>, an \u003Ccode>a\u003C/code> element with \u003Ccode>href\u003C/code> has the role \u003Ccode>link\u003C/code>, and \u003Ccode>h1\u003C/code> to \u003Ccode>h6\u003C/code> have the role \u003Ccode>heading\u003C/code>. WAI-ARIA defines the accessible name as the name of a user interface element; it can come from the visible text, a label or an attribute such as \u003Ccode>aria-label\u003C/code>.\u003C/p>\n\u003Cp>In Playwright, \u003Ccode>page.getByRole('button', { name: 'Sign in' })\u003C/code> finds the button of the form. By default the \u003Ccode>name\u003C/code> matches as a case-insensitive substring; the option \u003Ccode>exact: true\u003C/code> requires a case-sensitive match of the whole string. Further options filter by state and level: \u003Ccode>checked\u003C/code>, \u003Ccode>disabled\u003C/code>, \u003Ccode>expanded\u003C/code>, \u003Ccode>pressed\u003C/code>, \u003Ccode>selected\u003C/code>, \u003Ccode>level\u003C/code>. Playwright's documentation notes that role locators follow the W3C specifications for ARIA roles, attributes and accessible names, but do not replace accessibility audits.\u003C/p>\n\u003Ch3 id=\"by-label\" class=\"wiki-heading\">By label\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"by-label\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>A \u003Cstrong>locator by label\u003C/strong> finds a form field by the text of its label. Playwright's \u003Ccode>page.getByLabel('Email')\u003C/code> matches the text of the associated \u003Ccode>label\u003C/code> element or of the element referenced by \u003Ccode>aria-labelledby\u003C/code>, or the value of \u003Ccode>aria-label\u003C/code>. Testing Library calls its equivalent \u003Ccode>getByLabelText\u003C/code> and recommends it for form fields, because users find fields by their labels.\u003C/p>\n\u003Ch3 id=\"by-placeholder\" class=\"wiki-heading\">By placeholder\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"by-placeholder\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>A \u003Cstrong>locator by placeholder\u003C/strong> finds an input by its \u003Ccode>placeholder\u003C/code> attribute: \u003Ccode>page.getByPlaceholder('name@example.com')\u003C/code>. Testing Library treats it as a fallback, because a placeholder is not a substitute for a label.\u003C/p>\n\u003Ch3 id=\"by-text\" class=\"wiki-heading\">By text\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"by-text\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>A \u003Cstrong>locator by text\u003C/strong> finds an element by its text content: \u003Ccode>page.getByText('Sign in')\u003C/code>. Playwright normalizes whitespace when it matches text, even with an exact match, and accepts a substring, a whole string or a regular expression. Its documentation recommends text locators for non-interactive elements such as \u003Ccode>div\u003C/code>, \u003Ccode>span\u003C/code> and \u003Ccode>p\u003C/code>, and role locators for interactive elements such as \u003Ccode>button\u003C/code>, \u003Ccode>a\u003C/code> and \u003Ccode>input\u003C/code>. In the form above, \u003Ccode>getByText('Sign in')\u003C/code> matches both the heading and the button. Playwright locators are strict: an action on a locator that matches more than one element throws an exception. A role locator separates the two: \u003Ccode>getByRole('heading', { name: 'Sign in' })\u003C/code> and \u003Ccode>getByRole('button', { name: 'Sign in' })\u003C/code>.\u003C/p>\n\u003Ch3 id=\"by-alt-text-and-title\" class=\"wiki-heading\">By alt text and title\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"by-alt-text-and-title\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>A \u003Cstrong>locator by alt text\u003C/strong> finds an element, usually an image, by its text alternative: \u003Ccode>page.getByAltText('Shop logo')\u003C/code>. A \u003Cstrong>locator by title\u003C/strong> finds an element by its \u003Ccode>title\u003C/code> attribute: \u003Ccode>page.getByTitle('Items in cart')\u003C/code>. Testing Library warns that \u003Ccode>title\u003C/code> is not read consistently by screen readers and is not visible by default.\u003C/p>\n\u003Ch3 id=\"by-test-id\" class=\"wiki-heading\">By test id\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"by-test-id\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>A \u003Cstrong>test id\u003C/strong> is an attribute added to the markup only so that tests can find the element. Playwright's \u003Ccode>page.getByTestId('cart-count')\u003C/code> looks for the attribute \u003Ccode>data-testid\u003C/code> by default. Another attribute name can be set with \u003Ccode>testIdAttribute\u003C/code> in the test configuration or with \u003Ccode>selectors.setTestIdAttribute()\u003C/code>.\u003C/p>\n\u003Cdiv class=\"wiki-code\" data-language=\"typescript\">\u003Cdiv class=\"wiki-code__header\">\u003Cspan class=\"wiki-code__language\">typescript\u003C/span>\u003Cbutton type=\"button\" class=\"wiki-code__copy\" data-wiki-copy data-copied-label=\"Copied\">\u003Csvg class=\"wiki-code__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z\"/>\u003C/svg>\u003Csvg class=\"wiki-code__icon wiki-code__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003Cspan class=\"wiki-code__label\">Copy\u003C/span>\u003Cspan class=\"wiki-code__label wiki-code__label--done\">Copied\u003C/span>\u003C/button>\u003C/div>\u003Cpre>\u003Ccode>import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n  use: {\n    testIdAttribute: 'data-pw',\n  },\n});\u003C/code>\u003C/pre>\u003C/div>\n\u003Cp>Playwright's documentation calls testing by test ids the most resilient way, because a test id survives changes of text and role. It also notes that test ids are not user-facing: a test that finds an element by test id does not check what the user sees.\u003C/p>\n\u003Ch3 id=\"css-selectors\" class=\"wiki-heading\">CSS selectors\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"css-selectors\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>A CSS selector finds elements by tag, id, classes, attributes and position in the document: \u003Ccode>button.btn-primary\u003C/code>, \u003Ccode>#email\u003C/code>, \u003Ccode>form &gt; button\u003C/code>. In Playwright, CSS is passed to \u003Ccode>page.locator()\u003C/code>, with or without the prefix \u003Ccode>css=\u003C/code>. CSS selectors can express everything the other kinds express through attributes, for example \u003Ccode>[data-testid='cart-count']\u003C/code> or \u003Ccode>[placeholder='name@example.com']\u003C/code>. Their stability depends on what they refer to: an id or a test id attribute is stable, classes and positions are not.\u003C/p>\n\u003Ch3 id=\"xpath\" class=\"wiki-heading\">XPath\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"xpath\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h3>\n\u003Cp>XPath is a language for selecting parts of an XML document; its version 1.0 is a W3C Recommendation of 16 November 1999. An XPath expression can select by structure, attributes and text: \u003Ccode>//button[normalize-space()='Sign in']\u003C/code>, \u003Ccode>//form/input[2]\u003C/code>. XPath can move from an element to its parent and siblings. In Playwright, XPath is passed to \u003Ccode>page.locator()\u003C/code>, with the prefix \u003Ccode>xpath=\u003C/code> or starting with \u003Ccode>//\u003C/code>. Playwright's documentation notes that XPath does not pierce shadow roots.\u003C/p>\n\u003Ch2 id=\"locators-in-webdriver-and-selenium\" class=\"wiki-heading\">Locators in WebDriver and Selenium\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"locators-in-webdriver-and-selenium\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>The W3C WebDriver specification defines five location strategies. A client passes a strategy and a value to the command Find Element, \u003Ccode>POST /session/{session id}/element\u003C/code>.\u003C/p>\n\u003Cdiv class=\"wiki-table wiki-table--cols-2\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Keyword\u003C/th>\n\u003Cth>What it finds\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>css selector\u003C/code>\u003C/td>\n\u003Ctd>Elements matching a CSS selector\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>link text\u003C/code>\u003C/td>\n\u003Ctd>Links whose visible text equals the value\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>partial link text\u003C/code>\u003C/td>\n\u003Ctd>Links whose visible text contains the value\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>tag name\u003C/code>\u003C/td>\n\u003Ctd>Elements with the given tag name\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>xpath\u003C/code>\u003C/td>\n\u003Ctd>Elements selected by an XPath expression\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\u003C/div>\n\u003Cp>Selenium supports eight traditional strategies: the five above and \u003Ccode>id\u003C/code>, \u003Ccode>name\u003C/code> and \u003Ccode>class name\u003C/code>. In the Python binding they are constants of the class \u003Ccode>By\u003C/code>; their string values match the keywords: \u003Ccode>By.CSS_SELECTOR\u003C/code> is \u003Ccode>&quot;css selector&quot;\u003C/code>, \u003Ccode>By.ID\u003C/code> is \u003Ccode>&quot;id&quot;\u003C/code>. The strategy \u003Ccode>class name\u003C/code> does not accept compound class names.\u003C/p>\n\u003Cdiv class=\"wiki-code\" data-language=\"python\">\u003Cdiv class=\"wiki-code__header\">\u003Cspan class=\"wiki-code__language\">python\u003C/span>\u003Cbutton type=\"button\" class=\"wiki-code__copy\" data-wiki-copy data-copied-label=\"Copied\">\u003Csvg class=\"wiki-code__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z\"/>\u003C/svg>\u003Csvg class=\"wiki-code__icon wiki-code__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003Cspan class=\"wiki-code__label\">Copy\u003C/span>\u003Cspan class=\"wiki-code__label wiki-code__label--done\">Copied\u003C/span>\u003C/button>\u003C/div>\u003Cpre>\u003Ccode>from selenium import webdriver\nfrom selenium.webdriver.common.by import By\n\ndriver = webdriver.Chrome()\ndriver.get(&quot;https://shop.example.com/login&quot;)\n\ndriver.find_element(By.ID, &quot;email&quot;).send_keys(&quot;user@example.com&quot;)\ndriver.find_element(By.CSS_SELECTOR, &quot;input[type='password']&quot;).send_keys(&quot;secret&quot;)\ndriver.find_element(By.XPATH, &quot;//button[normalize-space()='Sign in']&quot;).click()\u003C/code>\u003C/pre>\u003C/div>\n\u003Cp>None of the eight strategies finds an element by ARIA role and accessible name, so in Selenium a role-like locator is expressed through CSS or XPath. Selenium's documentation on encouraged practices gives its own order: an id is preferred when it is available, unique and predictable; otherwise a well-written CSS selector; XPath works as well as CSS, but its syntax is complicated and often difficult to debug. It calls a locator by tag name dangerous, because a page usually contains many elements with the same tag, and notes that link text strategies work only on links.\u003C/p>\n\u003Ch2 id=\"locators-in-playwright-and-testing-library\" class=\"wiki-heading\">Locators in Playwright and Testing Library\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"locators-in-playwright-and-testing-library\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>Playwright lists its recommended built-in locators in this order: \u003Ccode>getByRole\u003C/code>, \u003Ccode>getByText\u003C/code>, \u003Ccode>getByLabel\u003C/code>, \u003Ccode>getByPlaceholder\u003C/code>, \u003Ccode>getByAltText\u003C/code>, \u003Ccode>getByTitle\u003C/code>, \u003Ccode>getByTestId\u003C/code>. Its best practices recommend prioritizing user-facing attributes and explicit contracts, and state that CSS and XPath are not recommended because the DOM can often change. A test of the login form uses only recommended locators:\u003C/p>\n\u003Cdiv class=\"wiki-code\" data-language=\"typescript\">\u003Cdiv class=\"wiki-code__header\">\u003Cspan class=\"wiki-code__language\">typescript\u003C/span>\u003Cbutton type=\"button\" class=\"wiki-code__copy\" data-wiki-copy data-copied-label=\"Copied\">\u003Csvg class=\"wiki-code__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z\"/>\u003C/svg>\u003Csvg class=\"wiki-code__icon wiki-code__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003Cspan class=\"wiki-code__label\">Copy\u003C/span>\u003Cspan class=\"wiki-code__label wiki-code__label--done\">Copied\u003C/span>\u003C/button>\u003C/div>\u003Cpre>\u003Ccode>import { test, expect } from '@playwright/test';\n\ntest('user signs in', async ({ page }) =&gt; {\n  await page.goto('https://shop.example.com/login');\n\n  await page.getByLabel('Email').fill('user@example.com');\n  await page.getByLabel('Password').fill('secret');\n  await page.getByRole('button', { name: 'Sign in' }).click();\n\n  await expect(page.getByRole('heading', { name: 'My orders' })).toBeVisible();\n  await expect(page.getByTestId('cart-count')).toHaveText('0');\n});\u003C/code>\u003C/pre>\u003C/div>\n\u003Cp>Locators can be chained and filtered to narrow the search to a part of the page. \u003Ccode>page.getByRole('listitem').filter({ hasText: 'Product 2' })\u003C/code> selects the list item that contains the text, and a further \u003Ccode>getByRole('button', { name: 'Add to cart' })\u003C/code> selects the button inside it.\u003C/p>\n\u003Cp>Testing Library follows the guiding principle: &quot;The more your tests resemble the way your software is used, the more confidence they can give you.&quot; Its documentation divides queries into three groups by priority. The table compares the two orders.\u003C/p>\n\u003Cdiv class=\"wiki-table wiki-table--cols-3\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Priority\u003C/th>\n\u003Cth>Testing Library\u003C/th>\n\u003Cth>Playwright\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>1\u003C/td>\n\u003Ctd>Accessible to everyone: \u003Ccode>getByRole\u003C/code>, \u003Ccode>getByLabelText\u003C/code>, \u003Ccode>getByPlaceholderText\u003C/code>, \u003Ccode>getByText\u003C/code>, \u003Ccode>getByDisplayValue\u003C/code>\u003C/td>\n\u003Ctd>\u003Ccode>getByRole\u003C/code>, \u003Ccode>getByText\u003C/code>, \u003Ccode>getByLabel\u003C/code>, \u003Ccode>getByPlaceholder\u003C/code>\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>2\u003C/td>\n\u003Ctd>Semantic: \u003Ccode>getByAltText\u003C/code>, \u003Ccode>getByTitle\u003C/code>\u003C/td>\n\u003Ctd>\u003Ccode>getByAltText\u003C/code>, \u003Ccode>getByTitle\u003C/code>\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>3\u003C/td>\n\u003Ctd>Test ids: \u003Ccode>getByTestId\u003C/code>\u003C/td>\n\u003Ctd>\u003Ccode>getByTestId\u003C/code>\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Not listed\u003C/td>\n\u003Ctd>CSS and XPath\u003C/td>\n\u003Ctd>CSS and XPath, not recommended\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\u003C/div>\n\u003Cp>Both orders put the role first and the test id last among their own methods. The difference is inside the first group: Testing Library places the label before the text, Playwright the text before the label.\u003C/p>\n\u003Ch2 id=\"resilience-to-changes\" class=\"wiki-heading\">Resilience to changes\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"resilience-to-changes\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>The kinds of locators differ in which changes break them. The table compares them by three properties: stability under changes of markup, readability of the test, and dependence on the texts of the interface.\u003C/p>\n\u003Cdiv class=\"wiki-table wiki-table--cols-4\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Locator kind\u003C/th>\n\u003Cth>Stability under markup changes\u003C/th>\n\u003Cth>Readability\u003C/th>\n\u003Cth>Depends on texts\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Role and accessible name\u003C/td>\n\u003Ctd>High\u003C/td>\n\u003Ctd>High\u003C/td>\n\u003Ctd>Yes, through the name\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Label\u003C/td>\n\u003Ctd>High\u003C/td>\n\u003Ctd>High\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Placeholder\u003C/td>\n\u003Ctd>Medium\u003C/td>\n\u003Ctd>High\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Text\u003C/td>\n\u003Ctd>Medium\u003C/td>\n\u003Ctd>High\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Alt text, title\u003C/td>\n\u003Ctd>Medium\u003C/td>\n\u003Ctd>Medium\u003C/td>\n\u003Ctd>Yes\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Test id\u003C/td>\n\u003Ctd>High\u003C/td>\n\u003Ctd>Medium\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Id\u003C/td>\n\u003Ctd>High if the id is stable\u003C/td>\n\u003Ctd>Medium\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>CSS by classes and structure\u003C/td>\n\u003Ctd>Low\u003C/td>\n\u003Ctd>Low\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>XPath by structure\u003C/td>\n\u003Ctd>Low\u003C/td>\n\u003Ctd>Low\u003C/td>\n\u003Ctd>No\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>XPath or CSS by text or attribute\u003C/td>\n\u003Ctd>Medium\u003C/td>\n\u003Ctd>Low\u003C/td>\n\u003Ctd>Depends on the attribute\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\u003C/div>\n\u003Cp>The assessment follows from what each locator refers to. A role and an accessible name change only when the element becomes a different control or gets a different name, which is a change the user notices too. A test id changes only when someone edits it, but it is invisible to the user, so a test that relies on it does not notice that the button lost its label. Classes and positions change with refactoring and styling, without any change of behavior.\u003C/p>\n\u003Cp>A locator that depends on texts breaks when the text is edited. This is intended when the text is part of what the test checks, and unwanted when the text is only a way to find the element. Ids generated at runtime, for example from a counter, make locators by id unstable: the value can differ between page loads.\u003C/p>\n\u003Ch2 id=\"choosing-a-locator\" class=\"wiki-heading\">Choosing a locator\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"choosing-a-locator\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>The recommendations of Playwright, Testing Library and Selenium lead to a common order of preference:\u003C/p>\n\u003Col>\n\u003Cli>\u003Cstrong>Role and accessible name\u003C/strong>, for interactive elements: buttons, links, fields, checkboxes.\u003C/li>\n\u003Cli>\u003Cstrong>Label\u003C/strong>, for form fields; \u003Cstrong>text\u003C/strong>, for non-interactive elements.\u003C/li>\n\u003Cli>\u003Cstrong>Placeholder, alt text, title\u003C/strong>, when the element has no role, label or text.\u003C/li>\n\u003Cli>\u003Cstrong>Test id\u003C/strong>, when the user-facing attributes are absent, ambiguous or change for reasons unrelated to the test.\u003C/li>\n\u003Cli>\u003Cstrong>CSS or XPath\u003C/strong>, when nothing else works, for example in third-party markup that cannot be changed; preferably by stable attributes rather than structure.\u003C/li>\n\u003C/ol>\n\u003Cp>A locator that matches several elements is narrowed by chaining from a unique container rather than by position. A locator by role that cannot be written is a signal about the page itself: an element without an accessible name is also hard to use with a screen reader. Playwright's code generator, \u003Ccode>npx playwright codegen\u003C/code>, picks locators by the same priority: role, text and test id.\u003C/p>\n\u003Ch2 id=\"waiting-for-elements\" class=\"wiki-heading\">Waiting for elements\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"waiting-for-elements\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>A locator describes an element that may not exist yet. After a click, the page sends a request, receives a response and renders new content, and the test must wait for it. The way the tool waits is one of the causes of tests that fail without a \u003Cspan class=\"wiki-term\" tabindex=\"0\" data-wiki-term=\"defect\">defect\u003C/span>; such tests are described in the article \u003Ca href=\"/en/wiki/test-automation/flaky-tests\" class=\"wiki-link wiki-link--article\">Flaky tests\u003C/a>.\u003C/p>\n\u003Cp>\u003Cstrong>Auto-waiting\u003C/strong> in Playwright means that before each action the tool waits until the element passes actionability checks. For \u003Ccode>click\u003C/code> the checks are: the element is visible, stable, receives events and is enabled; for \u003Ccode>fill\u003C/code> it is visible, enabled and editable. If the checks do not pass within the timeout, the action fails with \u003Ccode>TimeoutError\u003C/code>. A Playwright locator is resolved to an element each time it is used. Assertions such as \u003Ccode>expect(locator).toBeVisible()\u003C/code> wait until the condition is met, while \u003Ccode>locator.isVisible()\u003C/code> returns immediately.\u003C/p>\n\u003Cp>Selenium has two mechanisms. An \u003Cstrong>implicit wait\u003C/strong> is a global setting for the whole session: every element search retries until the timeout; its default value is 0, so a missing element causes an error immediately. An \u003Cstrong>explicit wait\u003C/strong> is a loop in the test code that polls for a specific condition until it is true or the timeout expires. Selenium's documentation warns against mixing the two, because it can cause unpredictable wait times.\u003C/p>\n\u003Cdiv class=\"wiki-code\" data-language=\"python\">\u003Cdiv class=\"wiki-code__header\">\u003Cspan class=\"wiki-code__language\">python\u003C/span>\u003Cbutton type=\"button\" class=\"wiki-code__copy\" data-wiki-copy data-copied-label=\"Copied\">\u003Csvg class=\"wiki-code__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M216,28H88A12,12,0,0,0,76,40V76H40A12,12,0,0,0,28,88V216a12,12,0,0,0,12,12H168a12,12,0,0,0,12-12V180h36a12,12,0,0,0,12-12V40A12,12,0,0,0,216,28ZM156,204H52V100H156Zm48-48H180V88a12,12,0,0,0-12-12H100V52H204Z\"/>\u003C/svg>\u003Csvg class=\"wiki-code__icon wiki-code__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003Cspan class=\"wiki-code__label\">Copy\u003C/span>\u003Cspan class=\"wiki-code__label wiki-code__label--done\">Copied\u003C/span>\u003C/button>\u003C/div>\u003Cpre>\u003Ccode>from selenium.webdriver.common.by import By\nfrom selenium.webdriver.support.wait import WebDriverWait\n\nwait = WebDriverWait(driver, timeout=5)\nheading = wait.until(\n    lambda d: d.find_element(By.XPATH, &quot;//h1[normalize-space()='My orders']&quot;)\n)\nassert heading.is_displayed()\u003C/code>\u003C/pre>\u003C/div>\n\u003Cp>\u003Ccode>WebDriverWait.until\u003C/code> calls the function until it returns a truthy value and raises \u003Ccode>TimeoutException\u003C/code> when the timeout expires; by default it ignores \u003Ccode>NoSuchElementException\u003C/code> between attempts. A \u003Ccode>WebElement\u003C/code> found by Selenium refers to one specific element: if the page re-renders it, the reference becomes stale, and the element must be located again. Testing Library has a similar split: \u003Ccode>getBy\u003C/code> queries return immediately, \u003Ccode>findBy\u003C/code> queries return a promise and retry until a default timeout of 1000 ms.\u003C/p>\n\u003Ch2 id=\"locators-and-localization\" class=\"wiki-heading\">Locators and localization\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"locators-and-localization\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>Locators by role, label, placeholder, text, alt text and title depend on the texts of the interface, and these texts differ between languages. A test written as \u003Ccode>getByRole('button', { name: 'Sign in' })\u003C/code> fails on the German version of the page, where the button has a different name. Playwright's own example of a test id shows the case: a button with the text \u003Ccode>Itinéraire\u003C/code> and the attribute \u003Ccode>data-testid=&quot;directions&quot;\u003C/code>, found by \u003Ccode>getByTestId('directions')\u003C/code> regardless of the language.\u003C/p>\n\u003Cp>A suite that runs against several locales has a few options:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>one locale for most tests\u003C/strong>: Playwright sets the browser locale with the \u003Ccode>locale\u003C/code> option in the configuration, for example \u003Ccode>locale: 'en-GB'\u003C/code>;\u003C/li>\n\u003Cli>\u003Cstrong>texts from the translation resources\u003C/strong>: the test takes the expected name from the same translation files that the application uses, so the locator follows the translation;\u003C/li>\n\u003Cli>\u003Cstrong>test ids for elements whose text varies\u003C/strong>: the locator does not depend on the language, and a separate check verifies the texts;\u003C/li>\n\u003Cli>\u003Cstrong>regular expressions\u003C/strong> in \u003Ccode>name\u003C/code> or \u003Ccode>getByText\u003C/code>, when the variants are few and known.\u003C/li>\n\u003C/ul>\n\u003Cp>The choice also depends on what the test checks. A test of the translation itself must use texts; a test of a business flow need not.\u003C/p>\n\u003Ch2 id=\"locators-in-an-object-repository\" class=\"wiki-heading\">Locators in an object repository\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"locators-in-an-object-repository\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>When the same element is used in many tests, its locator is written once and referred to by name. A change of the markup is then fixed in one place instead of every test. Two ways to organize this, \u003Cspan class=\"wiki-term\" tabindex=\"0\" data-wiki-term=\"page-object\">page objects\u003C/span> and an \u003Cspan class=\"wiki-term\" tabindex=\"0\" data-wiki-term=\"object-repository\">object repository\u003C/span> with the structure &quot;pages, elements&quot;, are described in the article \u003Ca href=\"/en/wiki/test-automation/page-object-and-object-repository\" class=\"wiki-link wiki-link--article\">Object repository and the Page Object pattern\u003C/a>. Which test levels need locators at all is explained in the article \u003Ca href=\"/en/wiki/test-automation/automation-levels-and-test-pyramid\" class=\"wiki-link wiki-link--article\">Test automation levels and the test pyramid\u003C/a>.\u003C/p>\n\u003Ch2 id=\"locator-selector-and-element-handle\" class=\"wiki-heading\">Locator, selector and element handle\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"locator-selector-and-element-handle\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cp>Three words are used for related things.\u003C/p>\n\u003Cdiv class=\"wiki-table wiki-table--cols-4\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003C/th>\n\u003Cth>Selector\u003C/th>\n\u003Cth>Locator\u003C/th>\n\u003Cth>Element handle\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>What it is\u003C/td>\n\u003Ctd>A string in CSS or XPath syntax\u003C/td>\n\u003Ctd>A strategy and value for finding an element\u003C/td>\n\u003Ctd>A reference to one found element\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Example\u003C/td>\n\u003Ctd>\u003Ccode>button.btn-primary\u003C/code>\u003C/td>\n\u003Ctd>\u003Ccode>getByRole('button', { name: 'Sign in' })\u003C/code>\u003C/td>\n\u003Ctd>Selenium \u003Ccode>WebElement\u003C/code>, Playwright \u003Ccode>ElementHandle\u003C/code>\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>When it is resolved\u003C/td>\n\u003Ctd>When it is used\u003C/td>\n\u003Ctd>Each time it is used (Playwright)\u003C/td>\n\u003Ctd>Once, at the search\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>After re-rendering\u003C/td>\n\u003Ctd>Not applicable\u003C/td>\n\u003Ctd>Finds the new element\u003C/td>\n\u003Ctd>Becomes stale\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\u003C/div>\n\u003Cp>A selector is one possible value of a locator: a CSS or XPath locator contains a selector, a locator by role does not. Playwright's documentation states the difference between the last two directly: an \u003Ccode>ElementHandle\u003C/code> points to a particular element, while a \u003Ccode>Locator\u003C/code> captures the logic of how to retrieve an element. It discourages the use of \u003Ccode>ElementHandle\u003C/code> in favor of locators and web-first assertions.\u003C/p>\n\u003Ch2 id=\"terms\" class=\"wiki-heading\">Terms\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"terms\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cdiv class=\"wiki-table wiki-table--cols-2\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Term\u003C/th>\n\u003Cth>Meaning\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Locator\u003C/td>\n\u003Ctd>Description of how a UI test finds an element: a strategy and a value\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Location strategy\u003C/td>\n\u003Ctd>Method of finding an element: by role, label, text, test id, CSS, XPath and others\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Accessible name\u003C/td>\n\u003Ctd>Name of a user interface element exposed to assistive technology\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Test id\u003C/td>\n\u003Ctd>Attribute added to the markup only so that tests can find the element, by default \u003Ccode>data-testid\u003C/code>\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Auto-waiting\u003C/td>\n\u003Ctd>Waiting by the tool, before each action, until the element passes actionability checks\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Implicit wait\u003C/td>\n\u003Ctd>Global session setting under which every element search retries until a timeout\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Explicit wait\u003C/td>\n\u003Ctd>Loop in the test code that polls for a specific condition until it is true or a timeout expires\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Stale element reference\u003C/td>\n\u003Ctd>Reference to an element that was found earlier but is no longer in the document\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\u003C/div>\n\u003Ch2 id=\"sources\" class=\"wiki-heading\">Sources\u003Cbutton type=\"button\" class=\"wiki-heading__anchor\" data-wiki-anchor=\"sources\" aria-label=\"Copy link to section\" data-copied-label=\"Link to section copied\">\u003Csvg class=\"wiki-heading__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M117.18,188.74a12,12,0,0,1,0,17l-5.12,5.12A58.26,58.26,0,0,1,70.6,228h0A58.62,58.62,0,0,1,29.14,127.92L63.89,93.17a58.64,58.64,0,0,1,98.56,28.11,12,12,0,1,1-23.37,5.44,34.65,34.65,0,0,0-58.22-16.58L46.11,144.89A34.62,34.62,0,0,0,70.57,204h0a34.41,34.41,0,0,0,24.49-10.14l5.11-5.12A12,12,0,0,1,117.18,188.74ZM226.83,45.17a58.65,58.65,0,0,0-82.93,0l-5.11,5.11a12,12,0,0,0,17,17l5.12-5.12a34.63,34.63,0,1,1,49,49L175.1,145.86A34.39,34.39,0,0,1,150.61,156h0a34.63,34.63,0,0,1-33.69-26.72,12,12,0,0,0-23.38,5.44A58.64,58.64,0,0,0,150.56,180h.05a58.28,58.28,0,0,0,41.47-17.17l34.75-34.75a58.62,58.62,0,0,0,0-82.91Z\"/>\u003C/svg>\u003Csvg class=\"wiki-heading__icon wiki-heading__icon--done\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z\"/>\u003C/svg>\u003C/button>\u003C/h2>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https://www.w3.org/TR/webdriver1/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">WebDriver, W3C Recommendation, 5 June 2018\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.w3.org/TR/webdriver2/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">WebDriver Level 2, W3C Working Draft\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.w3.org/TR/wai-aria-1.2/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Accessible Rich Internet Applications (WAI-ARIA) 1.2, W3C Recommendation, 6 June 2023\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.w3.org/TR/html-aria/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">ARIA in HTML, W3C Recommendation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.w3.org/TR/xpath-10/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">XML Path Language (XPath) Version 1.0, W3C Recommendation, 16 November 1999\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://playwright.dev/docs/locators\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Locators, Playwright documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://playwright.dev/docs/best-practices\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Best Practices, Playwright documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://playwright.dev/docs/actionability\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Auto-waiting, Playwright documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://playwright.dev/docs/api/class-page\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Page class reference, Playwright documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://playwright.dev/docs/api/class-elementhandle\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">ElementHandle class reference, Playwright documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://playwright.dev/docs/emulation\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Emulation, Playwright documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://testing-library.com/docs/queries/about/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">About Queries, Testing Library documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://testing-library.com/docs/guiding-principles\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Guiding Principles, Testing Library documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.selenium.dev/documentation/webdriver/elements/locators/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Locator strategies, Selenium documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.selenium.dev/documentation/test_practices/encouraged/locators/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Locators, encouraged test practices, Selenium documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.selenium.dev/documentation/webdriver/waits/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Waiting strategies, Selenium documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">Understanding common errors, Selenium documentation\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003Cli>\u003Ca href=\"https://selenium-python-api-docs.readthedocs.io/en/selenium-4.39.0/_modules/selenium/webdriver/common/by.html\" target=\"_blank\" rel=\"noopener\" class=\"wiki-link wiki-link--external\">selenium.webdriver.common.by, Selenium Python API\u003Csvg class=\"wiki-link__icon\" viewBox=\"0 0 256 256\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\">\u003Cpath d=\"M228,104a12,12,0,0,1-24,0V69l-59.51,59.51a12,12,0,0,1-17-17L187,52H152a12,12,0,0,1,0-24h64a12,12,0,0,1,12,12Zm-44,24a12,12,0,0,0-12,12v64H52V84h64a12,12,0,0,0,0-24H48A20,20,0,0,0,28,80V208a20,20,0,0,0,20,20H176a20,20,0,0,0,20-20V140A12,12,0,0,0,184,128Z\"/>\u003C/svg>\u003Cspan class=\"wiki-visually-hidden\">(opens in a new tab)\u003C/span>\u003C/a>\u003C/li>\n\u003C/ul>\n",[10,14,17,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69],{"id":11,"level":12,"text":13},"the-problem-locators-solve",2,"The problem locators solve",{"id":15,"level":12,"text":16},"kinds-of-locators","Kinds of locators",{"id":18,"level":19,"text":20},"by-role",3,"By role",{"id":22,"level":19,"text":23},"by-label","By label",{"id":25,"level":19,"text":26},"by-placeholder","By placeholder",{"id":28,"level":19,"text":29},"by-text","By text",{"id":31,"level":19,"text":32},"by-alt-text-and-title","By alt text and title",{"id":34,"level":19,"text":35},"by-test-id","By test id",{"id":37,"level":19,"text":38},"css-selectors","CSS selectors",{"id":40,"level":19,"text":41},"xpath","XPath",{"id":43,"level":12,"text":44},"locators-in-webdriver-and-selenium","Locators in WebDriver and Selenium",{"id":46,"level":12,"text":47},"locators-in-playwright-and-testing-library","Locators in Playwright and Testing Library",{"id":49,"level":12,"text":50},"resilience-to-changes","Resilience to changes",{"id":52,"level":12,"text":53},"choosing-a-locator","Choosing a locator",{"id":55,"level":12,"text":56},"waiting-for-elements","Waiting for elements",{"id":58,"level":12,"text":59},"locators-and-localization","Locators and localization",{"id":61,"level":12,"text":62},"locators-in-an-object-repository","Locators in an object repository",{"id":64,"level":12,"text":65},"locator-selector-and-element-handle","Locator, selector and element handle",{"id":67,"level":12,"text":68},"terms","Terms",{"id":70,"level":12,"text":71},"sources","Sources",2758,1793718934611]