import { expect, type Locator } from '@playwright/test'; /** * 等到 React 把 props/事件监听挂到目标元素上,再对它发起交互。 * * 为什么需要:SSR HTML 一进入 DOM,元素就已经「可见」,但客户端组件的 onClick/onMouseEnter * 要等 hydration 完成才存在。这段窗口内派发的指针事件被浏览器当作普通事件丢弃,hydration 后 * 也不会重放 —— 表现为 hover/click 调用成功、状态却永远不变,然后 expect 轮询到 15s timeout。 * * 实测依据(next dev,本机 :3000):/contact 的 [data-testid="submit-button"] 在 first visible * 之后 1735ms 才挂上 handler;早点击得到 0 条 [data-testid="error-message"], * hydration 后同一动作得到 5 条。主导航「产品」按钮 first visible 时同样尚未 hydration。 * * 探针取 React DOM 写在宿主元素上的 __reactProps$ 内部键:`toBeVisible()` 只能证明 * 「渲染出来了」,证明不了「能交互」,而这个键是唯一能把两者分开的信号。项目锁定 React 18.3 * (package.json),该前缀自 React 16 起稳定。 */ export async function expectHydrated(target: Locator, timeout = 20000): Promise { await expect .poll( async () => target.evaluate((el) => Object.keys(el).some((key) => key.startsWith('__reactProps$'))), { timeout, message: '目标元素尚未完成 hydration' }, ) .toBe(true); }