Jest Puppeteer自定义测试环境中扩展Page类方法丢失问题
我一眼就看出了两个关键问题导致你遇到page.sendText is not a function的错误:
1. Jest GlobalSetup是独立进程,原型扩展不共享
Jest的GlobalSetup是在单独的进程中运行的,你在那里对Page.prototype的修改只会作用于那个进程,不会影响到执行测试的主进程。当你在测试进程中用puppeteer.connect()连接已有浏览器时,新创建的Page实例来自测试进程里的原始Puppeteer Page类,自然没有你添加的sendText方法。而直接在测试里launch浏览器时,扩展代码是在测试进程内执行的,所以原型修改生效了。
2. 箭头函数导致的this绑定错误
就算你解决了进程问题,原来的sendText用箭头函数定义也会报错——箭头函数没有自己的this,它会捕获外层上下文的this,而不是指向调用它的Page实例,到时候你会遇到this.waitForSelector is not a function的新问题。
修复步骤
第一步:抽离扩展逻辑为独立模块
把你的Page扩展代码单独放在一个文件里,比如puppeteer-extensions.js:
// puppeteer-extensions.js const puppeteer = require('puppeteer'); const Page = puppeteer.lib.Page.Page; // 改用普通函数,确保this指向Page实例 Page.prototype.sendText = async function(selector, text) { const element = await this.waitForSelector(selector, { visible: true }); await element.type(text); };
第二步:在测试进程中加载扩展
确保你的扩展代码在测试进程中被执行,而不是只在GlobalSetup里。修改你的npm模块中的测试环境代码,在创建浏览器连接前先加载扩展:
// 你的测试环境代码 require('./puppeteer-extensions'); // 先加载扩展,修改当前进程的Page原型 this.global.__BROWSER__ = await puppeteer.connect({ browserWSEndpoint: wsEndpoint });
第三步:验证测试代码
你的测试代码不需要修改,现在重新运行测试,page.sendText应该可以正常调用了:
describe('awesome test', () => { it('something will be ok', async () => { const context = global.__BROWSER__.defaultBrowserContext(); page = await context.newPage(); await page.goto('https://google.com/') await page.sendText('#search', "puppeteer") await page.screenshot({path: 'google.png', fullPage: true}) }) });
额外说明
如果你的npm模块需要让测试项目自动加载扩展,也可以在模块的入口文件中引入puppeteer-extensions.js,或者告诉用户在测试项目的jest.config.js的setupFilesAfterEnv数组中添加你的扩展模块路径,确保测试启动时自动执行扩展逻辑。
内容的提问来源于stack exchange,提问作者Galileo123

