typescript - Kan inte komma åt texten inuti Shadow DOM med playwright


Jag försöker använda Playwright för att verifiera text som nedan, vilken finns inuti en öppen shadow root som inte har några taggar kopplade till just den texten. Dessa texter finns inuti tabellceller.

<div>
<table-cell>
  #shadow-root (open)
  "Text content"
</table-cell>

Jag försöker att kontrollera "Textinnehåll" som finns under shadow DOM. Jag lyckades att unikt lokalisera det men kan inte få texten inuti. Det returnerar alltid en tom sträng eller ett objekt beroende på vilken metod jag försökte använda för att hämta texten. Exempel på TypeScript-kod som jag försökte är nedan,

const text = this.page.locator('table-cell').innerText();

Jag kunde få andra texter som är inne i shadow root och som har en tagg associerad med den texten. Men i det här fallet har den här specifika textraden ingen tagg associerad med sig, så metoderna fungerar inte som i andra scenarier.

Hur får jag innehållet i #shadow-root om det bara innehåller texten, utan några taggar?

Svar #1

innerText är en egenskap på HTMLElement

En shadowRoot är inte ett HTMLElement och har ingen innerText-egenskap.

Den har dock en innerHTML-egenskap: https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot

let text = document.querySelector("your-element").shadowRoot.innerHTML

Hämtar texten åt dig

Svar #2

Du kan fråga noden utanför skuggroten och asserta på dess text:

import {expect, test} from "@playwright/test"; // ^1.42.1

const html = `<!DOCTYPE html><html><body>
<div></div>
<script>
const el = document.querySelector("div");
const root = el.attachShadow({mode: "open"});
el.shadowRoot.innerHTML = "Text content";
</script>
</body></html>`;

test("Finds tagless text in a shadow root", async ({page}) => {
  await page.setContent(html);
  await expect(page.locator("div")).toHaveText("Text content");
});

För ditt fall, ersätt "div" med "table-cell".

Om din rot råkar ha ytterligare innehåll blir det lite krångligare. En anpassad matchare kan vara bäst, men detta fungerar i nödfall:

const html = `<!DOCTYPE html><html><body>
<div></div>
<script>
const el = document.querySelector("div");
const root = el.attachShadow({mode: "open"});
el.shadowRoot.innerHTML = "Text content<p>More text</p>";
</script>
</body></html>`;

test("Finds tagless text in a shadow root with other content", async ({page}) => {
  await page.setContent(html);
  await expect(async () => {
    const text = await page.locator("div").evaluate(el =>
      el.shadowRoot.childNodes[0]?.textContent
    );
    expect(text).toBe("Text content");
  }).toPass();
});

Om flera textnoder kan vara i vilken ordning som helst, kan du använda något som:

const text = await page.locator("div").evaluate(el =>
  [...el.shadowRoot.childNodes]
    .filter(e => e.nodeType === Node.TEXT_NODE)
    .map(e => e.textContent)
    .join("")
);

eller om det bara finns en nod någonstans bland barnen:

const text = await page.locator("div").evaluate(el =>
  [...el.shadowRoot.childNodes]
    .find(e => e.nodeType === Node.TEXT_NODE)
    ?.textContent
);

Känn dig fri att kommentera om du vet ett bättre sätt, och jag kommer att uppdatera detta om jag hittar en förbättring på egen hand.

Relaterade artiklar