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

时间:2019-06-16 07:05:19

标签: javascript jestjs puppeteer

我在后台页面中具有全局功能,如下所示:

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控制台都没有错误。那是什么问题呢?为什么不调用该全局函数?

1 个答案:

答案 0 :(得分:1)

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