skip to Main Content

I am trying to write unit tests for JS code using Node.js, but the JS code will ultimately run in the browser and in some cases depends on browser-only objects (like document). I’m trying to get Puppeteer to work in this context, but can’t seem to get past the basics.

The code I am testing is bundled into a single JS file, so I’m using the addScriptTag of the page object in Puppeteer to add this JS file, then using page.evaluate to execute my test code.

My JS bundle (the code under test) exports a single object, and when I try to access this object from within the evaluate execution, it is undefined. In trying to track down why, I discovered that addScriptTag doesn’t seem to add anything, and the document.scripts array is empty.

Here’s an example:

const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.addScriptTag({ 
  path: '/foo/bar/somescript.js', // This path is fake, but in my actual environment is correct
}).catch(error => console.log(error));

const result = await page.evaluate(() => {
  return document.scripts;
}).catch(error => console.log(error));

console.log(result.length); // This returns undefined!

await browser.close();

Does anyone know what is missing from the above to get the script to be added to the page?

2

Answers


  1. Chosen as BEST ANSWER

    OK.. looks like I am (somehow) holding it wrong. If I reduce the test case to a very simple JS file, it seems to work. The problem must be elsewhere. For example, the following will work.

    Define a JS file for testing

    test.js

    const foo = "bar";
    

    Try to access the value of foo in Puppeteer:

    const jsPath = 'test.js'; // Assume the path to this file is correct
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    
    await page.addScriptTag({ 
      path: jsPath,
    }).catch(error => console.log(error));
    
    const result = await page.evaluate(async () => {
      return foo;
    }).catch(error => console.log(error));
    
    console.log(result); // This prints "bar"
    
    await browser.close();
    

    Not sure why document.scripts does not return anything (even in this "working" case)


  2. Indeed, there was an error loading the script. Adding a pageerror handler revealed it:

    test.js

    var foo;
    fakenews;
    foo = 'bar';
    
    const jsPath = 'test.js'; // Assume the path to this file is correct
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    
    await page.addScriptTag({ 
      path: jsPath,
    }).catch(error => console.log(error));
    
    page.on('pageerror', pageerr => {
      console.log('A page error occurred: ', pageerr);
    });
    
    const result = await page.evaluate(async () => {
      return foo;
    }).catch(error => console.log(error));
    
    console.log(result); // This is undefined
    
    await browser.close();
    

    Without the pagerror handler, the value of foo us just undefined. Adding the handler, we see:

    A page error occurred:  Error [ReferenceError]: fakenews is not defined
    

    (in my real case, the error was: Error [TypeError]: crypto.randomUUID is not a function, which is a separate issue to diagnose)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search