Typings for chromium driver (#22688)

* Typings for chromium driver

* buffer => base64

* remove unused param. consolidate imports
This commit is contained in:
Stacey Gammon 2018-09-07 16:01:39 -04:00 committed by GitHub
parent 54ab5a7374
commit c9b1d7ad7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 142 additions and 96 deletions

View file

@ -233,6 +233,7 @@
"@types/minimatch": "^2.0.29",
"@types/node": "^8.10.20",
"@types/prop-types": "^15.5.3",
"@types/puppeteer": "^1.6.2",
"@types/react": "^16.3.14",
"@types/react-dom": "^16.0.5",
"@types/react-redux": "^6.0.6",

View file

@ -3,8 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Size } from '../../../../../types';
import { ViewZoomWidthHeight } from './types';
import { Size, ViewZoomWidthHeight } from '../../../../../types';
export interface PageSizeParams {
pageMarginTop: number;

View file

@ -7,6 +7,7 @@ import path from 'path';
import { Size } from '../../../../../types';
import { Layout, PageSizeParams } from './layout';
// We use a zoom of two to bump up the resolution of the screenshot a bit.
const ZOOM: number = 2;
export class PreserveLayout extends Layout {

View file

@ -4,19 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import path from 'path';
import { KbnServer, Size } from '../../../../../types';
import { EvaluateOptions, KbnServer, Size } from '../../../../../types';
import { Layout } from './layout';
import { CaptureConfig } from './types';
type EvalArgs = any[];
interface EvaluateOptions {
// 'fn' is a function in string form to avoid tslint from auto formatting it into a version not
// underfood by transform_fn safeWrap.
fn: ((...evalArgs: EvalArgs) => any);
args: EvalArgs; // Arguments to be passed into the function defined by fn.
}
interface BrowserClient {
evaluate: (evaluateOptions: EvaluateOptions) => void;
}

View file

@ -9,9 +9,3 @@ export interface CaptureConfig {
zoom: number;
viewport: Size;
}
export interface ViewZoomWidthHeight {
zoom: number;
width: number;
height: number;
}

View file

@ -0,0 +1,92 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import * as Chrome from 'puppeteer';
import {
ElementPosition,
EvalArgs,
EvalFn,
EvaluateOptions,
Logger,
ViewZoomWidthHeight,
} from '../../../../types';
export interface ChromiumDriverOptions {
logger: Logger;
}
const WAIT_FOR_DELAY_MS: number = 100;
export class HeadlessChromiumDriver {
private readonly page: Chrome.Page;
private readonly logger: Logger;
constructor(page: Chrome.Page, { logger }: ChromiumDriverOptions) {
this.page = page;
this.logger = logger;
}
public async open(
url: string,
{ headers, waitForSelector }: { headers: Record<string, string>; waitForSelector: string }
) {
this.logger.debug(`HeadlessChromiumDriver:opening url ${url}`);
await this.page.setExtraHTTPHeaders(headers);
await this.page.goto(url, { waitUntil: 'networkidle0' });
await this.page.waitFor(waitForSelector);
}
public async screenshot(elementPosition: ElementPosition) {
let clip;
if (elementPosition) {
const { boundingClientRect, scroll = { x: 0, y: 0 } } = elementPosition;
clip = {
x: boundingClientRect.left + scroll.x,
y: boundingClientRect.top + scroll.y,
height: boundingClientRect.height,
width: boundingClientRect.width,
};
}
const screenshot = await this.page.screenshot({
clip,
});
return screenshot.toString('base64');
}
public async evaluate({ fn, args = [] }: EvaluateOptions) {
const result = await this.page.evaluate(fn, ...args);
return result;
}
public waitForSelector(selector: string) {
return this.page.waitFor(selector);
}
public async waitFor<T>({ fn, args, toEqual }: { fn: EvalFn<T>; args: EvalArgs; toEqual: T }) {
while (true) {
const result = await this.evaluate({ fn, args });
if (result === toEqual) {
return;
}
await new Promise(r => setTimeout(r, WAIT_FOR_DELAY_MS));
}
}
public async setViewport({ width, height, zoom }: ViewZoomWidthHeight) {
this.logger.debug(`Setting viewport to width: ${width}, height: ${height}, zoom: ${zoom}`);
await this.page.setViewport({
width: Math.floor(width / zoom),
height: Math.floor(height / zoom),
deviceScaleFactor: zoom,
isMobile: false,
});
}
}

View file

@ -1,78 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export class HeadlessChromiumDriver {
constructor(page, { maxScreenshotDimension, logger }) {
this._page = page;
this._maxScreenshotDimension = maxScreenshotDimension;
this._waitForDelayMs = 100;
this._zoom = 1;
this._logger = logger;
}
async open(url, { headers, waitForSelector }) {
this._logger.debug(`HeadlessChromiumDriver:opening url ${url}`);
await this._page.setExtraHTTPHeaders(headers);
await this._page.goto(url, { waitUntil: 'networkidle0' });
this.documentNode = await this._page.evaluateHandle(() => document);
await this._page.waitFor(waitForSelector);
}
async screenshot(elementPosition = null) {
let clip;
if (elementPosition) {
const { boundingClientRect, scroll = { x: 0, y: 0 } } = elementPosition;
clip = {
x: boundingClientRect.left + scroll.x,
y: boundingClientRect.top + scroll.y,
height: boundingClientRect.height,
width: boundingClientRect.width,
};
}
const screenshot = await this._page.screenshot({
encoding: 'base64',
clip,
});
return screenshot;
}
async evaluate({ fn, args = [] }) {
const result = await this._page.evaluate(fn, ...args);
return result;
}
waitForSelector(selector) {
return this._page.waitFor(selector);
}
async waitFor({ fn, args, toEqual }) {
while (true) {
const result = await this.evaluate({ fn, args });
if (result === toEqual) {
return;
}
await new Promise(r => setTimeout(r, this._waitForDelayMs));
}
}
async setViewport({ width, height, zoom }) {
this._logger.debug(`Setting viewport to width: ${width}, height: ${height}, zoom: ${zoom}`);
await this._page.setViewport({
width: Math.floor(width / zoom),
height: Math.floor(height / zoom),
deviceScaleFactor: zoom,
isMobile: false,
});
this._zoom = zoom;
}
}

View file

@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export { HeadlessChromiumDriver } from './chromium_driver';

View file

@ -21,3 +21,35 @@ export interface Logger {
error: (message: string) => void;
warning: (message: string) => void;
}
export interface ViewZoomWidthHeight {
zoom: number;
width: number;
height: number;
}
export type EvalArgs = any[];
export type EvalFn<T> = ((...evalArgs: EvalArgs) => T);
export interface EvaluateOptions {
fn: EvalFn<any>;
args: EvalArgs; // Arguments to be passed into the function defined by fn.
}
export interface ElementPosition {
boundingClientRect: {
// modern browsers support x/y, but older ones don't
top: number;
left: number;
width: number;
height: number;
};
scroll: {
x: number;
y: number;
};
}
export interface HeadlessElementInfo {
position: ElementPosition;
}

View file

@ -488,6 +488,13 @@
version "15.5.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.3.tgz#bef071852dca2a2dbb65fecdb7bfb30cedae2de2"
"@types/puppeteer@^1.6.2":
version "1.6.2"
resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-1.6.2.tgz#9b4ba40a67abad3c729a021ffd259d929d00c5e0"
dependencies:
"@types/events" "*"
"@types/node" "*"
"@types/react-dom@^16.0.5":
version "16.0.5"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.5.tgz#a757457662e3819409229e8f86795ff37b371f96"