后台页面中声明的全局函数不会通过 evaluateHandle 调用

Global function declared in background page does not get called via evaluateHandle

我在后台页面中有一个全局函数,如下所示:

window.myfn = function(){
    return new Promise((resolve, reject) => { stuff; });
};

我正在使用 Jest 和 Puppeteer。在我的 test.js 文件中考虑这一点:

async function getBackgroundPage() {
    const targets = await browser.targets(),
        backgroundPageTarget = targets.find(
            target => target.type() === "background_page",
        ),
        backgroundPage = await backgroundPageTarget.page();

    return backgroundPage;
}

async function sendUpdate() {
    const bgPage = await getBackgroundPage(),
        argString = `() => window.myfn()`;
    await bgPage.evaluateHandle(argString);
    await sleep(30000);
}

getBackgroundPage 是从 docs 字面上复制的,所以我希望它是正确的。但是,sendUpdate() 没有按预期工作。理想情况下,应该调用 window.myfn 但实际上它从未被调用过。我知道这是因为:

  1. 我在里面放了几个console.log,所以如果它被调用,应该会有一些日志输出。
  2. 30 秒的睡眠让我有足够的时间转到 chrome://extensions,并通过 Inspect Views 打开后台页面控制台,但我在那里找不到任何日志输出。

后台页面和Jest控制台都没有报错。那问题是什么?为什么那个全局函数没有被调用?

给函数和给 evaluateHandle(和 evaluate)函数提供字符串之间存在细微差别。

如果传递一个函数,该函数将在页面内部被调用。如果传递一个字符串,该字符串将在页面上下文中执行。这意味着,这两行做不同的事情:

await bgPage.evaluate(() => console.log("test"););
await bgPage.evaluate('() => console.log("test");');

第一行将执行页面内的函数(和运行 console.log)。但是,第二行只会声明函数而不会调用它。因此,如果我们传递一个字符串,我们必须做这些事情之一:

await bgPage.evaluate('console.log("test")'); // directly run console.log
await bgPage.evaluate('(() => console.log("test"))()'); // execute the function

正在修复您的代码

回到您的代码,这意味着您要么直接调用 window.myfn(),要么将参数作为函数传递:

await bgPage.evaluateHandle('window.myfn()'); // directly call the function
await bgPage.evaluateHandle(() => window.myfn()); // or pass as a function and not as string