我有一个TypeScript项目,该项目使用Jest进行单元测试,并且刚刚将Puppeteer添加到组合中,目的是在客户端上运行一些测试。除非我尝试在page.evaluate
中使用导入的函数,否则它会很好地工作。
例如,我在HdpiCanvas.test.ts
中具有以下内容:
import { createHdpiCanvas } from "./HdpiCanvas";
test("createHdpiCanvas", async () => {
await page.setViewport({ width: 800, height: 600, deviceScaleFactor: 2 });
let size = await page.evaluate(() => {
const canvas = createHdpiCanvas(); // document.createElement('canvas');
return [canvas.width, canvas.height];
});
console.log(size); // [600, 300] for HDPI canvas and [ 300, 150 ] for a regular one
});
在注释为document.createElement('canvas')
的情况下,测试运行良好,并记录了[ 300, 150 ]
。但是,使用createHdpiCanvas()
时,page.evaluate
函数会引发以下错误:
Error: Evaluation failed: ReferenceError: HdpiCanvas_1 is not defined
at __puppeteer_evaluation_script__:2:24
createHdpiCanvas
内部的实际HdpiCanvas.ts
定义如下:
export function createHdpiCanvas(width = 300, height = 150): HTMLCanvasElement {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
applyHdpiOverrides(canvas);
return canvas;
}
及其本身取决于HdpiCanvas.ts
中定义的其他功能,例如applyHdpiOverrides
。
答案 0 :(得分:2)
您可以在调用evaluate
函数之前这样做:
await page.exposeFunction("applyHdpiOverrides",applyHdpiOverrides);
await page.exposeFunction("createHdpiCanvas",createHdpiCanvas);
现在您的窗口将识别这些功能
答案 1 :(得分:2)
Meni Roytenburd建议的解决方案是正确的。如果您不喜欢每个功能都需要单独显示给浏览器的事实,那么想到的唯一想法是,将项目首先转换为单个JavaScript文件,然后将其作为<script>
标记注入-就像您在现实生活中一样。
第一步是使用您的软件包生成一个JavaScript文件。有时,这可以单独使用TypeScript编译器来完成,但是也可以使用Webpack之类的工具。
完成后,您可以将捆绑包从Puppeteer中移至客户端:
await page.addScriptTag({ path: 'path/to/the/bundle' });
请记住,这仍然可能会将您的函数公开给全局范围,因此可以通过window
访问它们。
let size = await page.evaluate(() => {
const canvas = window.createHdpiCanvas();
return [canvas.width, canvas.height];
});
console.log(size); // [ 300, 150 ]
该方法必须处理TypeScript生成的警告的另一个缺点-目前尚不知道createHdpiCanvas
上存在window
,因此访问window.createHdpiCanvas
会导致错误。
答案 2 :(得分:1)
您可能已经发现,page.evaluate
失败的原因是因为该函数是在不同的上下文中求值的,并且当前作用域(其中createHdpiCanvas
在该函数之外可用)是迷路了。
我一点都不熟悉pupeteer,但是通过查看该函数的文档,您可以尝试一下。它虽然不漂亮,但也许值得尝试:
您可以将createHdpiCanvas
作为参数传递,但是函数不能序列化,因此您必须自己做:
page.evaluate((createHdpiCanvasCode) => {
const createHdpiCanvas = new Function(`return ${createHdpiCanvasCode}`)();
const canvas = createHdpiCanvas();
return [canvas.width, canvas.height];
}, createHdpiCanvas.toString());
但是,您必须以相同的方式注入依赖项。