Z ZPI 文档 v0.3.8
介绍页

源码

tests/helpers/tooltip.ts

typescript59 行查看原文
import type { Page } from "@playwright/test";
import { expect } from "./test.ts";

// Start before the pointer/scroll event and inspect every rendered frame, including
// Radix's 150ms exit presence. Waiting only for eventual removal misses the flash.
export async function expectNoCornerTooltipDuring(page: Page, action: () => Promise<unknown>) {
  const monitor = await page.evaluateHandle(() => {
    const state = {
      endAt: Number.POSITIVE_INFINITY,
      frames: 0,
      ghosts: [] as Array<{ x: number; y: number; text: string | null }>,
      done: Promise.resolve(),
    };
    state.done = new Promise<void>((resolve) => {
      const sample = () => {
        state.frames++;
        for (const tooltip of document.querySelectorAll<HTMLElement>(".control-hint-tooltip")) {
          const wrapper = tooltip.closest<HTMLElement>("[data-radix-popper-content-wrapper]");
          if (!wrapper) continue;
          const bounds = wrapper.getBoundingClientRect();
          const style = getComputedStyle(tooltip);
          if (
            style.visibility !== "hidden" &&
            style.display !== "none" &&
            Number(style.opacity) > 0 &&
            bounds.width > 0 &&
            bounds.height > 0 &&
            bounds.x >= -1 &&
            bounds.x < 24 &&
            bounds.y >= -1 &&
            bounds.y < 24
          ) {
            state.ghosts.push({ x: bounds.x, y: bounds.y, text: tooltip.textContent });
          }
        }
        if (performance.now() < state.endAt) requestAnimationFrame(sample);
        else resolve();
      };
      requestAnimationFrame(sample);
    });
    return state;
  });
  try {
    await action();
    const result = await monitor.evaluate(async (state) => {
      state.endAt = performance.now() + 250;
      await state.done;
      return { frames: state.frames, ghosts: state.ghosts };
    });
    expect(result.frames).toBeGreaterThan(2);
    expect(result.ghosts).toEqual([]);
  } finally {
    await monitor.evaluate((state) => {
      state.endAt = 0;
    });
    await monitor.dispose();
  }
}