From 86397f66e06f1b122354ad3fe1002a8779803459 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Tue, 2 Jul 2019 00:39:55 +0200 Subject: [PATCH 1/7] chore: drop Node6 support Node6 was end-of-life'ed in the end of April, 2019, with AWS Lambda prohibiting updaets to the node6 runtime since June 30, 2019. This makes it quite safe for us to remove the Node 6 support from the repository. From now on, all the subsequent commits will require Node 8.9.0+. --- .appveyor.yml | 3 - .ci/node6/Dockerfile.linux | 17 -- .cirrus.yml | 9 - .travis.yml | 3 - DeviceDescriptors.js | 13 +- Errors.js | 13 +- README.md | 3 +- .../puppeteer-firefox/DeviceDescriptors.js | 13 +- .../puppeteer-firefox/lib/BrowserFetcher.js | 8 +- experimental/puppeteer-firefox/lib/helper.js | 16 -- .../misc/install-preferences.js | 4 +- index.js | 23 +-- install.js | 18 -- lib/BrowserFetcher.js | 12 +- lib/DOMWorld.js | 3 +- lib/Launcher.js | 5 +- lib/Page.js | 4 +- lib/helper.js | 25 +-- package.json | 8 +- test/evaluation.spec.js | 15 +- test/headful.spec.js | 7 +- test/launcher.spec.js | 11 +- utils/doclint/Source.js | 30 +--- .../TransformAsyncFunctions.js | 156 ------------------ utils/node6-transform/index.js | 63 ------- utils/node6-transform/test/test.js | 97 ----------- 26 files changed, 56 insertions(+), 523 deletions(-) delete mode 100644 .ci/node6/Dockerfile.linux delete mode 100644 utils/node6-transform/TransformAsyncFunctions.js delete mode 100644 utils/node6-transform/index.js delete mode 100644 utils/node6-transform/test/test.js diff --git a/.appveyor.yml b/.appveyor.yml index 2a8d3bef9a61f..3b835f32f6070 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,5 @@ environment: matrix: - - nodejs_version: "6.12.3" - nodejs_version: "8.11.3" build: off @@ -13,6 +12,4 @@ install: npm run coverage && npm run test-doclint && npm run test-types - ) else ( - npm run unit-node6 ) diff --git a/.ci/node6/Dockerfile.linux b/.ci/node6/Dockerfile.linux deleted file mode 100644 index 77b416735d9db..0000000000000 --- a/.ci/node6/Dockerfile.linux +++ /dev/null @@ -1,17 +0,0 @@ -FROM node:6.12.3 - -RUN apt-get update && \ - apt-get -y install xvfb gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \ - libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 \ - libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \ - libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \ - libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget && \ - rm -rf /var/lib/apt/lists/* - -# Add user so we don't need --no-sandbox. -RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ - && mkdir -p /home/pptruser/Downloads \ - && chown -R pptruser:pptruser /home/pptruser - -# Run everything after as non-privileged user. -USER pptruser diff --git a/.cirrus.yml b/.cirrus.yml index aaba646fd01e8..d73bed88f71d1 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,15 +1,6 @@ env: DISPLAY: :99.0 -task: - matrix: - - name: Chromium (node6 + linux) - container: - dockerfile: .ci/node6/Dockerfile.linux - xvfb_start_background_script: Xvfb :99 -ac -screen 0 1024x768x24 - install_script: npm install --unsafe-perm - test_script: npm run unit-node6 - task: matrix: - name: Chromium (node8 + linux) diff --git a/.travis.yml b/.travis.yml index 24641f8dcab8d..5a470e9ee0490 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,13 +24,10 @@ script: - 'if [ "$NODE8" = "true" ]; then npm run test-types; fi' - 'if [ "$NODE8" = "true" ]; then npm run bundle; fi' - 'if [ "$NODE8" = "true" ]; then npm run unit-bundle; fi' - - 'if [ "$NODE6" = "true" ]; then npm run unit-node6; fi' jobs: include: - node_js: "8.11.3" env: NODE8=true - - node_js: "6.12.3" - env: NODE6=true before_deploy: "npm run apply-next-version" deploy: provider: npm diff --git a/DeviceDescriptors.js b/DeviceDescriptors.js index a89a09829000d..05135a115368c 100644 --- a/DeviceDescriptors.js +++ b/DeviceDescriptors.js @@ -14,15 +14,4 @@ * limitations under the License. */ -let asyncawait = true; -try { - new Function('async function test(){await 1}'); -} catch (error) { - asyncawait = false; -} - -// If node does not support async await, use the compiled version. -if (asyncawait) - module.exports = require('./lib/DeviceDescriptors'); -else - module.exports = require('./node6/lib/DeviceDescriptors'); +module.exports = require('./lib/DeviceDescriptors'); diff --git a/Errors.js b/Errors.js index dc41298ac12b2..4779e1d850812 100644 --- a/Errors.js +++ b/Errors.js @@ -14,15 +14,4 @@ * limitations under the License. */ -let asyncawait = true; -try { - new Function('async function test(){await 1}'); -} catch (error) { - asyncawait = false; -} - -// If node does not support async await, use the compiled version. -if (asyncawait) - module.exports = require('./lib/Errors'); -else - module.exports = require('./node6/lib/Errors'); +module.exports = require('./lib/Errors'); diff --git a/README.md b/README.md index 2b66be927686f..a84f02af4083c 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,8 @@ See [puppeteer vs puppeteer-core](https://github.com/GoogleChrome/puppeteer/blob ### Usage -Note: Puppeteer requires at least Node v6.4.0, but the examples below use async/await which is only supported in Node v7.6.0 or greater. +Note: Prior to v1.18.1, Puppeteer required at least Node v6.4.0. All subsequent versions rely on +Node 8.9.0+. All examples below use async/await which is only supported in Node v7.6.0 or greater. Puppeteer will be familiar to people using other browser testing frameworks. You create an instance of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/GoogleChrome/puppeteer/blob/v1.18.1/docs/api.md#). diff --git a/experimental/puppeteer-firefox/DeviceDescriptors.js b/experimental/puppeteer-firefox/DeviceDescriptors.js index a89a09829000d..05135a115368c 100644 --- a/experimental/puppeteer-firefox/DeviceDescriptors.js +++ b/experimental/puppeteer-firefox/DeviceDescriptors.js @@ -14,15 +14,4 @@ * limitations under the License. */ -let asyncawait = true; -try { - new Function('async function test(){await 1}'); -} catch (error) { - asyncawait = false; -} - -// If node does not support async await, use the compiled version. -if (asyncawait) - module.exports = require('./lib/DeviceDescriptors'); -else - module.exports = require('./node6/lib/DeviceDescriptors'); +module.exports = require('./lib/DeviceDescriptors'); diff --git a/experimental/puppeteer-firefox/lib/BrowserFetcher.js b/experimental/puppeteer-firefox/lib/BrowserFetcher.js index c7d1250e4c1ee..c222754d32584 100644 --- a/experimental/puppeteer-firefox/lib/BrowserFetcher.js +++ b/experimental/puppeteer-firefox/lib/BrowserFetcher.js @@ -82,10 +82,10 @@ function downloadURL(product, platform, host, revision) { return util.format(downloadURLs[product][platform], host, revision, archiveName(product, platform, revision)); } -const readdirAsync = helper.promisify(fs.readdir.bind(fs)); -const mkdirAsync = helper.promisify(fs.mkdir.bind(fs)); -const unlinkAsync = helper.promisify(fs.unlink.bind(fs)); -const chmodAsync = helper.promisify(fs.chmod.bind(fs)); +const readdirAsync = util.promisify(fs.readdir.bind(fs)); +const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); +const unlinkAsync = util.promisify(fs.unlink.bind(fs)); +const chmodAsync = util.promisify(fs.chmod.bind(fs)); function existsAsync(filePath) { let fulfill = null; diff --git a/experimental/puppeteer-firefox/lib/helper.js b/experimental/puppeteer-firefox/lib/helper.js index 78dd01d6889e0..cd4d0e9f4c222 100644 --- a/experimental/puppeteer-firefox/lib/helper.js +++ b/experimental/puppeteer-firefox/lib/helper.js @@ -65,22 +65,6 @@ class Helper { } } - static promisify(nodeFunction) { - function promisified(...args) { - return new Promise((resolve, reject) => { - function callback(err, ...result) { - if (err) - return reject(err); - if (result.length === 1) - return resolve(result[0]); - return resolve(result); - } - nodeFunction.call(null, ...args, callback); - }); - } - return promisified; - } - /** * @param {!Object} obj * @return {boolean} diff --git a/experimental/puppeteer-firefox/misc/install-preferences.js b/experimental/puppeteer-firefox/misc/install-preferences.js index c536baa7eab6f..b48267091ddd6 100644 --- a/experimental/puppeteer-firefox/misc/install-preferences.js +++ b/experimental/puppeteer-firefox/misc/install-preferences.js @@ -1,14 +1,14 @@ const os = require('os'); const fs = require('fs'); const path = require('path'); +const util = require('util'); // Install browser preferences after downloading and unpacking // firefox instances. // Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Enterprise_deployment_before_60#Configuration async function installFirefoxPreferences(executablePath) { const firefoxFolder = path.dirname(executablePath); - const {helper} = require('../lib/helper'); - const mkdirAsync = helper.promisify(fs.mkdir.bind(fs)); + const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); let prefPath = ''; let configPath = ''; diff --git a/index.js b/index.js index e7143fb3a5b18..a73d4d23d5fc6 100644 --- a/index.js +++ b/index.js @@ -14,25 +14,16 @@ * limitations under the License. */ -let asyncawait = true; -try { - new Function('async function test(){await 1}'); -} catch (error) { - asyncawait = false; -} - -if (asyncawait) { - const {helper} = require('./lib/helper'); - const api = require('./lib/api'); - for (const className in api) { - // Puppeteer-web excludes certain classes from bundle, e.g. BrowserFetcher. - if (typeof api[className] === 'function') - helper.installAsyncStackHooks(api[className]); - } +const {helper} = require('./lib/helper'); +const api = require('./lib/api'); +for (const className in api) { + // Puppeteer-web excludes certain classes from bundle, e.g. BrowserFetcher. + if (typeof api[className] === 'function') + helper.installAsyncStackHooks(api[className]); } // If node does not support async await, use the compiled version. -const Puppeteer = asyncawait ? require('./lib/Puppeteer') : require('./node6/lib/Puppeteer'); +const Puppeteer = require('./lib/Puppeteer'); const packageJson = require('./package.json'); const preferredRevision = packageJson.puppeteer.chromium_revision; const isPuppeteerCore = packageJson.name === 'puppeteer-core'; diff --git a/install.js b/install.js index d0e6c9181506a..2e3f52b540411 100644 --- a/install.js +++ b/install.js @@ -18,8 +18,6 @@ if (require('./package.json').name === 'puppeteer-core') return; -buildNode6IfNecessary(); - if (process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD) { logPolitely('**INFO** Skipping Chromium download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" environment variable was found.'); return; @@ -109,22 +107,6 @@ function toMegabytes(bytes) { return `${Math.round(mb * 10) / 10} Mb`; } -function buildNode6IfNecessary() { - const fs = require('fs'); - const path = require('path'); - - // if this package is installed from NPM, then it already has up-to-date node6 - // folder. - if (!fs.existsSync(path.join('utils', 'node6-transform'))) - return; - // if async/await is supported, then node6 is not needed. - if (supportsAsyncAwait()) - return; - // Re-build node6/ folder. - logPolitely('Building Puppeteer for Node 6'); - require(path.join(__dirname, 'utils', 'node6-transform')); -} - function supportsAsyncAwait() { try { new Function('async function test(){await 1}'); diff --git a/lib/BrowserFetcher.js b/lib/BrowserFetcher.js index 4f0492bdcecac..cea6e3ee97f13 100644 --- a/lib/BrowserFetcher.js +++ b/lib/BrowserFetcher.js @@ -17,10 +17,10 @@ const os = require('os'); const fs = require('fs'); const path = require('path'); -const extract = require('extract-zip'); const util = require('util'); +const extract = require('extract-zip'); const URL = require('url'); -const {helper, assert} = require('./helper'); +const {assert} = require('./helper'); const removeRecursive = require('rimraf'); // @ts-ignore const ProxyAgent = require('https-proxy-agent'); @@ -64,10 +64,10 @@ function downloadURL(platform, host, revision) { return util.format(downloadURLs[platform], host, revision, archiveName(platform, revision)); } -const readdirAsync = helper.promisify(fs.readdir.bind(fs)); -const mkdirAsync = helper.promisify(fs.mkdir.bind(fs)); -const unlinkAsync = helper.promisify(fs.unlink.bind(fs)); -const chmodAsync = helper.promisify(fs.chmod.bind(fs)); +const readdirAsync = util.promisify(fs.readdir.bind(fs)); +const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); +const unlinkAsync = util.promisify(fs.unlink.bind(fs)); +const chmodAsync = util.promisify(fs.chmod.bind(fs)); function existsAsync(filePath) { let fulfill = null; diff --git a/lib/DOMWorld.js b/lib/DOMWorld.js index 1668fad003483..6894f82151eca 100644 --- a/lib/DOMWorld.js +++ b/lib/DOMWorld.js @@ -15,10 +15,11 @@ */ const fs = require('fs'); +const util = require('util'); const {helper, assert} = require('./helper'); const {LifecycleWatcher} = require('./LifecycleWatcher'); const {TimeoutError} = require('./Errors'); -const readFileAsync = helper.promisify(fs.readFile); +const readFileAsync = util.promisify(fs.readFile); /** * @unrestricted diff --git a/lib/Launcher.js b/lib/Launcher.js index 8a92ab7486e1f..4fd5e52fdd8d0 100644 --- a/lib/Launcher.js +++ b/lib/Launcher.js @@ -15,6 +15,7 @@ */ const os = require('os'); const path = require('path'); +const util = require('util'); const http = require('http'); const https = require('https'); const URL = require('url'); @@ -30,8 +31,8 @@ const {TimeoutError} = require('./Errors'); const WebSocketTransport = require('./WebSocketTransport'); const PipeTransport = require('./PipeTransport'); -const mkdtempAsync = helper.promisify(fs.mkdtemp); -const removeFolderAsync = helper.promisify(removeFolder); +const mkdtempAsync = util.promisify(fs.mkdtemp); +const removeFolderAsync = util.promisify(removeFolder); const CHROME_PROFILE_PATH = path.join(os.tmpdir(), 'puppeteer_dev_profile-'); diff --git a/lib/Page.js b/lib/Page.js index 80d960dc3b043..e38524dee8f99 100644 --- a/lib/Page.js +++ b/lib/Page.js @@ -17,6 +17,7 @@ const fs = require('fs'); const EventEmitter = require('events'); const mime = require('mime'); +const util = require('util'); const {Events} = require('./Events'); const {Connection} = require('./Connection'); const {Dialog} = require('./Dialog'); @@ -30,7 +31,8 @@ const {Worker} = require('./Worker'); const {createJSHandle} = require('./JSHandle'); const {Accessibility} = require('./Accessibility'); const {TimeoutSettings} = require('./TimeoutSettings'); -const writeFileAsync = helper.promisify(fs.writeFile); + +const writeFileAsync = util.promisify(fs.writeFile); class Page extends EventEmitter { /** diff --git a/lib/helper.js b/lib/helper.js index e12d63dbeceed..ca53f0080a2f4 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -16,6 +16,11 @@ const {TimeoutError} = require('./Errors'); const debugError = require('debug')(`puppeteer:error`); const fs = require('fs'); +const util = require('util'); + +const openAsync = util.promisify(fs.open); +const writeAsync = util.promisify(fs.write); +const closeAsync = util.promisify(fs.close); class Helper { /** @@ -156,22 +161,6 @@ class Helper { return typeof obj === 'number' || obj instanceof Number; } - static promisify(nodeFunction) { - function promisified(...args) { - return new Promise((resolve, reject) => { - function callback(err, ...result) { - if (err) - return reject(err); - if (result.length === 1) - return resolve(result[0]); - return resolve(result); - } - nodeFunction.call(null, ...args, callback); - }); - } - return promisified; - } - /** * @param {!NodeJS.EventEmitter} emitter * @param {(string|symbol)} eventName @@ -254,10 +243,6 @@ class Helper { } } -const openAsync = Helper.promisify(fs.open); -const writeAsync = Helper.promisify(fs.write); -const closeAsync = Helper.promisify(fs.close); - /** * @param {*} value * @param {string=} message diff --git a/package.json b/package.json index aa64a5607b228..03585a4372e2f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "repository": "github:GoogleChrome/puppeteer", "engines": { - "node": ">=6.4.0" + "node": ">=8.9.0" }, "puppeteer": { "chromium_revision": "673587" @@ -15,14 +15,11 @@ "funit": "BROWSER=firefox node test/test.js", "debug-unit": "node --inspect-brk test/test.js", "test-doclint": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js", - "test": "npm run lint --silent && npm run coverage && npm run test-doclint && npm run test-node6-transformer && npm run test-types", + "test": "npm run lint --silent && npm run coverage && npm run test-doclint && npm run test-types", "install": "node install.js", "lint": "([ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .) && npm run tsc && npm run doc", "doc": "node utils/doclint/cli.js", "coverage": "cross-env COVERAGE=true npm run unit", - "test-node6-transformer": "node utils/node6-transform/test/test.js", - "build": "node utils/node6-transform/index.js && node utils/doclint/generate_types", - "unit-node6": "node node6/test/test.js", "tsc": "tsc -p .", "prepublishOnly": "npm run build", "apply-next-version": "node utils/apply_next_version.js", @@ -63,7 +60,6 @@ }, "browser": { "./lib/BrowserFetcher.js": false, - "./node6/lib/Puppeteer": false, "ws": "./utils/browser/WebSocket", "fs": false, "child_process": false, diff --git a/test/evaluation.spec.js b/test/evaluation.spec.js index ee3988dcc0b2d..b91ff03d7490e 100644 --- a/test/evaluation.spec.js +++ b/test/evaluation.spec.js @@ -16,13 +16,6 @@ const utils = require('./utils'); -let asyncawait = true; -try { - new Function('async function foo() {await 1}'); -} catch (e) { - asyncawait = false; -} - const bigint = typeof BigInt !== 'undefined'; module.exports.addTests = function({testRunner, expect}) { @@ -74,14 +67,12 @@ module.exports.addTests = function({testRunner, expect}) { it_fails_ffox('should return undefined for objects with symbols', async({page, server}) => { expect(await page.evaluate(() => [Symbol('foo4')])).toBe(undefined); }); - (asyncawait ? it : xit)('should work with function shorthands', async({page, server}) => { - // trick node6 transpiler to not touch our object. - // TODO(lushnikov): remove eval once Node6 is dropped. - const a = eval(`({ + it('should work with function shorthands', async({page, server}) => { + const a = { sum(a, b) { return a + b; }, async mult(a, b) { return a * b; } - })`); + }; expect(await page.evaluate(a.sum, 1, 2)).toBe(3); expect(await page.evaluate(a.mult, 2, 4)).toBe(8); }); diff --git a/test/headful.spec.js b/test/headful.spec.js index 965fc2431f423..3128c1657ff08 100644 --- a/test/headful.spec.js +++ b/test/headful.spec.js @@ -17,11 +17,12 @@ const path = require('path'); const os = require('os'); const fs = require('fs'); -const {helper} = require('../lib/helper'); -const rmAsync = helper.promisify(require('rimraf')); +const util = require('util'); const utils = require('./utils'); const {waitEvent} = utils; -const mkdtempAsync = helper.promisify(fs.mkdtemp); + +const rmAsync = util.promisify(require('rimraf')); +const mkdtempAsync = util.promisify(fs.mkdtemp); const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); diff --git a/test/launcher.spec.js b/test/launcher.spec.js index 510d1c9ef1bb4..00243215375fe 100644 --- a/test/launcher.spec.js +++ b/test/launcher.spec.js @@ -16,11 +16,12 @@ const fs = require('fs'); const os = require('os'); const path = require('path'); -const {helper} = require('../lib/helper'); -const rmAsync = helper.promisify(require('rimraf')); -const mkdtempAsync = helper.promisify(fs.mkdtemp); -const readFileAsync = helper.promisify(fs.readFile); -const statAsync = helper.promisify(fs.stat); +const util = require('util'); + +const rmAsync = util.promisify(require('rimraf')); +const mkdtempAsync = util.promisify(fs.mkdtemp); +const readFileAsync = util.promisify(fs.readFile); +const statAsync = util.promisify(fs.stat); const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); const utils = require('./utils'); diff --git a/utils/doclint/Source.js b/utils/doclint/Source.js index 455f41924372e..dd77eac9469d3 100644 --- a/utils/doclint/Source.js +++ b/utils/doclint/Source.js @@ -15,11 +15,12 @@ */ const path = require('path'); +const util = require('util'); const fs = require('fs'); -const readFileAsync = promisify(fs.readFile); -const readdirAsync = promisify(fs.readdir); -const writeFileAsync = promisify(fs.writeFile); +const readFileAsync = util.promisify(fs.readFile); +const readdirAsync = util.promisify(fs.readdir); +const writeFileAsync = util.promisify(fs.writeFile); const PROJECT_DIR = path.join(__dirname, '..', '..'); @@ -110,26 +111,3 @@ class Source { } module.exports = Source; -/** - * @param {function(?)} nodeFunction - * @return {function(?):!Promise} - */ -function promisify(nodeFunction) { - /** - * @param {!Array} options - * @return {!Promise} - */ - return function(...options) { - return new Promise(function(fulfill, reject) { - options.push(callback); - nodeFunction.call(null, ...options); - function callback(err, result) { - if (err) - reject(err); - else - fulfill(result); - } - }); - }; -} - diff --git a/utils/node6-transform/TransformAsyncFunctions.js b/utils/node6-transform/TransformAsyncFunctions.js deleted file mode 100644 index 5903d89839d11..0000000000000 --- a/utils/node6-transform/TransformAsyncFunctions.js +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const esprima = require('esprima'); -const ESTreeWalker = require('../ESTreeWalker'); - -// This is converted from Babel's "transform-async-to-generator" -// https://babeljs.io/docs/plugins/transform-async-to-generator/ -const asyncToGenerator = fn => { - const gen = fn.call(this); - return new Promise((resolve, reject) => { - function step(key, arg) { - let info, value; - try { - info = gen[key](arg); - value = info.value; - } catch (error) { - reject(error); - return; - } - if (info.done) { - resolve(value); - } else { - return Promise.resolve(value).then( - value => { - step('next', value); - }, - err => { - step('throw', err); - }); - } - } - return step('next'); - }); -}; - -/** - * @param {string} text - * @return {string} - */ -function transformAsyncFunctions(text) { - /** - * @type {!Array<{from: number, to: number, replacement: string}>} - */ - const edits = []; - - const ast = esprima.parseScript(text, {range: true, tolerant: true}); - const walker = new ESTreeWalker(node => { - if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'ArrowFunctionExpression') - onBeforeFunction(node); - else if (node.type === 'AwaitExpression') - onBeforeAwait(node); - }, node => { - if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'ArrowFunctionExpression') - onAfterFunction(node); - else if (node.type === 'AwaitExpression') - onAfterAwait(node); - }); - walker.walk(ast); - - edits.reverse(); - for (const {replacement, from, to} of edits) - text = text.substring(0, from) + replacement + text.substring(to); - - return text; - - /** - * @param {ESTree.Node} node - */ - function onBeforeFunction(node) { - if (!node.async) return; - - let range; - if (node.parent.type === 'MethodDefinition') - range = node.parent.range; - else - range = node.range; - const index = text.substring(range[0], range[1]).indexOf('async') + range[0]; - insertText(index, index + 'async'.length, '/* async */'); - - let before = `{return (${asyncToGenerator.toString()})(function*()`; - if (node.body.type !== 'BlockStatement') { - before += `{ return `; - - // Remove parentheses that might wrap an arrow function - const beforeBody = text.substring(node.range[0], node.body.range[0]); - if (/\(\s*$/.test(beforeBody)) { - const openParen = node.range[0] + beforeBody.lastIndexOf('('); - insertText(openParen, openParen + 1, ' '); - } - } - - - insertText(node.body.range[0], node.body.range[0], before); - } - - /** - * @param {ESTree.Node} node - */ - function onAfterFunction(node) { - if (!node.async) return; - - let after = `);}`; - if (node.body.type !== 'BlockStatement') - after = `; }` + after; - insertText(node.body.range[1], node.body.range[1], after); - - if (node.body.type !== 'BlockStatement') { - // Remove parentheses that might wrap an arrow function - const beforeBody = text.substring(node.range[0], node.body.range[0]); - if (/\(\s*$/.test(beforeBody)) { - const afterBody = text.substring(node.body.range[1], node.range[1]); - const closeParen = node.body.range[1] + afterBody.indexOf(')'); - insertText(closeParen, closeParen + 1, ' '); - } - } - } - - /** - * @param {ESTree.Node} node - */ - function onBeforeAwait(node) { - const index = text.substring(node.range[0], node.range[1]).indexOf('await') + node.range[0]; - insertText(index, index + 'await'.length, '(yield'); - } - - /** - * @param {ESTree.Node} node - */ - function onAfterAwait(node) { - insertText(node.range[1], node.range[1], ')'); - } - - /** - * @param {number} from - * @param {number} to - */ - function insertText(from, to, replacement) { - edits.push({from, to, replacement}); - } -} - -module.exports = transformAsyncFunctions; \ No newline at end of file diff --git a/utils/node6-transform/index.js b/utils/node6-transform/index.js deleted file mode 100644 index 967899f9a104d..0000000000000 --- a/utils/node6-transform/index.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const fs = require('fs'); -const path = require('path'); -const removeRecursive = require('rimraf').sync; -const transformAsyncFunctions = require('./TransformAsyncFunctions'); - -const root = path.join(__dirname, '..', '..'); -const dest = path.join(__dirname, '..', '..', 'node6'); - -const excludes = [ - path.resolve(root, 'test', 'assets'), -]; - -if (fs.existsSync(dest)) - removeRecursive(dest); -fs.mkdirSync(dest); -fs.mkdirSync(path.join(dest, 'utils')); - -copyFolder(path.join(root, 'lib'), path.join(dest, 'lib')); -copyFolder(path.join(root, 'test'), path.join(dest, 'test')); -copyFolder(path.join(root, 'utils', 'testrunner'), path.join(dest, 'utils', 'testrunner')); -copyFolder(path.join(root, 'utils', 'testserver'), path.join(dest, 'utils', 'testserver')); - -function copyFolder(source, target) { - if (fs.existsSync(target)) - removeRecursive(target); - fs.mkdirSync(target); - - fs.readdirSync(source).forEach(file => { - const from = path.join(source, file); - const to = path.join(target, file); - if (fs.lstatSync(from).isDirectory()) - copyFolder(from, to); - else - copyFile(from, to); - }); -} - -function copyFile(from, to) { - let text = fs.readFileSync(from); - const isExcluded = excludes.some(exclude => from.startsWith(exclude)); - if (!isExcluded && from.endsWith('.js')) { - text = text.toString(); - const prefix = text.startsWith('#!') ? text.substring(0, text.indexOf('\n')) : ''; - text = prefix + transformAsyncFunctions(text.substring(prefix.length)); - } - fs.writeFileSync(to, text); -} diff --git a/utils/node6-transform/test/test.js b/utils/node6-transform/test/test.js deleted file mode 100644 index 46836d848ec8a..0000000000000 --- a/utils/node6-transform/test/test.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright 2017 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -const transformAsyncFunctions = require('../TransformAsyncFunctions'); - -const {TestRunner, Reporter, Matchers} = require('../../testrunner/'); -const runner = new TestRunner(); -new Reporter(runner); - -const {describe, xdescribe, fdescribe} = runner; -const {it, fit, xit} = runner; -const {beforeAll, beforeEach, afterAll, afterEach} = runner; - -const {expect} = new Matchers(); - -describe('TransformAsyncFunctions', function() { - it('should convert a function expression', function(done) { - const input = `(async function(){ return 123 })()`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should convert an arrow function', function(done) { - const input = `(async () => 123)()`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should convert an arrow function with curly braces', function(done) { - const input = `(async () => { return 123 })()`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should convert a function declaration', function(done) { - const input = `async function f(){ return 123; } f();`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should convert await', function(done) { - const input = `async function f(){ return 23 + await Promise.resolve(100); } f();`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should convert method', function(done) { - const input = `class X{async f() { return 123 }} (new X()).f();`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should pass arguments', function(done) { - const input = `(async function(a, b){ return await a + await b })(Promise.resolve(100), 23)`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should still work across eval', function(done) { - const input = `var str = (async function(){ return 123; }).toString(); eval('(' + str + ')')();`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should work with double await', function(done) { - const input = `async function f(){ return 23 + await Promise.resolve(50 + await Promise.resolve(50)); } f();`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should work paren around arrow function', function(done) { - const input = `(async x => ( 123))()`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); - it('should work async arrow with await', function(done) { - const input = `(async() => await 123)()`; - const output = eval(transformAsyncFunctions(input)); - expect(output instanceof Promise).toBe(true); - output.then(result => expect(result).toBe(123)).then(done); - }); -}); - -runner.run(); From 9cea37974375043154524f87e2630d30a639554e Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Wed, 11 Sep 2019 10:20:28 +0200 Subject: [PATCH 2/7] Remove supportsAsyncAwait --- install.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/install.js b/install.js index 2e3f52b540411..1e9faf53ad0e2 100644 --- a/install.js +++ b/install.js @@ -107,18 +107,7 @@ function toMegabytes(bytes) { return `${Math.round(mb * 10) / 10} Mb`; } -function supportsAsyncAwait() { - try { - new Function('async function test(){await 1}'); - } catch (error) { - return false; - } - return true; -} - function generateProtocolTypesIfNecessary(updated) { - if (!supportsAsyncAwait()) - return; const fs = require('fs'); const path = require('path'); if (!fs.existsSync(path.join(__dirname, 'utils', 'protocol-types-generator'))) From 85a3386fdf2fa6a73a652705cc7a3377e0e27b30 Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Wed, 16 Oct 2019 10:31:24 +0200 Subject: [PATCH 3/7] Add LTS note to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ae705d9366eb8..468eed34f5373 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ See [puppeteer vs puppeteer-core](https://github.com/GoogleChrome/puppeteer/blob ### Usage +Puppeteer follows the latest [maintenance LTS](https://github.com/nodejs/Release#release-schedule) version of Node. + Note: Prior to v1.18.1, Puppeteer required at least Node v6.4.0. All subsequent versions rely on Node 8.9.0+. All examples below use async/await which is only supported in Node v7.6.0 or greater. From b10db48534c545c5afb31b65b35a74e3b1eaa856 Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Wed, 16 Oct 2019 10:50:40 +0200 Subject: [PATCH 4/7] Bump to latest Node.js v8 LTS --- .appveyor.yml | 2 +- .travis.yml | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 49f62d4f1b673..6a2eeff1eb13b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,6 @@ environment: matrix: - - nodejs_version: "8.11.3" + - nodejs_version: "8.16.2" FLAKINESS_DASHBOARD_NAME: Appveyor Chromium (Win + node8) FLAKINESS_DASHBOARD_PASSWORD: secure: g66jP+j6C+hkXLutBV9fdxB5fRJgcQQzy93SgQzXUmcCl/RjkJwnzyHvX0xfCVnv diff --git a/.travis.yml b/.travis.yml index 3168bdd3be179..86cb12a91e7ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,12 +26,12 @@ script: - 'if [ "$NODE8" = "true" ]; then npm run unit-bundle; fi' jobs: include: - - node_js: "8.11.3" + - node_js: "8.16.2" env: - NODE8=true - FLAKINESS_DASHBOARD_NAME="Travis Chromium (node8 + linux)" - FLAKINESS_DASHBOARD_BUILD_URL="${TRAVIS_JOB_WEB_URL}" - - node_js: "8.11.3" + - node_js: "8.16.2" env: - FIREFOX=true - FLAKINESS_DASHBOARD_NAME="Travis Firefox (node8 + linux)" diff --git a/package.json b/package.json index 13ace7c1debf7..618e998facec9 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "repository": "github:GoogleChrome/puppeteer", "engines": { - "node": ">=8.9.0" + "node": ">=8.16.2" }, "puppeteer": { "chromium_revision": "686378" From e13199474a86320cfb4f7271a486a89dcd650f81 Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Wed, 16 Oct 2019 13:07:24 +0200 Subject: [PATCH 5/7] Tweak flaky test This shouldn't affect its flakiness. --- test/launcher.spec.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/launcher.spec.js b/test/launcher.spec.js index bb415ffa1220d..78fdd93cef1d0 100644 --- a/test/launcher.spec.js +++ b/test/launcher.spec.js @@ -234,9 +234,10 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p const browser = await puppeteer.launch(options); const pages = await browser.pages(); expect(pages.length).toBe(1); - if (pages[0].url() !== server.EMPTY_PAGE) - await pages[0].waitForNavigation(); - expect(pages[0].url()).toBe(server.EMPTY_PAGE); + const page = pages[0]; + if (page.url() !== server.EMPTY_PAGE) + await page.waitForNavigation(); + expect(page.url()).toBe(server.EMPTY_PAGE); await browser.close(); }); it('should set the default viewport', async() => { From 112fd20d6533ee47db9c0fd87c8fd2516ecf4658 Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Wed, 16 Oct 2019 13:15:20 +0200 Subject: [PATCH 6/7] Use an older Node.js that appveyor hopefully supports --- .appveyor.yml | 4 ++-- .travis.yml | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6a2eeff1eb13b..1ec90faa2b4da 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,6 @@ environment: matrix: - - nodejs_version: "8.16.2" + - nodejs_version: "8.16.0" FLAKINESS_DASHBOARD_NAME: Appveyor Chromium (Win + node8) FLAKINESS_DASHBOARD_PASSWORD: secure: g66jP+j6C+hkXLutBV9fdxB5fRJgcQQzy93SgQzXUmcCl/RjkJwnzyHvX0xfCVnv @@ -11,7 +11,7 @@ install: - ps: $env:FLAKINESS_DASHBOARD_BUILD_URL="https://ci.appveyor.com/project/aslushnikov/puppeteer/builds/$env:APPVEYOR_BUILD_ID/job/$env:APPVEYOR_JOB_ID" - ps: Install-Product node $env:nodejs_version - npm install - - if "%nodejs_version%" == "8.11.3" ( + - if "%nodejs_version%" == "8.16.0" ( npm run lint && npm run coverage && npm run test-doclint && diff --git a/.travis.yml b/.travis.yml index 86cb12a91e7ec..84f45ce3c4f3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,12 +26,12 @@ script: - 'if [ "$NODE8" = "true" ]; then npm run unit-bundle; fi' jobs: include: - - node_js: "8.16.2" + - node_js: "8.16.0" env: - NODE8=true - FLAKINESS_DASHBOARD_NAME="Travis Chromium (node8 + linux)" - FLAKINESS_DASHBOARD_BUILD_URL="${TRAVIS_JOB_WEB_URL}" - - node_js: "8.16.2" + - node_js: "8.16.0" env: - FIREFOX=true - FLAKINESS_DASHBOARD_NAME="Travis Firefox (node8 + linux)" diff --git a/package.json b/package.json index 618e998facec9..66d31c2d89e44 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "repository": "github:GoogleChrome/puppeteer", "engines": { - "node": ">=8.16.2" + "node": ">=8.16.0" }, "puppeteer": { "chromium_revision": "686378" From 38a2deab219585b69bea4008c9ef03e52f120dac Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Wed, 16 Oct 2019 14:35:53 +0200 Subject: [PATCH 7/7] Restore helper.promisify so puppeteer-web doesn't break We can reconsider this once https://github.com/browserify/browserify/pull/1844 gets merged. --- .../puppeteer-firefox/lib/BrowserFetcher.js | 8 ++--- experimental/puppeteer-firefox/lib/Page.js | 3 +- experimental/puppeteer-firefox/lib/helper.js | 20 +++++++++++++ lib/BrowserFetcher.js | 10 +++---- lib/DOMWorld.js | 3 +- lib/Launcher.js | 5 ++-- lib/Page.js | 3 +- lib/helper.js | 29 +++++++++++++++---- test/launcher.spec.js | 11 ++++--- 9 files changed, 63 insertions(+), 29 deletions(-) diff --git a/experimental/puppeteer-firefox/lib/BrowserFetcher.js b/experimental/puppeteer-firefox/lib/BrowserFetcher.js index c222754d32584..c7d1250e4c1ee 100644 --- a/experimental/puppeteer-firefox/lib/BrowserFetcher.js +++ b/experimental/puppeteer-firefox/lib/BrowserFetcher.js @@ -82,10 +82,10 @@ function downloadURL(product, platform, host, revision) { return util.format(downloadURLs[product][platform], host, revision, archiveName(product, platform, revision)); } -const readdirAsync = util.promisify(fs.readdir.bind(fs)); -const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); -const unlinkAsync = util.promisify(fs.unlink.bind(fs)); -const chmodAsync = util.promisify(fs.chmod.bind(fs)); +const readdirAsync = helper.promisify(fs.readdir.bind(fs)); +const mkdirAsync = helper.promisify(fs.mkdir.bind(fs)); +const unlinkAsync = helper.promisify(fs.unlink.bind(fs)); +const chmodAsync = helper.promisify(fs.chmod.bind(fs)); function existsAsync(filePath) { let fulfill = null; diff --git a/experimental/puppeteer-firefox/lib/Page.js b/experimental/puppeteer-firefox/lib/Page.js index c2ce1bdb3ed6f..de5c7b41e95f1 100644 --- a/experimental/puppeteer-firefox/lib/Page.js +++ b/experimental/puppeteer-firefox/lib/Page.js @@ -4,7 +4,6 @@ const {Dialog} = require('./Dialog'); const {TimeoutError} = require('./Errors'); const fs = require('fs'); const mime = require('mime'); -const util = require('util'); const EventEmitter = require('events'); const {createHandle} = require('./JSHandle'); const {Events} = require('./Events'); @@ -15,7 +14,7 @@ const {TimeoutSettings} = require('./TimeoutSettings'); const {NavigationWatchdog} = require('./NavigationWatchdog'); const {Accessibility} = require('./Accessibility'); -const writeFileAsync = util.promisify(fs.writeFile); +const writeFileAsync = helper.promisify(fs.writeFile); class Page extends EventEmitter { /** diff --git a/experimental/puppeteer-firefox/lib/helper.js b/experimental/puppeteer-firefox/lib/helper.js index 07f180c7f1be7..92e86ad22b5c6 100644 --- a/experimental/puppeteer-firefox/lib/helper.js +++ b/experimental/puppeteer-firefox/lib/helper.js @@ -65,6 +65,26 @@ class Helper { } } + /** + * @param {function} nodeFunction + * @return {function} + */ + static promisify(nodeFunction) { + function promisified(...args) { + return new Promise((resolve, reject) => { + function callback(err, ...result) { + if (err) + return reject(err); + if (result.length === 1) + return resolve(result[0]); + return resolve(result); + } + nodeFunction.call(null, ...args, callback); + }); + } + return promisified; + } + /** * @param {!Object} obj * @return {boolean} diff --git a/lib/BrowserFetcher.js b/lib/BrowserFetcher.js index cea6e3ee97f13..aace9220591f4 100644 --- a/lib/BrowserFetcher.js +++ b/lib/BrowserFetcher.js @@ -20,7 +20,7 @@ const path = require('path'); const util = require('util'); const extract = require('extract-zip'); const URL = require('url'); -const {assert} = require('./helper'); +const {helper, assert} = require('./helper'); const removeRecursive = require('rimraf'); // @ts-ignore const ProxyAgent = require('https-proxy-agent'); @@ -64,10 +64,10 @@ function downloadURL(platform, host, revision) { return util.format(downloadURLs[platform], host, revision, archiveName(platform, revision)); } -const readdirAsync = util.promisify(fs.readdir.bind(fs)); -const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); -const unlinkAsync = util.promisify(fs.unlink.bind(fs)); -const chmodAsync = util.promisify(fs.chmod.bind(fs)); +const readdirAsync = helper.promisify(fs.readdir.bind(fs)); +const mkdirAsync = helper.promisify(fs.mkdir.bind(fs)); +const unlinkAsync = helper.promisify(fs.unlink.bind(fs)); +const chmodAsync = helper.promisify(fs.chmod.bind(fs)); function existsAsync(filePath) { let fulfill = null; diff --git a/lib/DOMWorld.js b/lib/DOMWorld.js index ba1a3193449d4..c5852cacd9faf 100644 --- a/lib/DOMWorld.js +++ b/lib/DOMWorld.js @@ -15,11 +15,10 @@ */ const fs = require('fs'); -const util = require('util'); const {helper, assert} = require('./helper'); const {LifecycleWatcher} = require('./LifecycleWatcher'); const {TimeoutError} = require('./Errors'); -const readFileAsync = util.promisify(fs.readFile); +const readFileAsync = helper.promisify(fs.readFile); /** * @unrestricted diff --git a/lib/Launcher.js b/lib/Launcher.js index 6a3e4db0463f1..41dc1e5da3ce5 100644 --- a/lib/Launcher.js +++ b/lib/Launcher.js @@ -15,7 +15,6 @@ */ const os = require('os'); const path = require('path'); -const util = require('util'); const http = require('http'); const https = require('https'); const URL = require('url'); @@ -31,8 +30,8 @@ const {TimeoutError} = require('./Errors'); const WebSocketTransport = require('./WebSocketTransport'); const PipeTransport = require('./PipeTransport'); -const mkdtempAsync = util.promisify(fs.mkdtemp); -const removeFolderAsync = util.promisify(removeFolder); +const mkdtempAsync = helper.promisify(fs.mkdtemp); +const removeFolderAsync = helper.promisify(removeFolder); const CHROME_PROFILE_PATH = path.join(os.tmpdir(), 'puppeteer_dev_profile-'); diff --git a/lib/Page.js b/lib/Page.js index d1cd837bfc400..0bdd217c8291f 100644 --- a/lib/Page.js +++ b/lib/Page.js @@ -18,7 +18,6 @@ const fs = require('fs'); const path = require('path'); const EventEmitter = require('events'); const mime = require('mime'); -const util = require('util'); const {Events} = require('./Events'); const {Connection} = require('./Connection'); const {Dialog} = require('./Dialog'); @@ -33,7 +32,7 @@ const {createJSHandle} = require('./JSHandle'); const {Accessibility} = require('./Accessibility'); const {TimeoutSettings} = require('./TimeoutSettings'); -const writeFileAsync = util.promisify(fs.writeFile); +const writeFileAsync = helper.promisify(fs.writeFile); class Page extends EventEmitter { /** diff --git a/lib/helper.js b/lib/helper.js index 231a148e08803..3c5d987ad0b99 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -16,11 +16,6 @@ const {TimeoutError} = require('./Errors'); const debugError = require('debug')(`puppeteer:error`); const fs = require('fs'); -const util = require('util'); - -const openAsync = util.promisify(fs.open); -const writeAsync = util.promisify(fs.write); -const closeAsync = util.promisify(fs.close); class Helper { /** @@ -161,6 +156,26 @@ class Helper { return typeof obj === 'number' || obj instanceof Number; } + /** + * @param {function} nodeFunction + * @return {function} + */ + static promisify(nodeFunction) { + function promisified(...args) { + return new Promise((resolve, reject) => { + function callback(err, ...result) { + if (err) + return reject(err); + if (result.length === 1) + return resolve(result[0]); + return resolve(result); + } + nodeFunction.call(null, ...args, callback); + }); + } + return promisified; + } + /** * @param {!NodeJS.EventEmitter} emitter * @param {(string|symbol)} eventName @@ -255,6 +270,10 @@ class Helper { } } +const openAsync = Helper.promisify(fs.open); +const writeAsync = Helper.promisify(fs.write); +const closeAsync = Helper.promisify(fs.close); + /** * @param {*} value * @param {string=} message diff --git a/test/launcher.spec.js b/test/launcher.spec.js index 78fdd93cef1d0..8cb43a9737a42 100644 --- a/test/launcher.spec.js +++ b/test/launcher.spec.js @@ -16,12 +16,11 @@ const fs = require('fs'); const os = require('os'); const path = require('path'); -const util = require('util'); - -const rmAsync = util.promisify(require('rimraf')); -const mkdtempAsync = util.promisify(fs.mkdtemp); -const readFileAsync = util.promisify(fs.readFile); -const statAsync = util.promisify(fs.stat); +const {helper} = require('../lib/helper'); +const rmAsync = helper.promisify(require('rimraf')); +const mkdtempAsync = helper.promisify(fs.mkdtemp); +const readFileAsync = helper.promisify(fs.readFile); +const statAsync = helper.promisify(fs.stat); const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); const utils = require('./utils');