Skip to content
Merged
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 @@ -37,6 +37,7 @@ types.eslint.config.js
/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
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,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 @@ -591,6 +590,7 @@
"@types/parse-link-header": "^1.0.0",
"@types/pdfmake": "^0.1.15",
"@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 @@ -618,6 +618,7 @@
"@types/selenium-webdriver": "^4.0.19",
"@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 @@ -756,8 +757,8 @@
"jest-specific-snapshot": "2.0.0",
"jest-styled-components": "^7.0.3",
"jest-when": "^3.2.1",
"jimp": "^0.14.0",
"jsdom": "13.1.0",
"json-schema-typed": "^8.0.1",
"json5": "^1.0.1",
"jsondiffpatch": "0.4.1",
"license-checker": "^16.0.0",
Expand Down Expand Up @@ -785,7 +786,7 @@
"parse-link-header": "^1.0.1",
"pbf": "3.2.1",
"pirates": "^4.0.1",
"pixelmatch": "^5.1.0",
"pixelmatch": "^5.3.0",
"playwright": "^1.17.1",
"postcss": "^7.0.32",
"postcss-loader": "^3.0.0",
Expand Down
149 changes: 118 additions & 31 deletions packages/kbn-pm/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33099,7 +33099,7 @@ const JSONError = errorEx('JSONError', {
codeFrame: errorEx.append('\n\n%s\n')
});

module.exports = (string, reviver, filename) => {
const parseJson = (string, reviver, filename) => {
if (typeof reviver === 'string') {
filename = reviver;
reviver = null;
Expand All @@ -33114,7 +33114,7 @@ module.exports = (string, reviver, filename) => {
}
} catch (error) {
error.message = error.message.replace(/\n/g, '');
const indexMatch = error.message.match(/in JSON at position (\d+) while parsing near/);
const indexMatch = error.message.match(/in JSON at position (\d+) while parsing/);

const jsonError = new JSONError(error);
if (filename) {
Expand All @@ -33139,6 +33139,10 @@ module.exports = (string, reviver, filename) => {
}
};

parseJson.JSONError = JSONError;

module.exports = parseJson;


/***/ }),
/* 367 */
Expand Down Expand Up @@ -33304,43 +33308,126 @@ module.exports = function isArrayish(obj) {
"use strict";


module.exports = parseJson
function parseJson (txt, reviver, context) {
const hexify = char => {
const h = char.charCodeAt(0).toString(16).toUpperCase()
return '0x' + (h.length % 2 ? '0' : '') + h
}

const parseError = (e, txt, context) => {
if (!txt) {
return {
message: e.message + ' while parsing empty string',
position: 0,
}
}
const badToken = e.message.match(/^Unexpected token (.) .*position\s+(\d+)/i)
const errIdx = badToken ? +badToken[2]
: e.message.match(/^Unexpected end of JSON.*/i) ? txt.length - 1
: null

const msg = badToken ? e.message.replace(/^Unexpected token ./, `Unexpected token ${
JSON.stringify(badToken[1])
} (${hexify(badToken[1])})`)
: e.message

if (errIdx !== null && errIdx !== undefined) {
const start = errIdx <= context ? 0
: errIdx - context

const end = errIdx + context >= txt.length ? txt.length
: errIdx + context

const slice = (start === 0 ? '' : '...') +
txt.slice(start, end) +
(end === txt.length ? '' : '...')

const near = txt === slice ? '' : 'near '

return {
message: msg + ` while parsing ${near}${JSON.stringify(slice)}`,
position: errIdx,
}
} else {
return {
message: msg + ` while parsing '${txt.slice(0, context * 2)}'`,
position: 0,
}
}
}

class JSONParseError extends SyntaxError {
constructor (er, txt, context, caller) {
context = context || 20
const metadata = parseError(er, txt, context)
super(metadata.message)
Object.assign(this, metadata)
this.code = 'EJSONPARSE'
this.systemError = er
Error.captureStackTrace(this, caller || this.constructor)
}
get name () { return this.constructor.name }
set name (n) {}
get [Symbol.toStringTag] () { return this.constructor.name }
}

const kIndent = Symbol.for('indent')
const kNewline = Symbol.for('newline')
// only respect indentation if we got a line break, otherwise squash it
// things other than objects and arrays aren't indented, so ignore those
// Important: in both of these regexps, the $1 capture group is the newline
// or undefined, and the $2 capture group is the indent, or undefined.
const formatRE = /^\s*[{\[]((?:\r?\n)+)([\s\t]*)/
const emptyRE = /^(?:\{\}|\[\])((?:\r?\n)+)?$/

const parseJson = (txt, reviver, context) => {
const parseText = stripBOM(txt)
context = context || 20
try {
return JSON.parse(txt, reviver)
// get the indentation so that we can save it back nicely
// if the file starts with {" then we have an indent of '', ie, none
// otherwise, pick the indentation of the next line after the first \n
// If the pattern doesn't match, then it means no indentation.
// JSON.stringify ignores symbols, so this is reasonably safe.
// if the string is '{}' or '[]', then use the default 2-space indent.
const [, newline = '\n', indent = ' '] = parseText.match(emptyRE) ||
parseText.match(formatRE) ||
[, '', '']

const result = JSON.parse(parseText, reviver)
if (result && typeof result === 'object') {
result[kNewline] = newline
result[kIndent] = indent
}
return result
} catch (e) {
if (typeof txt !== 'string') {
if (typeof txt !== 'string' && !Buffer.isBuffer(txt)) {
const isEmptyArray = Array.isArray(txt) && txt.length === 0
const errorMessage = 'Cannot parse ' +
(isEmptyArray ? 'an empty array' : String(txt))
throw new TypeError(errorMessage)
}
const syntaxErr = e.message.match(/^Unexpected token.*position\s+(\d+)/i)
const errIdx = syntaxErr
? +syntaxErr[1]
: e.message.match(/^Unexpected end of JSON.*/i)
? txt.length - 1
: null
if (errIdx != null) {
const start = errIdx <= context
? 0
: errIdx - context
const end = errIdx + context >= txt.length
? txt.length
: errIdx + context
e.message += ` while parsing near '${
start === 0 ? '' : '...'
}${txt.slice(start, end)}${
end === txt.length ? '' : '...'
}'`
} else {
e.message += ` while parsing '${txt.slice(0, context * 2)}'`
throw Object.assign(new TypeError(
`Cannot parse ${isEmptyArray ? 'an empty array' : String(txt)}`
), {
code: 'EJSONPARSE',
systemError: e,
})
}
throw e

throw new JSONParseError(e, parseText, context, parseJson)
}
}

// Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
// because the buffer-to-string conversion in `fs.readFileSync()`
// translates it to FEFF, the UTF-16 BOM.
const stripBOM = txt => String(txt).replace(/^\uFEFF/, '')

module.exports = parseJson
parseJson.JSONParseError = JSONParseError

parseJson.noExceptions = (txt, reviver) => {
try {
return JSON.parse(stripBOM(txt), reviver)
} catch (e) {}
}


/***/ }),
/* 370 */
Expand Down
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 @@ -13,7 +13,7 @@ import { Key, Origin, WebDriver } from 'selenium-webdriver';
import { LegacyActionSequence } from 'selenium-webdriver/lib/actions';
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 @@ -89,8 +89,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 @@ -105,23 +106,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 @@ -131,9 +145,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';
Loading