Last year a tool called ‘ ’ was released by the team. This tool is a headless Chrome, which means that with it you can interact with and visit websites programmatically. This is a powerful concept that has many uses. Puppeteer Chrome Developers uses Puppeteer extensively nowadays. I want to explain in 2 posts how we use Puppeteer. In this post I will explain why and how we use Puppeteer for our test suite. In the next post I will cover how we use Puppeteer and serverless functions to generate previews and metadata for sandboxes (projects). CodeSandbox But Why? In CodeSandbox we do all bundling of the sandbox code in the browser, to do this. We still make changes and add features to this bundler, so it’s crucial that we extensively test if the changes affect existing sandboxes built by users. I’ve built a custom bundler Before I’ve always kept a list of ‘test’ sandboxes and would load every sandbox manually to see if they still worked. As you can probably expect, this proved to be very time consuming as the list kept growing beyond 20 sandboxes and we started getting more contributions. Puppeteer to the rescue! Solution Puppeteer has a really nifty function called (you can try it ). The function does exactly what it describes: it takes a screenshot of the current webpage and returns the of the screenshot. For CodeSandbox we can use this as a snapshot tool: after every commit we take a screenshot of all test sandboxes and compare them with the previously stored screenshots. If there’s a difference of more than 1% we fail the test suite. screenshot here Buffer Implementation I decided to use for running all tests. We start by setting up an array of sandboxes to test: Jest This is a list of sandbox ids, of which some have extra options like a more tolerant threshold. We iterate this list to create test cases: The biggest question was how to take a screenshot of a single sandbox. This turned out to be quite simple, we already support opening a sandbox as a separate page by going to (example: ). So the only thing left for me was adding this functionality to the development server, so we can create screenshots with the new code. I ended up changing our webpack config to have a ‘test’ mode, this mode will only build the sandbox bundler and host it at (example: ). Note that we set the id as a hash, this way we don’t interfere with the routing of the sandbox. https://:id.codesandbox.io https://vue.codesandbox.io http://localhost:3001#:id http://localhost:3001#vue A generated screenshot of a todo redux example After having this set up it was fairly straightforward to build the rest. There’s already a library for comparing screenshots called . This library exposes on , which works almost exactly the same as . [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot) toMatchImageSnapshot expect toMatchSnapshot The final implementation looks like this: You can see in the code that we expose a function called . The bundler calls when it’s finished, this function is exposed by puppeteer so we can exactly know when we can take the screenshot. The generated screenshots are then saved in the GitHub repo. You can find them . window.__puppeteer__ window.__puppeteer__ here We run these tests using CircleCI, but we need to generate the initial screenshots locally. To ensure that we generate similar screenshots as CircleCI we generate screenshots using a docker container. We have a simple script which we just run to generate new screenshots: I have set up a simple workflow for CircleCI to start the test server and simultaneously run the tests. These tests are run in a docker container that has Puppeteer preinstalled. The workflow of CodeSandbox, notice the test-integrations step We save all diffs as artifacts, so we can easily compare the screenshots. You can see a list of artifacts of a recent test run here: . https://circleci.com/gh/CompuIves/codesandbox-client/4291#artifacts/containers/0 A diff artifact: the arrows are different Conclusion The implementation turned out to be quite simple, but it has saved me a lot of time already. We now test a little over 20 sandboxes for every commit and PR. I also noticed that I’m more inclined to add sandboxes to the test suite too, which made the bundler more stable in general. In the next post I will cover how we use Puppeteer with serverless functions to generate metadata and oEmbed tags for sandboxes. You can follow my Twitter or to stay up to date! @CompuIves @codesandboxapp If you’re interested in the code; all code that was described here (and of CodeSandbox) is open source on GitHub. You can find the main repository here: _codesandbox-client - An online code editor tailored for web application development 🏖️_github.com CompuIves/codesandbox-client I hope you found the post interesting, don’t hesitate to respond with more ideas and uses for Puppeteer!
Share Your Thoughts