puppeteer/assets/js/f3976560.620b7f56.js
2021-10-07 15:21:45 +00:00

1 line
38 KiB
JavaScript

"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[62844],{3905:function(e,t,a){a.d(t,{Zo:function(){return u},kt:function(){return c}});var n=a(67294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function p(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?p(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):p(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function i(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},p=Object.keys(e);for(n=0;n<p.length;n++)a=p[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var p=Object.getOwnPropertySymbols(e);for(n=0;n<p.length;n++)a=p[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),l=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,p=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),h=l(a),c=r,d=h["".concat(s,".").concat(c)]||h[c]||m[c]||p;return a?n.createElement(d,o(o({ref:t},u),{},{components:a})):n.createElement(d,o({ref:t},u))}));function c(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var p=a.length,o=new Array(p);o[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:r,o[1]=i;for(var l=2;l<p;l++)o[l]=a[l];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}h.displayName="MDXCreateElement"},98105:function(e,t,a){a.r(t),a.d(t,{frontMatter:function(){return i},contentTitle:function(){return s},metadata:function(){return l},toc:function(){return u},default:function(){return h}});var n=a(87462),r=a(63366),p=(a(67294),a(3905)),o=["components"],i={},s="Puppeteer",l={type:"mdx",permalink:"/puppeteer/",source:"@site/src/pages/index.md"},u=[{value:"Getting Started",id:"getting-started",children:[{value:"Installation",id:"installation",children:[]},{value:"puppeteer-core",id:"puppeteer-core",children:[]},{value:"Usage",id:"usage",children:[]}]},{value:"Default runtime settings",id:"default-runtime-settings",children:[]},{value:"Resources",id:"resources",children:[]},{value:"Debugging tips",id:"debugging-tips",children:[]},{value:"Usage with TypeScript",id:"usage-with-typescript",children:[]},{value:"Contributing to Puppeteer",id:"contributing-to-puppeteer",children:[]}],m={toc:u};function h(e){var t=e.components,a=(0,r.Z)(e,o);return(0,p.kt)("wrapper",(0,n.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,p.kt)("h1",{id:"puppeteer"},"Puppeteer"),(0,p.kt)("p",null,(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/actions?query=workflow%3Arun-checks"},(0,p.kt)("img",{parentName:"a",src:"https://github.com/puppeteer/puppeteer/workflows/run-checks/badge.svg",alt:"Build status"}))," ",(0,p.kt)("a",{parentName:"p",href:"https://npmjs.org/package/puppeteer"},(0,p.kt)("img",{parentName:"a",src:"https://img.shields.io/npm/v/puppeteer.svg",alt:"npm puppeteer package"}))),(0,p.kt)("img",{src:"https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png",height:"200",align:"right"}),(0,p.kt)("h6",{id:"api--faq--contributing--troubleshooting"},(0,p.kt)("a",{parentName:"h6",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md"},"API")," | ",(0,p.kt)("a",{parentName:"h6",href:"#faq"},"FAQ")," | ",(0,p.kt)("a",{parentName:"h6",href:"https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md"},"Contributing")," | ",(0,p.kt)("a",{parentName:"h6",href:"https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md"},"Troubleshooting")),(0,p.kt)("blockquote",null,(0,p.kt)("p",{parentName:"blockquote"},"Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the ",(0,p.kt)("a",{parentName:"p",href:"https://chromedevtools.github.io/devtools-protocol/"},"DevTools Protocol"),". Puppeteer runs ",(0,p.kt)("a",{parentName:"p",href:"https://developers.google.com/web/updates/2017/04/headless-chrome"},"headless")," by default, but can be configured to run full (non-headless) Chrome or Chromium.")),(0,p.kt)("h6",{id:"what-can-i-do"},"What can I do?"),(0,p.kt)("p",null,"Most things that you can do manually in the browser can be done using Puppeteer! Here are a few examples to get you started:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},"Generate screenshots and PDFs of pages."),(0,p.kt)("li",{parentName:"ul"},'Crawl a SPA (Single-Page Application) and generate pre-rendered content (i.e. "SSR" (Server-Side Rendering)).'),(0,p.kt)("li",{parentName:"ul"},"Automate form submission, UI testing, keyboard input, etc."),(0,p.kt)("li",{parentName:"ul"},"Create an up-to-date, automated testing environment. Run your tests directly in the latest version of Chrome using the latest JavaScript and browser features."),(0,p.kt)("li",{parentName:"ul"},"Capture a ",(0,p.kt)("a",{parentName:"li",href:"https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference"},"timeline trace")," of your site to help diagnose performance issues."),(0,p.kt)("li",{parentName:"ul"},"Test Chrome Extensions.")),(0,p.kt)("p",null,"Give it a spin: ",(0,p.kt)("a",{parentName:"p",href:"https://try-puppeteer.appspot.com/"},"https://try-puppeteer.appspot.com/")),(0,p.kt)("h2",{id:"getting-started"},"Getting Started"),(0,p.kt)("h3",{id:"installation"},"Installation"),(0,p.kt)("p",null,"To use Puppeteer in your project, run:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},'npm i puppeteer\n# or "yarn add puppeteer"\n')),(0,p.kt)("p",null,"Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, or to download a different browser, see ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#environment-variables"},"Environment variables"),"."),(0,p.kt)("h3",{id:"puppeteer-core"},"puppeteer-core"),(0,p.kt)("p",null,"Since version 1.7.0 we publish the ",(0,p.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/puppeteer-core"},(0,p.kt)("inlineCode",{parentName:"a"},"puppeteer-core"))," package,\na version of Puppeteer that doesn't download any browser by default."),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},'npm i puppeteer-core\n# or "yarn add puppeteer-core"\n')),(0,p.kt)("p",null,(0,p.kt)("inlineCode",{parentName:"p"},"puppeteer-core")," is intended to be a lightweight version of Puppeteer for launching an existing browser installation or for connecting to a remote one. Be sure that the version of puppeteer-core you install is compatible with the\nbrowser you intend to connect to."),(0,p.kt)("p",null,"See ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#puppeteer-vs-puppeteer-core"},"puppeteer vs puppeteer-core"),"."),(0,p.kt)("h3",{id:"usage"},"Usage"),(0,p.kt)("p",null,"Puppeteer follows the latest ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/nodejs/Release#release-schedule"},"maintenance LTS")," version of Node."),(0,p.kt)("p",null,"Note: Prior to v1.18.1, Puppeteer required at least Node v6.4.0. Versions from v1.18.1 to v2.1.0 rely on\nNode 8.9.0+. Starting from v3.0.0 Puppeteer starts to rely on Node 10.18.1+. All examples below use async/await which is only supported in Node v7.6.0 or greater."),(0,p.kt)("p",null,"Puppeteer will be familiar to people using other browser testing frameworks. You create an instance\nof ",(0,p.kt)("inlineCode",{parentName:"p"},"Browser"),", open pages, and then manipulate them with ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#"},"Puppeteer's API"),"."),(0,p.kt)("p",null,(0,p.kt)("strong",{parentName:"p"},"Example")," - navigating to ",(0,p.kt)("a",{parentName:"p",href:"https://example.com"},"https://example.com")," and saving a screenshot as ",(0,p.kt)("em",{parentName:"p"},"example.png"),":"),(0,p.kt)("p",null,"Save file as ",(0,p.kt)("strong",{parentName:"p"},"example.js")),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const puppeteer = require('puppeteer');\n\n(async () => {\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.goto('https://example.com');\n await page.screenshot({ path: 'example.png' });\n\n await browser.close();\n})();\n")),(0,p.kt)("p",null,"Execute script on the command line"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},"node example.js\n")),(0,p.kt)("p",null,"Puppeteer sets an initial page size to 800\xd7600px, which defines the screenshot size. The page size can be customized with ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#pagesetviewportviewport"},(0,p.kt)("inlineCode",{parentName:"a"},"Page.setViewport()")),"."),(0,p.kt)("p",null,(0,p.kt)("strong",{parentName:"p"},"Example")," - create a PDF."),(0,p.kt)("p",null,"Save file as ",(0,p.kt)("strong",{parentName:"p"},"hn.js")),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const puppeteer = require('puppeteer');\n\n(async () => {\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.goto('https://news.ycombinator.com', {\n waitUntil: 'networkidle2',\n });\n await page.pdf({ path: 'hn.pdf', format: 'a4' });\n\n await browser.close();\n})();\n")),(0,p.kt)("p",null,"Execute script on the command line"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},"node hn.js\n")),(0,p.kt)("p",null,"See ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#pagepdfoptions"},(0,p.kt)("inlineCode",{parentName:"a"},"Page.pdf()"))," for more information about creating pdfs."),(0,p.kt)("p",null,(0,p.kt)("strong",{parentName:"p"},"Example")," - evaluate script in the context of the page"),(0,p.kt)("p",null,"Save file as ",(0,p.kt)("strong",{parentName:"p"},"get-dimensions.js")),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const puppeteer = require('puppeteer');\n\n(async () => {\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.goto('https://example.com');\n\n // Get the \"viewport\" of the page, as reported by the page.\n const dimensions = await page.evaluate(() => {\n return {\n width: document.documentElement.clientWidth,\n height: document.documentElement.clientHeight,\n deviceScaleFactor: window.devicePixelRatio,\n };\n });\n\n console.log('Dimensions:', dimensions);\n\n await browser.close();\n})();\n")),(0,p.kt)("p",null,"Execute script on the command line"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},"node get-dimensions.js\n")),(0,p.kt)("p",null,"See ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#pageevaluatepagefunction-args"},(0,p.kt)("inlineCode",{parentName:"a"},"Page.evaluate()"))," for more information on ",(0,p.kt)("inlineCode",{parentName:"p"},"evaluate")," and related methods like ",(0,p.kt)("inlineCode",{parentName:"p"},"evaluateOnNewDocument")," and ",(0,p.kt)("inlineCode",{parentName:"p"},"exposeFunction"),"."),(0,p.kt)("h2",{id:"default-runtime-settings"},"Default runtime settings"),(0,p.kt)("p",null,(0,p.kt)("strong",{parentName:"p"},"1. Uses Headless mode")),(0,p.kt)("p",null,"Puppeteer launches Chromium in ",(0,p.kt)("a",{parentName:"p",href:"https://developers.google.com/web/updates/2017/04/headless-chrome"},"headless mode"),". To launch a full version of Chromium, set the ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#puppeteerlaunchoptions"},(0,p.kt)("inlineCode",{parentName:"a"},"headless")," option")," when launching a browser:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const browser = await puppeteer.launch({ headless: false }); // default is true\n")),(0,p.kt)("p",null,(0,p.kt)("strong",{parentName:"p"},"2. Runs a bundled version of Chromium")),(0,p.kt)("p",null,"By default, Puppeteer downloads and uses a specific version of Chromium so its API\nis guaranteed to work out of the box. To use Puppeteer with a different version of Chrome or Chromium,\npass in the executable's path when creating a ",(0,p.kt)("inlineCode",{parentName:"p"},"Browser")," instance:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const browser = await puppeteer.launch({ executablePath: '/path/to/Chrome' });\n")),(0,p.kt)("p",null,"You can also use Puppeteer with Firefox Nightly (experimental support). See ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#puppeteerlaunchoptions"},(0,p.kt)("inlineCode",{parentName:"a"},"Puppeteer.launch()"))," for more information."),(0,p.kt)("p",null,"See ",(0,p.kt)("a",{parentName:"p",href:"https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/"},(0,p.kt)("inlineCode",{parentName:"a"},"this article"))," for a description of the differences between Chromium and Chrome. ",(0,p.kt)("a",{parentName:"p",href:"https://chromium.googlesource.com/chromium/src/+/master/docs/chromium_browser_vs_google_chrome.md"},(0,p.kt)("inlineCode",{parentName:"a"},"This article"))," describes some differences for Linux users."),(0,p.kt)("p",null,(0,p.kt)("strong",{parentName:"p"},"3. Creates a fresh user profile")),(0,p.kt)("p",null,"Puppeteer creates its own browser user profile which it ",(0,p.kt)("strong",{parentName:"p"},"cleans up on every run"),"."),(0,p.kt)("h2",{id:"resources"},"Resources"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("a",{parentName:"li",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md"},"API Documentation")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("a",{parentName:"li",href:"https://github.com/puppeteer/puppeteer/tree/main/examples/"},"Examples")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("a",{parentName:"li",href:"https://github.com/transitive-bullshit/awesome-puppeteer"},"Community list of Puppeteer resources"))),(0,p.kt)("h2",{id:"debugging-tips"},"Debugging tips"),(0,p.kt)("ol",null,(0,p.kt)("li",{parentName:"ol"},(0,p.kt)("p",{parentName:"li"},"Turn off headless mode - sometimes it's useful to see what the browser is\ndisplaying. Instead of launching in headless mode, launch a full version of\nthe browser using ",(0,p.kt)("inlineCode",{parentName:"p"},"headless: false"),":"),(0,p.kt)("pre",{parentName:"li"},(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const browser = await puppeteer.launch({ headless: false });\n"))),(0,p.kt)("li",{parentName:"ol"},(0,p.kt)("p",{parentName:"li"},"Slow it down - the ",(0,p.kt)("inlineCode",{parentName:"p"},"slowMo")," option slows down Puppeteer operations by the\nspecified amount of milliseconds. It's another way to help see what's going on."),(0,p.kt)("pre",{parentName:"li"},(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const browser = await puppeteer.launch({\n headless: false,\n slowMo: 250, // slow down by 250ms\n});\n"))),(0,p.kt)("li",{parentName:"ol"},(0,p.kt)("p",{parentName:"li"},"Capture console output - You can listen for the ",(0,p.kt)("inlineCode",{parentName:"p"},"console")," event.\nThis is also handy when debugging code in ",(0,p.kt)("inlineCode",{parentName:"p"},"page.evaluate()"),":"),(0,p.kt)("pre",{parentName:"li"},(0,p.kt)("code",{parentName:"pre",className:"language-js"},"page.on('console', (msg) => console.log('PAGE LOG:', msg.text()));\n\nawait page.evaluate(() => console.log(`url is ${location.href}`));\n"))),(0,p.kt)("li",{parentName:"ol"},(0,p.kt)("p",{parentName:"li"},"Use debugger in application code browser"),(0,p.kt)("p",{parentName:"li"},"There are two execution context: node.js that is running test code, and the browser\nrunning application code being tested. This lets you debug code in the\napplication code browser; ie code inside ",(0,p.kt)("inlineCode",{parentName:"p"},"evaluate()"),"."),(0,p.kt)("ul",{parentName:"li"},(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"Use ",(0,p.kt)("inlineCode",{parentName:"p"},"{devtools: true}")," when launching Puppeteer:"),(0,p.kt)("pre",{parentName:"li"},(0,p.kt)("code",{parentName:"pre",className:"language-js"},"const browser = await puppeteer.launch({ devtools: true });\n"))),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"Change default test timeout:"),(0,p.kt)("p",{parentName:"li"},"jest: ",(0,p.kt)("inlineCode",{parentName:"p"},"jest.setTimeout(100000);")),(0,p.kt)("p",{parentName:"li"},"jasmine: ",(0,p.kt)("inlineCode",{parentName:"p"},"jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;")),(0,p.kt)("p",{parentName:"li"},"mocha: ",(0,p.kt)("inlineCode",{parentName:"p"},"this.timeout(100000);")," (don't forget to change test to use ",(0,p.kt)("a",{parentName:"p",href:"https://stackoverflow.com/a/23492442"},"function and not '=>'"),")")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"Add an evaluate statement with ",(0,p.kt)("inlineCode",{parentName:"p"},"debugger")," inside / add ",(0,p.kt)("inlineCode",{parentName:"p"},"debugger")," to an existing evaluate statement:"),(0,p.kt)("pre",{parentName:"li"},(0,p.kt)("code",{parentName:"pre",className:"language-js"},"await page.evaluate(() => {\n debugger;\n});\n")),(0,p.kt)("p",{parentName:"li"},"The test will now stop executing in the above evaluate statement, and chromium will stop in debug mode.")))),(0,p.kt)("li",{parentName:"ol"},(0,p.kt)("p",{parentName:"li"},"Use debugger in node.js"),(0,p.kt)("p",{parentName:"li"},"This will let you debug test code. For example, you can step over ",(0,p.kt)("inlineCode",{parentName:"p"},"await page.click()")," in the node.js script and see the click happen in the application code browser."),(0,p.kt)("p",{parentName:"li"},"Note that you won't be able to run ",(0,p.kt)("inlineCode",{parentName:"p"},"await page.click()")," in\nDevTools console due to this ",(0,p.kt)("a",{parentName:"p",href:"https://bugs.chromium.org/p/chromium/issues/detail?id=833928"},"Chromium bug"),". So if\nyou want to try something out, you have to add it to your test file."),(0,p.kt)("ul",{parentName:"li"},(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"Add ",(0,p.kt)("inlineCode",{parentName:"p"},"debugger;")," to your test, eg:"),(0,p.kt)("pre",{parentName:"li"},(0,p.kt)("code",{parentName:"pre",className:"language-js"},"debugger;\nawait page.click('a[target=_blank]');\n"))),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"Set ",(0,p.kt)("inlineCode",{parentName:"p"},"headless")," to ",(0,p.kt)("inlineCode",{parentName:"p"},"false"))),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"Run ",(0,p.kt)("inlineCode",{parentName:"p"},"node --inspect-brk"),", eg ",(0,p.kt)("inlineCode",{parentName:"p"},"node --inspect-brk node_modules/.bin/jest tests"))),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"In Chrome open ",(0,p.kt)("inlineCode",{parentName:"p"},"chrome://inspect/#devices")," and click ",(0,p.kt)("inlineCode",{parentName:"p"},"inspect"))),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"In the newly opened test browser, type ",(0,p.kt)("inlineCode",{parentName:"p"},"F8")," to resume test execution")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"Now your ",(0,p.kt)("inlineCode",{parentName:"p"},"debugger")," will be hit and you can debug in the test browser")))),(0,p.kt)("li",{parentName:"ol"},(0,p.kt)("p",{parentName:"li"},"Enable verbose logging - internal DevTools protocol traffic\nwill be logged via the ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/visionmedia/debug"},(0,p.kt)("inlineCode",{parentName:"a"},"debug"))," module under the ",(0,p.kt)("inlineCode",{parentName:"p"},"puppeteer")," namespace."),(0,p.kt)("pre",{parentName:"li"},(0,p.kt)("code",{parentName:"pre"},' # Basic verbose logging\n env DEBUG="puppeteer:*" node script.js\n\n # Protocol traffic can be rather noisy. This example filters out all Network domain messages\n env DEBUG="puppeteer:*" env DEBUG_COLORS=true node script.js 2>&1 | grep -v \'"Network\'\n'))),(0,p.kt)("li",{parentName:"ol"},(0,p.kt)("p",{parentName:"li"},"Debug your Puppeteer (node) code easily, using ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/GoogleChromeLabs/ndb"},"ndb")))),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},(0,p.kt)("inlineCode",{parentName:"p"},"npm install -g ndb")," (or even better, use ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/zkat/npx"},"npx"),"!)")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"add a ",(0,p.kt)("inlineCode",{parentName:"p"},"debugger")," to your Puppeteer (node) code")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"add ",(0,p.kt)("inlineCode",{parentName:"p"},"ndb")," (or ",(0,p.kt)("inlineCode",{parentName:"p"},"npx ndb"),") before your test command. For example:"),(0,p.kt)("p",{parentName:"li"},(0,p.kt)("inlineCode",{parentName:"p"},"ndb jest")," or ",(0,p.kt)("inlineCode",{parentName:"p"},"ndb mocha")," (or ",(0,p.kt)("inlineCode",{parentName:"p"},"npx ndb jest")," / ",(0,p.kt)("inlineCode",{parentName:"p"},"npx ndb mocha"),")")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},"debug your test inside chromium like a boss!"))),(0,p.kt)("h2",{id:"usage-with-typescript"},"Usage with TypeScript"),(0,p.kt)("p",null,"We have recently completed a migration to move the Puppeteer source code from JavaScript to TypeScript and as of version 7.0.1 we ship our own built-in type definitions."),(0,p.kt)("p",null,"If you are on a version older than 7, we recommend installing the Puppeteer type definitions from the ",(0,p.kt)("a",{parentName:"p",href:"https://definitelytyped.org/"},"DefinitelyTyped")," repository:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},"npm install --save-dev @types/puppeteer\n")),(0,p.kt)("p",null,"The types that you'll see appearing in the Puppeteer source code are based off the great work of those who have contributed to the ",(0,p.kt)("inlineCode",{parentName:"p"},"@types/puppeteer")," package. We really appreciate the hard work those people put in to providing high quality TypeScript definitions for Puppeteer's users."),(0,p.kt)("h2",{id:"contributing-to-puppeteer"},"Contributing to Puppeteer"),(0,p.kt)("p",null,"Check out ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md"},"contributing guide")," to get an overview of Puppeteer development."),(0,p.kt)("h1",{id:"faq"},"FAQ"),(0,p.kt)("h4",{id:"q-who-maintains-puppeteer"},"Q: Who maintains Puppeteer?"),(0,p.kt)("p",null,"The Chrome DevTools team maintains the library, but we'd love your help and expertise on the project!\nSee ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md"},"Contributing"),"."),(0,p.kt)("h4",{id:"q-what-is-the-status-of-cross-browser-support"},"Q: What is the status of cross-browser support?"),(0,p.kt)("p",null,"Official Firefox support is currently experimental. The ongoing collaboration with Mozilla aims to support common end-to-end testing use cases, for which developers expect cross-browser coverage. The Puppeteer team needs input from users to stabilize Firefox support and to bring missing APIs to our attention."),(0,p.kt)("p",null,"From Puppeteer v2.1.0 onwards you can specify ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#puppeteerlaunchoptions"},(0,p.kt)("inlineCode",{parentName:"a"},"puppeteer.launch({product: 'firefox'})"))," to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While ",(0,p.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/puppeteer-firefox"},"an older experiment")," required a patched version of Firefox, ",(0,p.kt)("a",{parentName:"p",href:"https://wiki.mozilla.org/Remote"},"the current approach")," works with \u201cstock\u201d Firefox."),(0,p.kt)("p",null,"We will continue to collaborate with other browser vendors to bring Puppeteer support to browsers such as Safari.\nThis effort includes exploration of a standard for executing cross-browser commands (instead of relying on the non-standard DevTools Protocol used by Chrome)."),(0,p.kt)("h4",{id:"q-what-are-puppeteers-goals-and-principles"},"Q: What are Puppeteer\u2019s goals and principles?"),(0,p.kt)("p",null,"The goals of the project are:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},"Provide a slim, canonical library that highlights the capabilities of the ",(0,p.kt)("a",{parentName:"li",href:"https://chromedevtools.github.io/devtools-protocol/"},"DevTools Protocol"),"."),(0,p.kt)("li",{parentName:"ul"},"Provide a reference implementation for similar testing libraries. Eventually, these other frameworks could adopt Puppeteer as their foundational layer."),(0,p.kt)("li",{parentName:"ul"},"Grow the adoption of headless/automated browser testing."),(0,p.kt)("li",{parentName:"ul"},"Help dogfood new DevTools Protocol features...and catch bugs!"),(0,p.kt)("li",{parentName:"ul"},"Learn more about the pain points of automated browser testing and help fill those gaps.")),(0,p.kt)("p",null,"We adapt ",(0,p.kt)("a",{parentName:"p",href:"https://www.chromium.org/developers/core-principles"},"Chromium principles")," to help us drive product decisions:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("strong",{parentName:"li"},"Speed"),": Puppeteer has almost zero performance overhead over an automated page."),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("strong",{parentName:"li"},"Security"),": Puppeteer operates off-process with respect to Chromium, making it safe to automate potentially malicious pages."),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("strong",{parentName:"li"},"Stability"),": Puppeteer should not be flaky and should not leak memory."),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("strong",{parentName:"li"},"Simplicity"),": Puppeteer provides a high-level API that\u2019s easy to use, understand, and debug.")),(0,p.kt)("h4",{id:"q-is-puppeteer-replacing-seleniumwebdriver"},"Q: Is Puppeteer replacing Selenium/WebDriver?"),(0,p.kt)("p",null,(0,p.kt)("strong",{parentName:"p"},"No"),". Both projects are valuable for very different reasons:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},"Selenium/WebDriver focuses on cross-browser automation; its value proposition is a single standard API that works across all major browsers."),(0,p.kt)("li",{parentName:"ul"},"Puppeteer focuses on Chromium; its value proposition is richer functionality and higher reliability.")),(0,p.kt)("p",null,"That said, you ",(0,p.kt)("strong",{parentName:"p"},"can")," use Puppeteer to run tests against Chromium, e.g. using the community-driven ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/smooth-code/jest-puppeteer"},"jest-puppeteer"),". While this probably shouldn\u2019t be your only testing solution, it does have a few good points compared to WebDriver:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},"Puppeteer requires zero setup and comes bundled with the Chromium version it works best with, making it ",(0,p.kt)("a",{parentName:"li",href:"https://github.com/puppeteer/puppeteer/#getting-started"},"very easy to start with"),". At the end of the day, it\u2019s better to have a few tests running chromium-only, than no tests at all."),(0,p.kt)("li",{parentName:"ul"},"Puppeteer has event-driven architecture, which removes a lot of potential flakiness. There\u2019s no need for evil \u201csleep(1000)\u201d calls in puppeteer scripts."),(0,p.kt)("li",{parentName:"ul"},"Puppeteer runs headless by default, which makes it fast to run. Puppeteer v1.5.0 also exposes browser contexts, making it possible to efficiently parallelize test execution."),(0,p.kt)("li",{parentName:"ul"},"Puppeteer shines when it comes to debugging: flip the \u201cheadless\u201d bit to false, add \u201cslowMo\u201d, and you\u2019ll see what the browser is doing. You can even open Chrome DevTools to inspect the test environment.")),(0,p.kt)("h4",{id:"q-why-doesnt-puppeteer-vxxx-work-with-chromium-vyyy"},"Q: Why doesn\u2019t Puppeteer v.XXX work with Chromium v.YYY?"),(0,p.kt)("p",null,"We see Puppeteer as an ",(0,p.kt)("strong",{parentName:"p"},"indivisible entity")," with Chromium. Each version of Puppeteer bundles a specific version of Chromium \u2013 ",(0,p.kt)("strong",{parentName:"p"},"the only")," version it is guaranteed to work with."),(0,p.kt)("p",null,"This is not an artificial constraint: A lot of work on Puppeteer is actually taking place in the Chromium repository. Here\u2019s a typical story:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},"A Puppeteer bug is reported: ",(0,p.kt)("a",{parentName:"li",href:"https://github.com/puppeteer/puppeteer/issues/2709"},"https://github.com/puppeteer/puppeteer/issues/2709")),(0,p.kt)("li",{parentName:"ul"},"It turned out this is an issue with the DevTools protocol, so we\u2019re fixing it in Chromium: ",(0,p.kt)("a",{parentName:"li",href:"https://chromium-review.googlesource.com/c/chromium/src/+/1102154"},"https://chromium-review.googlesource.com/c/chromium/src/+/1102154")),(0,p.kt)("li",{parentName:"ul"},"Once the upstream fix is landed, we roll updated Chromium into Puppeteer: ",(0,p.kt)("a",{parentName:"li",href:"https://github.com/puppeteer/puppeteer/pull/2769"},"https://github.com/puppeteer/puppeteer/pull/2769"))),(0,p.kt)("p",null,"However, oftentimes it is desirable to use Puppeteer with the official Google Chrome rather than Chromium. For this to work, you should install a ",(0,p.kt)("inlineCode",{parentName:"p"},"puppeteer-core")," version that corresponds to the Chrome version."),(0,p.kt)("p",null,"For example, in order to drive Chrome 71 with puppeteer-core, use ",(0,p.kt)("inlineCode",{parentName:"p"},"chrome-71")," npm tag:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},"npm install puppeteer-core@chrome-71\n")),(0,p.kt)("h4",{id:"q-which-chromium-version-does-puppeteer-use"},"Q: Which Chromium version does Puppeteer use?"),(0,p.kt)("p",null,"Look for the ",(0,p.kt)("inlineCode",{parentName:"p"},"chromium")," entry in ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/main/src/revisions.ts"},"revisions.ts"),". To find the corresponding Chromium commit and version number, search for the revision prefixed by an ",(0,p.kt)("inlineCode",{parentName:"p"},"r")," in ",(0,p.kt)("a",{parentName:"p",href:"https://omahaproxy.appspot.com/"},"OmahaProxy"),'\'s "Find Releases" section.'),(0,p.kt)("h4",{id:"q-which-firefox-version-does-puppeteer-use"},"Q: Which Firefox version does Puppeteer use?"),(0,p.kt)("p",null,"Since Firefox support is experimental, Puppeteer downloads the latest ",(0,p.kt)("a",{parentName:"p",href:"https://wiki.mozilla.org/Nightly"},"Firefox Nightly")," when the ",(0,p.kt)("inlineCode",{parentName:"p"},"PUPPETEER_PRODUCT")," environment variable is set to ",(0,p.kt)("inlineCode",{parentName:"p"},"firefox"),". That's also why the value of ",(0,p.kt)("inlineCode",{parentName:"p"},"firefox")," in ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/main/src/revisions.ts"},"revisions.ts")," is ",(0,p.kt)("inlineCode",{parentName:"p"},"latest")," -- Puppeteer isn't tied to a particular Firefox version."),(0,p.kt)("p",null,"To fetch Firefox Nightly as part of Puppeteer installation:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},'PUPPETEER_PRODUCT=firefox npm i puppeteer\n# or "yarn add puppeteer"\n')),(0,p.kt)("h4",{id:"q-whats-considered-a-navigation"},"Q: What\u2019s considered a \u201cNavigation\u201d?"),(0,p.kt)("p",null,"From Puppeteer\u2019s standpoint, ",(0,p.kt)("strong",{parentName:"p"},"\u201cnavigation\u201d is anything that changes a page\u2019s URL"),".\nAside from regular navigation where the browser hits the network to fetch a new document from the web server, this includes ",(0,p.kt)("a",{parentName:"p",href:"https://www.w3.org/TR/html5/single-page.html#scroll-to-fragid"},"anchor navigations")," and ",(0,p.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/API/History_API"},"History API")," usage."),(0,p.kt)("p",null,"With this definition of \u201cnavigation,\u201d ",(0,p.kt)("strong",{parentName:"p"},"Puppeteer works seamlessly with single-page applications.")),(0,p.kt)("h4",{id:"q-whats-the-difference-between-a-trusted-and-untrusted-input-event"},'Q: What\u2019s the difference between a \u201ctrusted" and "untrusted" input event?'),(0,p.kt)("p",null,"In browsers, input events could be divided into two big groups: trusted vs. untrusted."),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("strong",{parentName:"li"},"Trusted events"),": events generated by users interacting with the page, e.g. using a mouse or keyboard."),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("strong",{parentName:"li"},"Untrusted event"),": events generated by Web APIs, e.g. ",(0,p.kt)("inlineCode",{parentName:"li"},"document.createEvent")," or ",(0,p.kt)("inlineCode",{parentName:"li"},"element.click()")," methods.")),(0,p.kt)("p",null,"Websites can distinguish between these two groups:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},"using an ",(0,p.kt)("a",{parentName:"li",href:"https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted"},(0,p.kt)("inlineCode",{parentName:"a"},"Event.isTrusted"))," event flag"),(0,p.kt)("li",{parentName:"ul"},"sniffing for accompanying events. For example, every trusted ",(0,p.kt)("inlineCode",{parentName:"li"},"'click'")," event is preceded by ",(0,p.kt)("inlineCode",{parentName:"li"},"'mousedown'")," and ",(0,p.kt)("inlineCode",{parentName:"li"},"'mouseup'")," events.")),(0,p.kt)("p",null,"For automation purposes it\u2019s important to generate trusted events. ",(0,p.kt)("strong",{parentName:"p"},"All input events generated with Puppeteer are trusted and fire proper accompanying events.")," If, for some reason, one needs an untrusted event, it\u2019s always possible to hop into a page context with ",(0,p.kt)("inlineCode",{parentName:"p"},"page.evaluate")," and generate a fake event:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-js"},"await page.evaluate(() => {\n document.querySelector('button[type=submit]').click();\n});\n")),(0,p.kt)("h4",{id:"q-what-features-does-puppeteer-not-support"},"Q: What features does Puppeteer not support?"),(0,p.kt)("p",null,"You may find that Puppeteer does not behave as expected when controlling pages that incorporate audio and video. (For example, ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/issues/291"},"video playback/screenshots is likely to fail"),".) There are two reasons for this:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},"Puppeteer is bundled with Chromium \u2014 not Chrome \u2014 and so by default, it inherits all of ",(0,p.kt)("a",{parentName:"li",href:"https://www.chromium.org/audio-video"},"Chromium's media-related limitations"),". This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the ",(0,p.kt)("a",{parentName:"li",href:"https://github.com/puppeteer/puppeteer/blob/v10.0.0/docs/api.md#puppeteerlaunchoptions"},(0,p.kt)("inlineCode",{parentName:"a"},"executablePath")," option to ",(0,p.kt)("inlineCode",{parentName:"a"},"puppeteer.launch")),". You should only use this configuration if you need an official release of Chrome that supports these media formats.)"),(0,p.kt)("li",{parentName:"ul"},"Since Puppeteer (in all configurations) controls a desktop version of Chromium/Chrome, features that are only supported by the mobile version of Chrome are not supported. This means that Puppeteer ",(0,p.kt)("a",{parentName:"li",href:"https://caniuse.com/#feat=http-live-streaming"},"does not support HTTP Live Streaming (HLS)"),".")),(0,p.kt)("h4",{id:"q-i-am-having-trouble-installing--running-puppeteer-in-my-test-environment-where-should-i-look-for-help"},"Q: I am having trouble installing / running Puppeteer in my test environment. Where should I look for help?"),(0,p.kt)("p",null,"We have a ",(0,p.kt)("a",{parentName:"p",href:"https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md"},"troubleshooting")," guide for various operating systems that lists the required dependencies."),(0,p.kt)("h4",{id:"q-how-do-i-trytest-a-prerelease-version-of-puppeteer"},"Q: How do I try/test a prerelease version of Puppeteer?"),(0,p.kt)("p",null,"You can check out this repo or install the latest prerelease from npm:"),(0,p.kt)("pre",null,(0,p.kt)("code",{parentName:"pre",className:"language-bash"},"npm i --save puppeteer@next\n")),(0,p.kt)("p",null,"Please note that prerelease may be unstable and contain bugs."),(0,p.kt)("h4",{id:"q-i-have-more-questions-where-do-i-ask"},"Q: I have more questions! Where do I ask?"),(0,p.kt)("p",null,"There are many ways to get help on Puppeteer:"),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("a",{parentName:"li",href:"https://github.com/puppeteer/puppeteer/issues"},"bugtracker")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("a",{parentName:"li",href:"https://stackoverflow.com/questions/tagged/puppeteer"},"Stack Overflow"))),(0,p.kt)("p",null,"Make sure to search these channels before posting your question."))}h.isMDXComponent=!0}}]);