如何动态注入函数以使用 Puppeteer 进行评估?
How can I dynamically inject functions to evaluate using Puppeteer?
我正在使用 Puppeteer 无头 Chrome。我希望评估页面内的一个函数,该函数使用其他函数的一部分,在别处动态定义。
下面的代码是一个最小的示例/证明。实际上 functionToInject()
和 otherFunctionToInject()
更复杂并且需要页面 DOM.
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(someURL);
var functionToInject = function(){
return 1+1;
}
var otherFunctionToInject = function(input){
return 6
}
var data = await page.evaluate(function(functionToInject, otherFunctionToInject){
console.log('woo I run inside a browser')
return functionToInject() + otherFunctionToInject();
});
return data
当我 运行 代码时,我得到:
Error: Evaluation failed: TypeError: functionToInject is not a function
据我了解:functionToInject
未传递到页面的 JS 上下文中。但是如何将它传递到页面的 JS 上下文中呢?
您可以使用 addScriptTag
:
将函数添加到页面上下文
const browser = await puppeteer.launch();
const page = await browser.newPage();
function functionToInject (){
return 1+1;
}
function otherFunctionToInject(input){
return 6
}
await page.addScriptTag({ content: `${functionToInject} ${otherFunctionToInject}`});
var data = await page.evaluate(function(){
console.log('woo I run inside a browser')
return functionToInject() + otherFunctionToInject();
});
console.log(data);
await browser.close();
这个例子是用字符串连接解决这个问题的肮脏方法。更干净的方法是在 addScriptTag
方法中使用 url
或 path
。
或使用exposeFunction
(但现在函数被包装在Promise中):
const browser = await puppeteer.launch();
const page = await browser.newPage();
var functionToInject = function(){
return 1+1;
}
var otherFunctionToInject = function(input){
return 6
}
await page.exposeFunction('functionToInject', functionToInject);
await page.exposeFunction('otherFunctionToInject', otherFunctionToInject);
var data = await page.evaluate(async function(){
console.log('woo I run inside a browser')
return await functionToInject() + await otherFunctionToInject();
});
console.log(data);
await browser.close();
工作示例accessible by link,在同一个 repo 中,您可以看到经过测试的组件。
it("click should return option value", async () => {
const optionToReturn = "ClickedOption";
const page = await newE2EPage();
const mockCallBack = jest.fn();
await page.setContent(
`<list-option option='${optionToReturn}'></list-option>`
);
await page.exposeFunction("functionToInject", mockCallBack); // Inject function
await page.$eval("list-option", (elm: any) => {
elm.onOptionSelected = this.functionToInject; // Assign function
});
await page.waitForChanges();
const element = await page.find("list-option");
await element.click();
expect(mockCallBack.mock.calls.length).toEqual(1); // Check calls
expect(mockCallBack.mock.calls[0][0]).toBe(optionToReturn); // Check argument
});
您还可以使用 page.exposeFunction()
,这将使您的函数 return 成为 Promise
(需要使用 async
和 await
)。发生这种情况是因为您的函数不会 running inside your browser,而是在您的 nodejs
应用程序内部,其结果正在 into/to 浏览器代码中来回发送。
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(someURL);
var functionToInject = function(){
return 1+1;
}
var otherFunctionToInject = function(input){
return 6
}
await page.exposeFunction("functionToInject", functionToInject)
await page.exposeFunction("otherFunctionToInject", otherFunctionToInject)
var data = await page.evaluate(async function(){
console.log('woo I run inside a browser')
return await functionToInject() + await otherFunctionToInject();
});
return data
相关问题:
- exposeFunction() does not work after goto()
- exposed function queryseldtcor not working in puppeteer
- How to use evaluateOnNewDocument and exposeFunction?
- exposeFunction remains in memory?
- Puppeteer evaluate function
- allow to pass a parameterized funciton as a string to page.evaluate
- Functions bound with page.exposeFunction() produce unhandled promise rejections
- How to pass a function in Puppeteers .evaluate() method?
- Why can't I access 'window' in an exposeFunction() function with Puppeteer?
我正在使用 Puppeteer 无头 Chrome。我希望评估页面内的一个函数,该函数使用其他函数的一部分,在别处动态定义。
下面的代码是一个最小的示例/证明。实际上 functionToInject()
和 otherFunctionToInject()
更复杂并且需要页面 DOM.
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(someURL);
var functionToInject = function(){
return 1+1;
}
var otherFunctionToInject = function(input){
return 6
}
var data = await page.evaluate(function(functionToInject, otherFunctionToInject){
console.log('woo I run inside a browser')
return functionToInject() + otherFunctionToInject();
});
return data
当我 运行 代码时,我得到:
Error: Evaluation failed: TypeError: functionToInject is not a function
据我了解:functionToInject
未传递到页面的 JS 上下文中。但是如何将它传递到页面的 JS 上下文中呢?
您可以使用 addScriptTag
:
const browser = await puppeteer.launch();
const page = await browser.newPage();
function functionToInject (){
return 1+1;
}
function otherFunctionToInject(input){
return 6
}
await page.addScriptTag({ content: `${functionToInject} ${otherFunctionToInject}`});
var data = await page.evaluate(function(){
console.log('woo I run inside a browser')
return functionToInject() + otherFunctionToInject();
});
console.log(data);
await browser.close();
这个例子是用字符串连接解决这个问题的肮脏方法。更干净的方法是在 addScriptTag
方法中使用 url
或 path
。
或使用exposeFunction
(但现在函数被包装在Promise中):
const browser = await puppeteer.launch();
const page = await browser.newPage();
var functionToInject = function(){
return 1+1;
}
var otherFunctionToInject = function(input){
return 6
}
await page.exposeFunction('functionToInject', functionToInject);
await page.exposeFunction('otherFunctionToInject', otherFunctionToInject);
var data = await page.evaluate(async function(){
console.log('woo I run inside a browser')
return await functionToInject() + await otherFunctionToInject();
});
console.log(data);
await browser.close();
工作示例accessible by link,在同一个 repo 中,您可以看到经过测试的组件。
it("click should return option value", async () => {
const optionToReturn = "ClickedOption";
const page = await newE2EPage();
const mockCallBack = jest.fn();
await page.setContent(
`<list-option option='${optionToReturn}'></list-option>`
);
await page.exposeFunction("functionToInject", mockCallBack); // Inject function
await page.$eval("list-option", (elm: any) => {
elm.onOptionSelected = this.functionToInject; // Assign function
});
await page.waitForChanges();
const element = await page.find("list-option");
await element.click();
expect(mockCallBack.mock.calls.length).toEqual(1); // Check calls
expect(mockCallBack.mock.calls[0][0]).toBe(optionToReturn); // Check argument
});
您还可以使用 page.exposeFunction()
,这将使您的函数 return 成为 Promise
(需要使用 async
和 await
)。发生这种情况是因为您的函数不会 running inside your browser,而是在您的 nodejs
应用程序内部,其结果正在 into/to 浏览器代码中来回发送。
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(someURL);
var functionToInject = function(){
return 1+1;
}
var otherFunctionToInject = function(input){
return 6
}
await page.exposeFunction("functionToInject", functionToInject)
await page.exposeFunction("otherFunctionToInject", otherFunctionToInject)
var data = await page.evaluate(async function(){
console.log('woo I run inside a browser')
return await functionToInject() + await otherFunctionToInject();
});
return data
相关问题:
- exposeFunction() does not work after goto()
- exposed function queryseldtcor not working in puppeteer
- How to use evaluateOnNewDocument and exposeFunction?
- exposeFunction remains in memory?
- Puppeteer evaluate function
- allow to pass a parameterized funciton as a string to page.evaluate
- Functions bound with page.exposeFunction() produce unhandled promise rejections
- How to pass a function in Puppeteers .evaluate() method?
- Why can't I access 'window' in an exposeFunction() function with Puppeteer?