[Bug]: getByLabel (and accessible name) ignore <label> for form-associated custom elements

Đã đóng
#43,898 2 bình luận 1 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Một pull request liên quan đã được merge.

  • #43900 của @microsoft-playwright-automation — đã merge

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
25/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Đình trệ
Công nghệ
html, playwright, typescript
Lĩnh vực
accessibility, testing-qa

Hướng nghiên cứu

Start in packages/injected/src/selectorUtils.ts and read getElementLabels, then trace how those labels feed getByLabel and accessible name computation. A linked pull request (#43900) is already open; completion would require both locators in the reproduction to resolve to the custom element and the related tests to pass.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

needs-triage
Version

1.64.1

Steps to reproduce
import { test, expect } from '@playwright/test';

test('label of a form-associated custom element', async ({ page }) => {
  await page.setContent(`
    <label for="city">City</label><my-field id="city">Pick one</my-field>
    <label>Street <my-field>Pick one</my-field></label>`);
  await page.addScriptTag({ content: `
    customElements.define('my-field', class extends HTMLElement {
      static formAssociated = true;
      constructor() { super(); this.attachInternals(); }
      connectedCallback() { this.tabIndex = 0; }
    });` });

  // The browser associates both labels with the custom elements:
  expect(await page.evaluate(() => [...document.querySelectorAll('label')].map((l) => l.control?.localName)))
    .toEqual(['my-field', 'my-field']);

  await expect(page.getByLabel('City')).toHaveCount(1);   // ❌ 0
  await expect(page.getByLabel('Street')).toHaveCount(1); // ❌ 0
});
Expected behavior

getByLabel('City') and getByLabel('Street') each resolve to the <my-field> element.

Form-associated custom elements are labelable elements. The browser associates the <label> with them, both for for= and for nesting: label.control returns the element, and Chrome's accessibility tree names it from the label (with role = 'combobox' set through ElementInternals, Chrome exposes combobox "City").

Actual behavior

Both locators resolve to 0 elements.

getElementLabels (packages/injected/src/selectorUtils.ts) reads element.labels only for a fixed list of native elements:

const isNonHiddenInput = element.nodeName === 'INPUT' && element.type !== 'hidden';
if (['BUTTON', 'METER', 'OUTPUT', 'PROGRESS', 'SELECT', 'TEXTAREA'].includes(element.nodeName) || isNonHiddenInput) {
  const labels = element.labels;
  ...

A form-associated custom element has no public .labels (only ElementInternals.labels, which is private to the element), so the element side can't be read. The label side can: HTMLLabelElement.control returns the custom element for both for= and nesting, so no new browser API is needed.

Additional context
  • Related, but different: #34264 (roles and states set through ElementInternals). That one needs access to the element's internals. This one doesn't: the association is readable today through label.control.
  • Possible fix: when the element is a form-associated custom element (customElements.get(el.localName)?.formAssociated), collect the <label> elements in its tree whose control === el, and use their text, excluding the text of the control nested inside a label (as is already done for native controls). The same labels should feed the accessible name computation (step 2D) used by getByRole({ name }).
  • It matters more and more: design systems build form controls as form-associated custom elements precisely so that <label for> works as with native controls.
Environment
Playwright 1.64.1, Chrome. The lookup happens in Playwright's injected script, so it shouldn't depend on the browser.
Ngôn ngữ chính
TypeScript
Star
99.1k
Fork
6.8k
Merge trung bình
16 giờ 56 phút
Pull request đã merge (30 ngày)
299

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của microsoft/playwright

Tất cả issue của microsoft/playwright

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.