diff --git a/appengine/headless-chrome/README.md b/appengine/headless-chrome/README.md new file mode 100644 index 0000000000..36ebb7fc99 --- /dev/null +++ b/appengine/headless-chrome/README.md @@ -0,0 +1,7 @@ +# Headless Chrome on Google App Engine + +This sample application demonstrates how to use Headless Chrome via the [Puppeteer](https://developers.google.com/web/tools/puppeteer/) module to take screenshots of webpages on [Google App Engine](https://cloud.google.com/appengine) Node.js [standard environment](https://cloud.google.com/appengine/docs/standard/nodejs). + +## Running and deploying + +Refer to the [appengine/README.md](../README.md) file for instructions on running and deploying. diff --git a/appengine/headless-chrome/app.js b/appengine/headless-chrome/app.js new file mode 100644 index 0000000000..036a8bab43 --- /dev/null +++ b/appengine/headless-chrome/app.js @@ -0,0 +1,51 @@ +/* +Copyright 2018 Google LLC + +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. +*/ +'use strict'; + +// [START full_sample] +const express = require('express'); +const puppeteer = require('puppeteer'); +const app = express(); + +app.use(async (req, res) => { + const url = req.query.url; + + if (!url) { + return res.send('Please provide URL as GET parameter, for example: ?url=https://example.com'); + } + + // [START browser] + const browser = await puppeteer.launch({ + args: ['--no-sandbox', '--disable-setuid-sandbox'] + }); + // [END browser] + const page = await browser.newPage(); + await page.goto(url); + const imageBuffer = await page.screenshot(); + await browser.close(); + + res.set('Content-Type', 'image/png'); + res.send(imageBuffer); +}); + +const server = app.listen(process.env.PORT || 8080, err => { + if (err) return console.error(err); + const port = server.address().port; + console.info(`App listening on port ${port}`); +}); +// [END full_sample] + +module.exports = app; diff --git a/appengine/headless-chrome/app.standard.yaml b/appengine/headless-chrome/app.standard.yaml new file mode 100644 index 0000000000..7b9ee1e02b --- /dev/null +++ b/appengine/headless-chrome/app.standard.yaml @@ -0,0 +1,17 @@ +# Copyright 2018, Google LLC +# 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 + +# [START app_yaml] +runtime: nodejs8 +instance_class: F4_1G +# [END app_yaml] diff --git a/appengine/headless-chrome/package.json b/appengine/headless-chrome/package.json new file mode 100644 index 0000000000..0188f0a5e5 --- /dev/null +++ b/appengine/headless-chrome/package.json @@ -0,0 +1,42 @@ +{ + "name": "headless-chrome-sample", + "engines": { + "node": "8.x" + }, + "version": "1.0.0", + "description": "An example of taking screenshot with Puppeteer (Headless Chrome) in Node.js on Google App Engine.", + "scripts": { + "start": "node app.js", + "system-test": "repo-tools test app", + "unit-test": "ava --verbose test/*.test.js", + "lint": "repo-tools lint", + "pretest": "npm run lint", + "test": "npm run unit-test && npm run system-test" + }, + "repository": { + "type": "git", + "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git" + }, + "author": { + "name": "Google LLC" + }, + "license": "Apache-2.0", + "dependencies": { + "express": "^4.16.3", + "puppeteer": "^1.2.0" + }, + "devDependencies": { + "@google-cloud/nodejs-repo-tools": "2.3.0", + "ava": "^0.25.0", + "semistandard": "^12.0.1" + }, + "cloud-repo-tools": { + "test": { + "app": { + "msg": "Please provide URL" + } + }, + "requiresKeyFile": true, + "requiresProjectId": true + } +} diff --git a/appengine/headless-chrome/test/app.test.js b/appengine/headless-chrome/test/app.test.js new file mode 100644 index 0000000000..02dac67deb --- /dev/null +++ b/appengine/headless-chrome/test/app.test.js @@ -0,0 +1,39 @@ +// Copyright 2017, Google, Inc. +// 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. + +// NOTE: +// This app can only be fully tested when deployed, because +// Pub/Sub requires a live endpoint URL to hit. Nevertheless, +// these tests mock it and partially test it locally. + +'use strict'; + +const test = require(`ava`); +const path = require(`path`); +const utils = require(`@google-cloud/nodejs-repo-tools`); + +const cwd = path.join(__dirname, `../`); +const requestObj = utils.getRequest({ cwd: cwd }); + +test.serial.cb(`should return a screenshot`, t => { + requestObj + .get(`/?url=https://example.com`) + .send() + .expect(200) + .expect(response => { + t.is(response.type, `image/png`); + t.true(response.body instanceof Buffer); + t.true(response.body.length > 0); + }) + .end(t.end); +});