How can I dynamically inject functions to evaluate using Puppeteer?

You can add function to page context with 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();

This example is a dirty way of solving this problem with string concatenation. More clean would be using a url or path in the addScriptTag method.


Or use exposeFunction (but now functions are wrapped in 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();

working example accessible by link, in the same repo you can see the tested component.

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
  });