From 07d8bc6d4cfea0a765cd5730b142f63685a1587e Mon Sep 17 00:00:00 2001 From: Joel Griffith Date: Mon, 31 Jul 2017 19:03:04 -0700 Subject: [PATCH 1/2] chrome-launcher + spelling fixes + docs --- README.md | 6 ++---- package.json | 5 ++++- src/api.ts | 1 + src/chrome/local-runtime.ts | 20 ++++++++++---------- src/chrome/local.ts | 26 +++++++++++++++++++++++--- src/types.ts | 1 + src/util.ts | 6 ++---- yarn.lock | 33 +++++++++++++++++++++++++++++++-- 8 files changed, 74 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 7b3f11fa..d1f0fd57 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,9 @@ run().catch(console.error.bind(console)) ### Local Chrome Usage -To run Chromeless locally, you need a recent version of Chrome or Chrome Canary installed and running. +To run Chromeless locally, you need a recent version of Chrome or Chrome Canary installed (version 60 or greater). By default, chromeless will start Chrome automatically and will default to the most recent version found on your system if there's multiple. You can override this behavior by starting Chrome yourself, and passing a flag of `launchChrome: false` in the `Chromeless` constructor. -Chromeless requires Chrome version 60 or greater. - -For example, on MacOS: +To launch Chrome yourself, and open the port for chromeless, follow this example: ```sh alias canary="/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary" diff --git a/package.json b/package.json index a1445aef..3155f7ec 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ }, "main": "dist/src/index.js", "typings": "dist/src/index.d.ts", - "files": ["dist"], + "files": [ + "dist" + ], "engines": { "node": ">= 6.10.0" }, @@ -27,6 +29,7 @@ "dependencies": { "aws-sdk": "^2.90.0", "bluebird": "^3.5.0", + "chrome-launcher": "^0.3.2", "chrome-remote-interface": "^0.24.2", "cuid": "^1.3.8", "form-data": "^2.1.4", diff --git a/src/api.ts b/src/api.ts index 75d8c184..7507898c 100644 --- a/src/api.ts +++ b/src/api.ts @@ -21,6 +21,7 @@ export default class Chromeless implements Promise { waitTimeout: 10000, remote: false, implicitWait: true, + launchChrome: true, ...options, diff --git a/src/chrome/local-runtime.ts b/src/chrome/local-runtime.ts index 8060be57..7a421470 100644 --- a/src/chrome/local-runtime.ts +++ b/src/chrome/local-runtime.ts @@ -21,11 +21,11 @@ import { export default class LocalRuntime { private client: Client - private chromlessOptions: ChromelessOptions + private chromelessOptions: ChromelessOptions - constructor(client: Client, chromlessOptions: ChromelessOptions) { + constructor(client: Client, chromelessOptions: ChromelessOptions) { this.client = client - this.chromlessOptions = chromlessOptions + this.chromelessOptions = chromelessOptions } async run(command: Command): Promise { @@ -86,14 +86,14 @@ export default class LocalRuntime { private async waitSelector(selector: string): Promise { this.log(`Waiting for ${selector}`) - await waitForNode(this.client, selector, this.chromlessOptions.waitTimeout) + await waitForNode(this.client, selector, this.chromelessOptions.waitTimeout) this.log(`Waited for ${selector}`) } private async click(selector: string): Promise { - if (this.chromlessOptions.implicitWait) { + if (this.chromelessOptions.implicitWait) { this.log(`click(): Waiting for ${selector}`) - await waitForNode(this.client, selector, this.chromlessOptions.waitTimeout) + await waitForNode(this.client, selector, this.chromelessOptions.waitTimeout) } const exists = await nodeExists(this.client, selector) @@ -101,7 +101,7 @@ export default class LocalRuntime { throw new Error(`click(): node for selector ${selector} doesn't exist`) } - const {scale} = this.chromlessOptions.viewport + const {scale} = this.chromelessOptions.viewport await click(this.client, selector, scale) this.log(`Clicked on ${selector}`) } @@ -116,9 +116,9 @@ export default class LocalRuntime { async type(text: string, selector?: string): Promise { if (selector) { - if (this.chromlessOptions.implicitWait) { + if (this.chromelessOptions.implicitWait) { this.log(`type(): Waiting for ${selector}`) - await waitForNode(this.client, selector, this.chromlessOptions.waitTimeout) + await waitForNode(this.client, selector, this.chromelessOptions.waitTimeout) } const exists = await nodeExists(this.client, selector) @@ -209,7 +209,7 @@ export default class LocalRuntime { } private log(msg: string): void { - if (this.chromlessOptions.debug) { + if (this.chromelessOptions.debug) { console.log(msg) } } diff --git a/src/chrome/local.ts b/src/chrome/local.ts index 89e686cd..e4631b20 100644 --- a/src/chrome/local.ts +++ b/src/chrome/local.ts @@ -1,5 +1,6 @@ import { Chrome, Command, ChromelessOptions, Client } from '../types' import * as CDP from 'chrome-remote-interface' +import { LaunchedChrome, launch } from 'chrome-launcher' import LocalRuntime from './local-runtime' import { evaluate } from '../util' @@ -11,6 +12,7 @@ interface RuntimeClient { export default class LocalChrome implements Chrome { private options: ChromelessOptions private runtimeClientPromise: Promise + private chromeInstance?: LaunchedChrome constructor(options: ChromelessOptions = {}) { this.options = options @@ -18,9 +20,23 @@ export default class LocalChrome implements Chrome { this.runtimeClientPromise = this.initRuntimeClient() } - private async initRuntimeClient(): Promise { + private async startChrome(): Promise { + this.chromeInstance = await launch({ + logLevel: this.options.debug ? 'info' : 'silent', + port: this.options.cdp.port + }) + return await CDP({ port: this.chromeInstance.port }) + } + + private async connectToChrome(): Promise { const target = await CDP.New() - const client = await CDP({ target }) + return await CDP({ target }) + } + + private async initRuntimeClient(): Promise { + const client = this.options.launchChrome ? + await this.startChrome() : + await this.connectToChrome() await this.setViewport(client) @@ -39,7 +55,7 @@ export default class LocalChrome implements Chrome { fitWindow: false, // as we cannot resize the window, `fitWindow: false` is needed in order for the viewport to be resizable } - const versionResult = await CDP.Version() + const versionResult = await CDP.Version({ port: this.chromeInstance.port }) const isHeadless = versionResult['User-Agent'].includes('Headless') if (viewport.height && viewport.width) { @@ -80,6 +96,10 @@ export default class LocalChrome implements Chrome { CDP.Close({ id: client.target.id }) } + if (this.chromeInstance) { + this.chromeInstance.kill() + } + await client.close() } } diff --git a/src/types.ts b/src/types.ts index f0bc1ac5..53bdaaad 100644 --- a/src/types.ts +++ b/src/types.ts @@ -31,6 +31,7 @@ export interface ChromelessOptions { height?: number // 900 if headless scale?: number // 1 } + launchChrome?: boolean // auto-launch chrome (local) `true` cdp?: CDPOptions remote?: RemoteOptions | boolean } diff --git a/src/util.ts b/src/util.ts index 1b54a855..79d93722 100644 --- a/src/util.ts +++ b/src/util.ts @@ -53,7 +53,7 @@ export async function wait(timeout: number): Promise { export async function nodeExists(client: Client, selector: string): Promise { const {Runtime} = client const exists = (selector) => { - return document.querySelector(selector) + return !!document.querySelector(selector) } const expression = `(${exists})(\`${selector}\`)` @@ -62,9 +62,7 @@ export async function nodeExists(client: Client, selector: string): Promise { diff --git a/yarn.lock b/yarn.lock index 2125a384..2d03aa4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -48,10 +48,22 @@ version "3.5.8" resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.8.tgz#242a83379f06c90f96acf6d1aeab3af6faebdb98" +"@types/core-js@^0.9.41": + version "0.9.42" + resolved "https://npm.corp.appnexus.com/@types%2fcore-js/-/core-js-0.9.42.tgz#dd6da92cd7d5ab5ca0b4477524537c3e633b6bce" + "@types/cuid@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@types/cuid/-/cuid-1.3.0.tgz#20b0e00ca555df564866bc52d2e251bf90c88db7" +"@types/mkdirp@^0.3.29": + version "0.3.29" + resolved "https://npm.corp.appnexus.com/@types%2fmkdirp/-/mkdirp-0.3.29.tgz#7f2ad7ec55f914482fc9b1ec4bb1ae6028d46066" + +"@types/node@6.0.66": + version "6.0.66" + resolved "https://npm.corp.appnexus.com/@types%2fnode/-/node-6.0.66.tgz#5680b74a6135d33d4c00447e7c3dc691a4601625" + "@types/node@^8.0.15": version "8.0.16" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.16.tgz#5aa51abd72621a0ce53fb86bccd76825ee1b4ca9" @@ -774,6 +786,17 @@ chokidar@^1.4.2: optionalDependencies: fsevents "^1.0.0" +chrome-launcher@^0.3.2: + version "0.3.2" + resolved "https://npm.corp.appnexus.com/chrome-launcher/-/chrome-launcher-0.3.2.tgz#c3a89e40ed2462899bac809417c4d7c451d5de05" + dependencies: + "@types/core-js" "^0.9.41" + "@types/mkdirp" "^0.3.29" + "@types/node" "6.0.66" + lighthouse-logger "^1.0.0" + mkdirp "0.5.1" + rimraf "^2.6.1" + chrome-remote-interface@^0.24.2: version "0.24.2" resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.24.2.tgz#43a05440a1fa60b73769e72f3e7892ac11d66eba" @@ -1005,7 +1028,7 @@ date-time@^2.1.0: dependencies: time-zone "^1.0.0" -debug@^2.1.1, debug@^2.2.0: +debug@^2.1.1, debug@^2.2.0, debug@^2.6.8: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: @@ -1886,6 +1909,12 @@ leven@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" +lighthouse-logger@^1.0.0: + version "1.0.0" + resolved "https://npm.corp.appnexus.com/lighthouse-logger/-/lighthouse-logger-1.0.0.tgz#c6abdfbbbf0b4a541ab33864802cbad8944bcc8c" + dependencies: + debug "^2.6.8" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -2069,7 +2098,7 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" -"mkdirp@>=0.5 0", mkdirp@^0.5.1: +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: From 51015a6e26964654c1bf3d99ed17fbaccc9c69c8 Mon Sep 17 00:00:00 2001 From: Joel Griffith Date: Tue, 1 Aug 2017 08:22:06 -0700 Subject: [PATCH 2/2] PR feedback and run.ts fixes --- CHANGELOG.md | 2 ++ serverless/src/run.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 832d506b..9f996cd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - CODE_OF_CONDUCT.md, CONTRIBUTING.md +- When using chromeless locally, chromeless will now boot chrome automatically [#120](https://github.com/graphcool/chromeless/pull/120) @joelgriffith ### Changed - `.evaluate()` now returns the resulting value or a Promise [#110](https://github.com/graphcool/chromeless/pull/110) @joelgriffith @@ -17,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - Ensure latest version of Serverless is used during deployment. [#58](https://github.com/graphcool/chromeless/issues/58) - package repository url [#64](https://github.com/graphcool/chromeless/pull/64) @Hazealign +- Spelling and minor bugfix when chromeless calls Version in CPD [#120](https://github.com/graphcool/chromeless/pull/120) @joelgriffith ## [1.0.1] - 2017-07-27 diff --git a/serverless/src/run.ts b/serverless/src/run.ts index 083bd1f9..e496b30a 100644 --- a/serverless/src/run.ts +++ b/serverless/src/run.ts @@ -19,6 +19,7 @@ export default async ( const chrome = new LocalChrome({ ...options, remote: false, + launchChrome: false, cdp: { closeTab: true }, })