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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ __tmp__
/x-pack/test/*/screenshots/failure
/x-pack/test/*/screenshots/session
/x-pack/test/*/screenshots/visual_regression_gallery.html
/x-pack/test/functional/apps/*/*/reporting/reports/failure

/html_docs
.eslintcache
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@
"fast-deep-equal": "^3.1.1",
"fflate": "^0.6.9",
"file-saver": "^1.3.8",
"file-type": "^10.9.0",
"font-awesome": "4.7.0",
"fp-ts": "^2.3.1",
"geojson-vt": "^3.2.1",
Expand Down Expand Up @@ -742,6 +741,7 @@
"@types/pbf": "3.0.2",
"@types/pdfmake": "^0.1.19",
"@types/pegjs": "^0.10.1",
"@types/pixelmatch": "^5.2.4",
"@types/pngjs": "^3.4.0",
"@types/prettier": "^2.3.2",
"@types/pretty-ms": "^5.0.0",
Expand Down Expand Up @@ -770,6 +770,7 @@
"@types/selenium-webdriver": "^4.1.0",
"@types/semver": "^7",
"@types/set-value": "^2.0.0",
"@types/sharp": "^0.30.4",
"@types/sinon": "^7.0.13",
"@types/source-map-support": "^0.5.3",
"@types/stats-lite": "^2.2.0",
Expand Down Expand Up @@ -906,7 +907,6 @@
"jest-snapshot": "^26.6.2",
"jest-specific-snapshot": "2.0.0",
"jest-styled-components": "^7.0.3",
"jimp": "^0.14.0",
"jsdom": "13.1.0",
"json-schema-typed": "^7.0.3",
"json5": "^1.0.1",
Expand All @@ -933,6 +933,7 @@
"openapi-types": "^10.0.0",
"pbf": "3.2.1",
"pirates": "^4.0.1",
"pixelmatch": "^5.3.0",
"playwright": "^1.17.1",
"postcss": "^7.0.32",
"postcss-loader": "^3.0.0",
Expand Down
Binary file modified test/functional/screenshots/baseline/area_chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/functional/screenshots/baseline/tsvb_dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 29 additions & 12 deletions test/functional/services/common/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { cloneDeepWith } from 'lodash';
import { Key, Origin, WebDriver } from 'selenium-webdriver';
import { modifyUrl } from '@kbn/std';

import Jimp from 'jimp';
import sharp from 'sharp';
import { WebElementWrapper } from '../lib/web_element_wrapper';
import { FtrProviderContext, FtrService } from '../../ftr_provider_context';
import { Browsers } from '../remote/browsers';
Expand Down Expand Up @@ -87,8 +87,9 @@ class BrowserService extends FtrService {
public async getScreenshotAsBitmap() {
const screenshot = await this.takeScreenshot();
const buffer = Buffer.from(screenshot, 'base64');
const session = (await Jimp.read(buffer)).clone();
return session.bitmap;

const session = sharp(buffer).png({ quality: 100, progressive: true }).clone();
return session;
}

/**
Expand All @@ -103,23 +104,36 @@ class BrowserService extends FtrService {
// We really want to set the Kibana app to a specific size without regard to the browser chrome (borders)
// But that means we first need to figure out the display scaling factor.
// NOTE: None of this is required when running Chrome headless because there's no scaling and no borders.
await this.setWindowSize(1200, 800);
const largeWidth = 1200;
const largeHeight = 800;
const smallWidth = 600;
const smallHeight = 400;

await this.setWindowSize(largeWidth, largeHeight);
const bitmap1 = await this.getScreenshotAsBitmap();
const bm1Data = await bitmap1.metadata();
this.log.debug(
`======browser======== actual initial screenshot size width=${bitmap1.width}, height=${bitmap1.height}`
`======browser======== actual initial screenshot size width=${bm1Data.width}, height=${bm1Data.height}`
);

// drasticly change the window size so we can calculate the scaling
await this.setWindowSize(600, 400);
await this.setWindowSize(smallWidth, smallHeight);
const bitmap2 = await this.getScreenshotAsBitmap();
const bm2Data = await bitmap2.metadata();
this.log.debug(
`======browser======== actual second screenshot size width= ${bitmap2.width}, height=${bitmap2.height}`
`======browser======== actual second screenshot size width= ${bm2Data.width}, height=${bm2Data.height}`
);

const xScaling = (bitmap1.width - bitmap2.width) / 600;
const yScaling = (bitmap1.height - bitmap2.height) / 400;
const xBorder = Math.round(600 - bitmap2.width / xScaling);
const yBorder = Math.round(400 - bitmap2.height / yScaling);
const bm1Width = bm1Data.width ?? smallWidth;
const bm1Height = bm1Data.height ?? smallHeight;
const bm2Width = bm2Data.width ?? smallWidth;
const bm2Height = bm2Data.height ?? smallHeight;

const xScaling = (bm1Width - bm2Width) / smallWidth;
const yScaling = (bm1Height - bm2Height) / smallHeight;
const xBorder = Math.round(600 - bm2Width / xScaling);
const yBorder = Math.round(400 - bm2Height / yScaling);

this.log.debug(
`======browser======== calculated values xBorder= ${xBorder}, yBorder=${yBorder}, xScaling=${xScaling}, yScaling=${yScaling}`
);
Expand All @@ -129,9 +143,12 @@ class BrowserService extends FtrService {
await this.setWindowSize(width + xBorder, height + yBorder);

const bitmap3 = await this.getScreenshotAsBitmap();
const bm3Data = await bitmap3.metadata();
const bm3Width = bm3Data.width ?? width;
const bm3Height = bm3Data.height ?? height;
// when there is display scaling this won't show the expected size. It will show expected size * scaling factor
this.log.debug(
`======browser======== final screenshot size width=${bitmap3.width}, height=${bitmap3.height}`
`======browser======== final screenshot size width=${bm3Width}, height=${bm3Height}`
);
}

Expand Down
1 change: 1 addition & 0 deletions test/functional/services/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type { Browser } from './browser';
export { BrowserProvider } from './browser';
export { FailureDebuggingProvider } from './failure_debugging';
export { FindProvider } from './find';
export { PngService } from './png';
export { ScreenshotsService } from './screenshots';
export { SnapshotsService } from './snapshots';
export { TestSubjects } from './test_subjects';
96 changes: 96 additions & 0 deletions test/functional/services/common/png.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { dirname } from 'path';
import { promisify } from 'util';
import { promises as fs, writeFile, readFileSync, mkdir } from 'fs';
import path from 'path';
import { comparePngs, PngDescriptor } from '../lib/compare_pngs';
import { FtrProviderContext, FtrService } from '../../ftr_provider_context';

const mkdirAsync = promisify(mkdir);
const writeFileAsync = promisify(writeFile);

export class PngService extends FtrService {
private readonly log = this.ctx.getService('log');

constructor(ctx: FtrProviderContext) {
super(ctx);
}

async comparePngs(
sessionInfo: string | PngDescriptor,
baselineInfo: string | PngDescriptor,
diffPath: string,
sessionDirectory: string
) {
return await comparePngs(sessionInfo, baselineInfo, diffPath, sessionDirectory, this.log);
}

async checkIfPngsMatch(actualpngPath: string, baselinepngPath: string, folder: string) {
this.log.debug(`checkIfpngsMatch: ${actualpngPath} vs ${baselinepngPath}`);
// Copy the pngs into the session directory, as that's where the generated pngs will automatically be
// stored.
const sessionDirectoryPath = path.resolve(folder, 'session');
const failureDirectoryPath = path.resolve(folder, 'failure');

await fs.mkdir(sessionDirectoryPath, { recursive: true });
await fs.mkdir(failureDirectoryPath, { recursive: true });

const actualpngFileName = path.basename(actualpngPath, '.png');
const baselinepngFileName = path.basename(baselinepngPath, '.png');

const baselineCopyPath = path.resolve(
sessionDirectoryPath,
`${baselinepngFileName}_baseline.png`
);
const actualCopyPath = path.resolve(sessionDirectoryPath, `${actualpngFileName}_actual.png`);

// Don't cause a test failure if the baseline snapshot doesn't exist - we don't have all OS's covered and we
// don't want to start causing failures for other devs working on OS's which are lacking snapshots. We have
// mac and linux covered which is better than nothing for now.
try {
this.log.debug(`writeFile: ${baselineCopyPath}`);
await fs.writeFile(baselineCopyPath, await fs.readFile(baselinepngPath));
} catch (error) {
throw new Error(`No baseline png found at ${baselinepngPath}`);
}
this.log.debug(`writeFile: ${actualCopyPath}`);
await fs.writeFile(actualCopyPath, await fs.readFile(actualpngPath));

let diffTotal = 0;

const diffPngPath = path.resolve(failureDirectoryPath, `${baselinepngFileName}-${1}.png`);
diffTotal += await this.comparePngs(
actualCopyPath,
baselineCopyPath,
diffPngPath,
sessionDirectoryPath
);

return diffTotal;
}

async compareAgainstBaseline(
sessionPath: string,
baselinePath: string,
folder: string,
updateBaselines: boolean
) {
this.log.debug(`compareAgainstBaseline: ${sessionPath} vs ${baselinePath}`);

if (updateBaselines) {
this.log.debug('Updating baseline PNG');
await mkdirAsync(dirname(baselinePath), { recursive: true });
await writeFileAsync(baselinePath, readFileSync(sessionPath));
return 0;
} else {
return await this.checkIfPngsMatch(sessionPath, baselinePath, folder);
}
}
}
2 changes: 2 additions & 0 deletions test/functional/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
BrowserProvider,
FailureDebuggingProvider,
FindProvider,
PngService,
ScreenshotsService,
SnapshotsService,
TestSubjects,
Expand Down Expand Up @@ -58,6 +59,7 @@ export const services = {
find: FindProvider,
testSubjects: TestSubjects,
docTable: DocTableService,
png: PngService,
screenshots: ScreenshotsService,
snapshots: SnapshotsService,
failureDebugging: FailureDebuggingProvider,
Expand Down
Loading