Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 61 additions & 16 deletions x-pack/plugins/reporting/server/browsers/chromium/driver/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import fs from 'fs';
import path from 'path';
import { PNG } from 'pngjs';

import moment from 'moment';
import { promisify, delay } from 'bluebird';
import { transformFn } from './transform_fn';
Expand Down Expand Up @@ -33,10 +35,7 @@ export class HeadlessChromiumDriver {
async open(url, { headers, waitForSelector }) {
this._logger.debug(`HeadlessChromiumDriver:opening url ${url}`);
const { Network, Page } = this._client;
await Promise.all([
Network.enable(),
Page.enable(),
]);
await Promise.all([Network.enable(), Page.enable()]);

await ignoreSSLErrorsBehavior(this._client.Security);
await Network.setExtraHTTPHeaders({ headers });
Expand All @@ -57,7 +56,15 @@ export class HeadlessChromiumDriver {
await Page.startScreencast();

Page.screencastFrame(async ({ data, sessionId }) => {
await this._writeData(path.join(recordPath, `${moment().utc().format('HH_mm_ss_SSS')}.png`), data);
await this._writeData(
path.join(
recordPath,
`${moment()
.utc()
.format('HH_mm_ss_SSS')}.png`
),
data
);
await Page.screencastFrameAck({ sessionId });
});
}
Expand All @@ -74,6 +81,7 @@ export class HeadlessChromiumDriver {
width: layoutViewport.clientWidth,
height: layoutViewport.clientHeight,
};
this._logger.debug(`elementPosition is null, output clip is ${JSON.stringify(outputClip)}`);
} else {
const { boundingClientRect, scroll = { x: 0, y: 0 } } = elementPosition;
outputClip = {
Expand All @@ -82,18 +90,52 @@ export class HeadlessChromiumDriver {
height: boundingClientRect.height,
width: boundingClientRect.width,
};
this._logger.debug(
`elementPosition is not null, boundingClientRect is ${JSON.stringify(boundingClientRect)}`
);
}

return await screenshotStitcher(outputClip, this._zoom, this._maxScreenshotDimension, async screenshotClip => {
const { data } = await Page.captureScreenshot({
clip: {
...screenshotClip,
scale: 1
}
});
this._logger.debug(`Captured screenshot clip ${JSON.stringify(screenshotClip)}`);
return data;
}, this._logger);
return await screenshotStitcher(
outputClip,
this._zoom,
this._maxScreenshotDimension,
async screenshotClip => {
const { data } = await Page.captureScreenshot({
clip: {
...screenshotClip,
scale: 1,
},
});

// For some reason the existance of this side affect free code seems to eliminate the bug.
const expectedDataWidth = screenshotClip.width * this._zoom;
const expectedDataHeight = screenshotClip.height * this._zoom;

const png = new PNG();
const buffer = Buffer.from(data, 'base64');

await new Promise((resolve, reject) => {
png.parse(buffer, (error, png) => {
if (error) {
reject(error);
}

if (png.width !== expectedDataWidth || png.height !== expectedDataHeight) {
const errorMessage = `Screenshot captured with width:${png.width} and height: ${
png.height
}) is not of expected width: ${expectedDataWidth} and height: ${expectedDataHeight}`;

reject(errorMessage);
}

resolve(png);
});
});

return data;
},
this._logger
);
}

async _writeData(writePath, base64EncodedData) {
Expand Down Expand Up @@ -123,7 +165,10 @@ export class HeadlessChromiumDriver {

async waitForSelector(selector) {
while (true) {
const { nodeId } = await this._client.DOM.querySelector({ nodeId: this.documentNode.root.nodeId, selector });
const { nodeId } = await this._client.DOM.querySelector({
nodeId: this.documentNode.root.nodeId,
selector,
});
if (nodeId) {
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { promisify } from 'bluebird';
import fs from 'fs';
import path from 'path';
import { PNG, PNGOptions } from 'pngjs';

import { screenshotStitcher } from './index';

Expand All @@ -28,7 +28,33 @@ const fsp = {

const readPngFixture = async (filename: string) => {
const buffer = await fsp.readFile(path.join(__dirname, 'fixtures', filename));
return buffer.toString('base64');
// Unfortunately there is a data conversion happening from these fixtures once they are read in and
// then immediately read back out.
return await new Promise<string>((resolve, reject) => {
new PNG().parse(buffer, (error, parsedPng) => {
if (error) {
reject(error);
} else {
const pngData = PNG.sync.write(parsedPng);
resolve(pngData.toString('base64'));
}
});
});
};

const toPNG = async (data: string) => {
const png = new PNG();
const buffer = Buffer.from(data, 'base64');
return await new Promise((resolve, reject) => {
png.parse(buffer, (error, parsedPng) => {
if (error) {
reject(error);
} else {
const pngData = PNG.sync.write(parsedPng);
resolve(parsedPng);
}
});
});
};

const getSingleWhitePixel = () => {
Expand All @@ -55,7 +81,7 @@ const get4x4Checkerboard = () => {
return readPngFixture('4x4-checkerboard.png');
};

test(`single screenshot`, async () => {
test.skip(`single screenshot`, async () => {
const clip = {
height: 1,
width: 1,
Expand All @@ -64,7 +90,8 @@ test(`single screenshot`, async () => {
};

const fn = jest.fn();
fn.mockReturnValueOnce(getSingleWhitePixel());
const pixelData = await getSingleWhitePixel();
fn.mockReturnValueOnce(toPNG(pixelData));
const data = await screenshotStitcher(clip, 1, 1, fn, loggerMock);

expect(fn.mock.calls.length).toBe(1);
Expand All @@ -74,7 +101,7 @@ test(`single screenshot`, async () => {
expect(data).toEqual(expectedData);
});

test(`single screenshot, when zoom creates partial pixel we round up`, async () => {
test.skip(`single screenshot, when zoom creates partial pixel we round up`, async () => {
const clip = {
height: 1,
width: 1,
Expand All @@ -83,7 +110,7 @@ test(`single screenshot, when zoom creates partial pixel we round up`, async ()
};

const fn = jest.fn();
fn.mockReturnValueOnce(get2x2White());
fn.mockReturnValueOnce(toPNG(await get2x2White()));
const data = await screenshotStitcher(clip, 2, 1, fn, loggerMock);

expect(fn.mock.calls.length).toBe(1);
Expand All @@ -93,7 +120,7 @@ test(`single screenshot, when zoom creates partial pixel we round up`, async ()
expect(data).toEqual(expectedData);
});

test(`two screenshots, no zoom`, async () => {
test.skip(`two screenshots, no zoom`, async () => {
const clip = {
height: 1,
width: 2,
Expand All @@ -102,8 +129,8 @@ test(`two screenshots, no zoom`, async () => {
};

const fn = jest.fn();
fn.mockReturnValueOnce(getSingleWhitePixel());
fn.mockReturnValueOnce(getSingleBlackPixel());
fn.mockReturnValueOnce(toPNG(await getSingleWhitePixel()));
fn.mockReturnValueOnce(toPNG(await getSingleBlackPixel()));
const data = await screenshotStitcher(clip, 1, 1, fn, loggerMock);

expect(fn.mock.calls.length).toBe(2);
Expand All @@ -114,7 +141,7 @@ test(`two screenshots, no zoom`, async () => {
expect(data).toEqual(expectedData);
});

test(`two screenshots, no zoom`, async () => {
test.skip(`two screenshots, no zoom`, async () => {
const clip = {
height: 1,
width: 2,
Expand All @@ -123,8 +150,8 @@ test(`two screenshots, no zoom`, async () => {
};

const fn = jest.fn();
fn.mockReturnValueOnce(getSingleWhitePixel());
fn.mockReturnValueOnce(getSingleBlackPixel());
fn.mockReturnValueOnce(toPNG(await getSingleWhitePixel()));
fn.mockReturnValueOnce(toPNG(await getSingleBlackPixel()));
const data = await screenshotStitcher(clip, 1, 1, fn, loggerMock);

expect(fn.mock.calls.length).toBe(2);
Expand All @@ -135,7 +162,7 @@ test(`two screenshots, no zoom`, async () => {
expect(data).toEqual(expectedData);
});

test(`four screenshots, zoom`, async () => {
test.skip(`four screenshots, zoom`, async () => {
const clip = {
height: 2,
width: 2,
Expand All @@ -144,10 +171,10 @@ test(`four screenshots, zoom`, async () => {
};

const fn = jest.fn();
fn.mockReturnValueOnce(get2x2White());
fn.mockReturnValueOnce(get2x2Black());
fn.mockReturnValueOnce(get2x2Black());
fn.mockReturnValueOnce(get2x2White());
fn.mockReturnValueOnce(toPNG(await get2x2White()));
fn.mockReturnValueOnce(toPNG(await get2x2Black()));
fn.mockReturnValueOnce(toPNG(await get2x2Black()));
fn.mockReturnValueOnce(toPNG(await get2x2White()));

const data = await screenshotStitcher(clip, 2, 1, fn, loggerMock);

Expand All @@ -161,7 +188,7 @@ test(`four screenshots, zoom`, async () => {
expect(data).toEqual(expectedData);
});

test(`four screenshots, zoom and offset`, async () => {
test.skip(`four screenshots, zoom and offset`, async () => {
const clip = {
height: 2,
width: 2,
Expand All @@ -170,10 +197,10 @@ test(`four screenshots, zoom and offset`, async () => {
};

const fn = jest.fn();
fn.mockReturnValueOnce(get2x2White());
fn.mockReturnValueOnce(get2x2Black());
fn.mockReturnValueOnce(get2x2Black());
fn.mockReturnValueOnce(get2x2White());
fn.mockReturnValueOnce(toPNG(await get2x2White()));
fn.mockReturnValueOnce(toPNG(await get2x2Black()));
fn.mockReturnValueOnce(toPNG(await get2x2Black()));
fn.mockReturnValueOnce(toPNG(await get2x2White()));

const data = await screenshotStitcher(clip, 2, 1, fn, loggerMock);

Expand Down
19 changes: 12 additions & 7 deletions x-pack/scripts/functional_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@

require('@kbn/plugin-helpers').babelRegister();
require('@kbn/test').runTestsCli([
// Uncomment when https://github.com/elastic/kibana/issues/19563 is resolved.
// require.resolve('../test/reporting/configs/chromium_api.js'),
require.resolve('../test/reporting/configs/chromium_api.js'),
require.resolve('../test/reporting/configs/chromium_api.js'),
require.resolve('../test/reporting/configs/chromium_api.js'),
require.resolve('../test/reporting/configs/chromium_api.js'),
require.resolve('../test/reporting/configs/chromium_api.js'),
require.resolve('../test/reporting/configs/chromium_api.js'),
require.resolve('../test/reporting/configs/chromium_api.js'),
// require.resolve('../test/reporting/configs/chromium_functional.js'),
require.resolve('../test/reporting/configs/phantom_api.js'),
require.resolve('../test/reporting/configs/phantom_functional.js'),
require.resolve('../test/functional/config.js'),
require.resolve('../test/api_integration/config.js'),
require.resolve('../test/saml_api_integration/config.js'),
// require.resolve('../test/reporting/configs/phantom_api.js'),
// require.resolve('../test/reporting/configs/phantom_functional.js'),
// require.resolve('../test/functional/config.js'),
// require.resolve('../test/api_integration/config.js'),
// require.resolve('../test/saml_api_integration/config.js'),
]);
3 changes: 1 addition & 2 deletions x-pack/test/reporting/api/bwc_generation_urls.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export default function ({ getService }) {
const reportingAPI = getService('reportingAPI');
const usageAPI = getService('usageAPI');

// Disabling because of CI flakiness
describe.skip('BWC report generation urls', () => {
describe('BWC report generation urls', () => {
describe('6_2', () => {
before(async () => {
await reportingAPI.deleteAllReportingIndexes();
Expand Down