Test HTML Content on a Webpage with Puppeteer

Tyler Clark
InstructorTyler Clark

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

Now that we have our setup and environment ready for using Puppeteer to test our create-react-app, we can write our first tests. We will test our h1 and navigation, to make sure that they load correctly. In this lesson, we will be able to watch puppeteer open up a browser and evaluate our tests in real time.

Instructor: [00:00] Now that we've got our setup done, let's write our first test. Let's make sure that the h1 has the correct text. Inside of our test block, we're going to do await page.goTo, and our localhost URL. Next, we'll do const HTML equals await page.eval, a selector, and then a callback function.

[00:23] Next, we'll do expect HTML to be, "Welcome to React." Finally, we'll close the browser, and give a timeout to our test. The first thing that we did was use this page.goTo, which is how we tell Puppeteer where to navigate inside the browser. We're telling to go to our localhost 3000.

[00:42] Once it gets there, we want to look for this appTitle class, which lives on our h1 inside of createReactApp. This eval method basically runs document.querySelector within whatever frame it's passed into.

[00:55] Once it finds a selector that matches this class, it's going to pass that to the callback function, where we can grab stuff, and do stuff with it. In our case, we want to grab that HTML that's inside of it. Once we have that extracted, we can write under it to expect to look, and make sure that the text says, "Welcome to React."

[01:12] Once we're done with that test, we want to close the browser. Perfect. Now, let's grab our terminal, and run our debug script. We're going to see our Chromium instance open, since we are debug mode, and we can see that it's stepping through, and checking our tests.

[01:29] We can see that our h1 did load correctly. Then if you also notice that our viewport that we've set inside of our page.emulate was respected. Our height was 2,400 pixels, and our width was only 500 pixels. Then our slowdown that we've set, we can speed it up, or slow it down, so that we can see what the browser's doing a little bit more clearly.

[01:52] Next, let's go ahead and write a couple more tests. Inside of our app JS file, we'll add a class to our nav. We'll call it navBar. Then I'm going to zoom out, and paste in an unordered list. We'll use this to replicate a nav bar.

[02:07] You can see that all of our LIs share the same class. Now, let's save this, go back to our app test file, and run a test to make sure that our nav, as you can see, will load correctly. Now, we don't want to create a new running browser and web page on every single test.

[02:24] Before we actually write our navigation test, let's refactor some of this shared code. Let's define two global variables, browser and page up here at the top. Then we're going to do before all, with a function, and we're going to do browser equals await puppeter.launch, with isDebugging.

[02:41] Then we're going to do page equals await browser.newPage, await page.goTo our localhost URL, and then page.setViewport, with our viewport properties. Now, inside of our test, we can remove some of this code, as well as our page.emulate.

[03:01] Because we didn't have anything for user agent, we could just use setViewportinstead of a beforeAll. Now, we can rid of our localhost, and we can also get rid of our browser.close, and use an afterAll, where we check to see if we're in debugging mode. If we are, then we want to remove that browser.

[03:23] Now, we can go ahead and write our nav test. Overwrite test, nav loads correctly with an async function, where we'll grab the nav bar using the eval function again on the nav bar class. Then we'll use a ternary to return true or false if the element exists.

[03:40] Then we'll grab our list items, and we'll do that by grabbing the navLI class. Then we're going to expect navBar to be true, and that our listItems.length is four. Just like in our h1 test, we're using this eval method to find the provided selector on the page, in our case, the navBar class.

[04:01] For our list items, we're using the double dollar sign method. This is like running document.querySelector all from within the page. When the eval title is not used alongside the dollar signs, it just means that there's no callback.

[04:17] Our expect checked for the existence of the navBar, and we use a node list length property to check the total number of nav LIs. Now, let's finish up by rerunning our debug script. Awesome, they both passed.

[04:36] One last to note. We are using classes as the selector, instead of our eval and double dollar sign methods. This works great inside of createReactApp, but can be brittle inside of other applications that use something like CSS modules.

[04:51] Instead, it's better to add data types. We'll paste in a data type selector for the h1, for our navBar, and for our list items. Finally, adding these data attributes to our HTML.

Platon
Platon
~ 4 years ago

Thanks for the course!

Can I reinitialize component state / reinitialize redux store with some mock data in beforeEach() without starting a new browser instance?

E.g. I would like to simulate a counter + / - by clicking a button.

// Counter starts at 0

element = page.$(`.add`)
element.click() 

// and now it's 1.

I would then like to simulate what happens when counter starts at 0 within the same browser instance without doing something hacky like adding decrement button click at the end of the of 'add' test to take the counter to 0 manually.

Learn Sifnos
Learn Sifnos
~ 4 years ago

If you are experiencing TypeError: environment.setup is not a function, just add to package.json:

  "jest": {
    "testEnvironment": "node"
  }
Maja Miarecki
Maja Miarecki
~ 4 years ago

The page variable also must have await, or it is a Promise in a time when page.emulate is called and it throws an error:

 FAIL  src/App.test.js
  on page load
    ✕ h1 loads correctly (1277ms)

  ● on page load › h1 loads correctly

    TypeError: page.emulate is not a function

It is already in the code on github, but NOT in video and many of us is not checking github code...

Anika  Sharma
Anika Sharma
~ 4 years ago

When I run the command "npm run debug", the following error comes: Couldn't find preset "react" relative to directory. Why does this error come?

julio
julio
~ 4 years ago

got error, had to run: npm install -g win-node-env

to make it run as Linux envirionment

Razvan Popa
Razvan Popa
~ 4 years ago

Expected "Welcome to React", received {}

Changed to: html.then(() => { expect(html).toBe('Welcome to React') }) and the test passed. Can't really explain this, can anyone help?

Razvan Popa
Razvan Popa
~ 4 years ago

I also got:

(node:19549) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Protocol error (Runtime.evaluate): Target closed. (node:19549) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Does this mean my node is a bit old?

Doug Grubba
Doug Grubba
~ 4 years ago

I'm receiving the same warning about the unhandled promise rejection and having a little trouble getting past it. Running v10.5.0 of node so I doubt that it is the issue.

I'm not 100% on the syntax needed to handle the rejection.

Carlos
Carlos
~ 4 years ago

I am having issues with running "npm run debug" script at 4:30.

I'm getting the following - npm run debug -> npm ERR! puppeteer-testing@0.1.0 debug: NODE_ENV=debug npm test npm ERR! Exit status 1

and

jest jest : The term 'jest' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Please advise.

Pav
Pav
~ 3 years ago

If you're on windows...

"debug": "SET NODE_ENV=debug & npm test",
Jwan Khalaf
Jwan Khalaf
~ 3 years ago

How do I get "debug": "NODE_ENV=debug yarn test" working with Parcel?

When I run yarn debug, I get an error:

'NODE_ENV' is not recognized as an internal or external command, operable program or batch file. error Command failed with exit code 1. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Jwan Khalaf
Jwan Khalaf
~ 3 years ago

Update

I've figured it out. On Windows, setting of the NODE_ENV is different, and to make it worse, it is different between various terminals within Windows (e.g. Bash vs PowerShell).

Here's how to fix it.

  • Install cross-env by doing npm install "cross-env".
  • Then in your debug script, have cross-env NODE_ENV=debug yarn test.