Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions packages/react-grab/e2e/element-context.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,110 @@ test.describe("Element Context Fallback", () => {
expect(clipboard).toContain("long-dom-element");
expect(clipboard.length).toBeLessThanOrEqual(510);
});

test("should include descendant text for syntax highlighted code blocks", async ({
reactGrab,
}) => {
await reactGrab.page.evaluate(() => {
const wrapper = document.createElement("div");
Object.assign(wrapper.style, {
position: "fixed",
top: "200px",
left: "200px",
width: "600px",
height: "160px",
zIndex: "999",
});

const codeBlock = document.createElement("pre");
codeBlock.className = "shiki shiki-themes github-light github-dark";
codeBlock.tabIndex = 0;
codeBlock.innerHTML = `
<code>
<span class="line"><span>git</span><span> add</span><span> .github/workflows/react-doctor.yml</span></span>
<span class="line"><span>git</span><span> commit</span><span> -m</span><span> "Add React Doctor to CI"</span></span>
<span class="line"><span>git</span><span> push</span></span>
</code>
`;

wrapper.appendChild(codeBlock);
document.body.appendChild(wrapper);
});

const didCopy = await reactGrab.copyElementViaApi("pre.shiki");
expect(didCopy).toBe(true);

const clipboard = await reactGrab.getClipboardContent();
expect(clipboard).toContain("<pre");
expect(clipboard).toContain("git add .github/workflows/react-doctor.yml");
expect(clipboard).toContain('git commit -m "Add React Doctor to CI"');
expect(clipboard).toContain("</pre>");
});

test("should include descendant text for nested link labels", async ({ reactGrab }) => {
await reactGrab.page.evaluate(() => {
const wrapper = document.createElement("div");
Object.assign(wrapper.style, {
position: "fixed",
top: "200px",
left: "200px",
width: "320px",
height: "80px",
zIndex: "999",
});

const link = document.createElement("a");
link.href = "/docs/ci-and-prs/github-actions-setup";
link.className = "flex h-8 w-full items-center gap-2 rounded-md px-2";
link.innerHTML = `
<span aria-hidden="true">#</span>
<span><span>GitHub Actions setup</span></span>
`;

wrapper.appendChild(link);
document.body.appendChild(wrapper);
});

const didCopy = await reactGrab.copyElementViaApi(
"a[href='/docs/ci-and-prs/github-actions-setup']",
);
expect(didCopy).toBe(true);

const clipboard = await reactGrab.getClipboardContent();
expect(clipboard).toContain('<a href="/docs/ci-and-prs/github-actions-setup"');
expect(clipboard).toContain("GitHub Actions setup");
expect(clipboard).not.toContain("# GitHub Actions setup");
expect(clipboard).toContain('selector: [href="/docs/ci-and-prs/github-actions-setup"]');
expect(clipboard).toContain("</a>");
});

test("should skip preview text for hidden selected roots", async ({ reactGrab }) => {
await reactGrab.page.evaluate(() => {
const wrapper = document.createElement("div");
Object.assign(wrapper.style, {
position: "fixed",
top: "200px",
left: "200px",
width: "200px",
height: "80px",
zIndex: "999",
});

const hiddenLabel = document.createElement("span");
hiddenLabel.setAttribute("aria-hidden", "true");
hiddenLabel.setAttribute("data-testid", "decorative-hidden-label");
hiddenLabel.textContent = "Decorative Hidden Label";

wrapper.appendChild(hiddenLabel);
document.body.appendChild(wrapper);
});

const didCopy = await reactGrab.copyElementViaApi("[data-testid='decorative-hidden-label']");
expect(didCopy).toBe(true);

const clipboard = await reactGrab.getClipboardContent();
expect(clipboard).toContain('aria-hidden="true"');
expect(clipboard).not.toContain("Decorative Hidden Label");
});
});
});
31 changes: 31 additions & 0 deletions packages/react-grab/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,37 @@ export const LABEL_GAP_PX = 4;
export const PREVIEW_TEXT_MAX_LENGTH = 100;
export const PREVIEW_ATTR_VALUE_MAX_LENGTH = 15;
export const PREVIEW_MAX_ATTRS = 3;
export const CONTEXT_SELECTOR_MAX_LENGTH_CHARS = 160;
export const PREVIEW_TEXT_TAGS = new Set([
"a",
"abbr",
"b",
"button",
"caption",
"cite",
"code",
"dd",
"dt",
"em",
"figcaption",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"label",
"legend",
"li",
"p",
"pre",
"small",
"span",
"strong",
"summary",
"td",
"th",
]);
export const PREVIEW_PRIORITY_ATTRS: readonly string[] = [
"id",
"class",
Expand Down
Loading
Loading