为何无法在Playwright的page.waitForFunction中使用page.locator?
核心原因
page.waitForFunction的回调函数是运行在浏览器的JavaScript上下文中的,而page对象是Playwright在Node.js环境中创建的控制对象,属于Node.js端的专属API,无法被序列化传递到浏览器上下文里执行。当你尝试把page作为参数传给waitForFunction时,浏览器端无法识别这个Node.js对象,因此会抛出Error: Unexpected value错误。
你的写法错误分析
你尝试的两种写法本质问题一致:
page是Node.js端对象,浏览器上下文没有该对象的有效定义,即便传递参数,也只是一个无法正常工作的序列化空壳,无法调用page.locator()方法。page.locator()返回的是Playwright封装的Locator对象,这是Node.js端的专属类型,浏览器环境中根本不存在,自然无法执行.count()这类方法。
而你测试的Promise示例能正常运行,是因为那些Promise是在浏览器上下文内部创建的,完全不依赖Node.js端的API,所以可以被浏览器正常解析执行。
可行方案解析
1. 循环等待
通过Node.js端循环调用page.locator().count()检查元素数量,本质是每次循环都由Playwright从Node.js向浏览器发送指令,因此能正常工作,但需要手动处理超时逻辑,代码相对繁琐。
2. 传递选择器到浏览器上下文
将CSS选择器字符串作为参数传入waitForFunction,在浏览器上下文里使用原生JS的document.querySelectorAll()获取元素,这种方式完全基于浏览器环境的原生API,不依赖Node.js端能力,因此可以正常运行。
3. 最简洁的Playwright原生方案
使用Playwright内置断言await expect(page.locator('xxx')).toHaveCount(10),这是官方推荐的写法。断言内部已经封装了自动等待逻辑,会持续检查直到条件满足或超时,完全匹配你之前使用Cypresscy.waitUntil的使用习惯,且代码最简洁。
内容的提问来源于stack exchange,提问作者im-a-train

