Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reporting] Make usable default element positions #63191

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export abstract class Layout {

public abstract getPdfPageSize(pageSizeParams: PageSizeParams): string | Size;

public abstract getViewport(itemsCount: number): ViewZoomWidthHeight;
public abstract getViewport(itemsCount: number): ViewZoomWidthHeight | null;

public abstract getBrowserZoom(): number;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { LevelLogger } from '../../../../server/lib';
import { createMockBrowserDriverFactory, createMockLayoutInstance } from '../../../../test_helpers';
import { ConditionalHeaders, HeadlessChromiumDriver } from '../../../../types';
import { CaptureConfig } from '../../../../server/types';
import * as contexts from './constants';
import { screenshotsObservableFactory } from './observable';
import { ElementsPositionAndAttribute } from './types';

Expand Down Expand Up @@ -57,10 +58,30 @@ describe('Screenshot Observable Pipeline', () => {
expect(result).toMatchInlineSnapshot(`
Array [
Object {
"elementsPositionAndAttributes": Array [
Object {
"attributes": Object {
"description": "Default ",
"title": "Default Mock Title",
},
"position": Object {
"boundingClientRect": Object {
"height": 600,
"left": 0,
"top": 0,
"width": 800,
},
"scroll": Object {
"x": 0,
"y": 0,
},
},
},
],
"error": undefined,
"screenshots": Array [
Object {
"base64EncodedData": "allyourBase64 of boundingClientRect,scroll",
"base64EncodedData": "allyourBase64",
"description": "Default ",
"title": "Default Mock Title",
},
Expand Down Expand Up @@ -95,6 +116,26 @@ describe('Screenshot Observable Pipeline', () => {
expect(result).toMatchInlineSnapshot(`
Array [
Object {
"elementsPositionAndAttributes": Array [
Object {
"attributes": Object {
"description": "Default ",
"title": "Default Mock Title",
},
"position": Object {
"boundingClientRect": Object {
"height": 600,
"left": 0,
"top": 0,
"width": 800,
},
"scroll": Object {
"x": 0,
"y": 0,
},
},
},
],
"error": undefined,
"screenshots": Array [
Object {
Expand All @@ -106,6 +147,26 @@ describe('Screenshot Observable Pipeline', () => {
"timeRange": "Default GetTimeRange Result",
},
Object {
"elementsPositionAndAttributes": Array [
Object {
"attributes": Object {
"description": "Default ",
"title": "Default Mock Title",
},
"position": Object {
"boundingClientRect": Object {
"height": 600,
"left": 0,
"top": 0,
"width": 800,
},
"scroll": Object {
"x": 0,
"y": 0,
},
},
},
],
"error": undefined,
"screenshots": Array [
Object {
Expand Down Expand Up @@ -150,21 +211,55 @@ describe('Screenshot Observable Pipeline', () => {
await expect(getScreenshot()).resolves.toMatchInlineSnapshot(`
Array [
Object {
"elementsPositionAndAttributes": Array [
Object {
"attributes": Object {},
"position": Object {
"boundingClientRect": Object {
"height": 200,
"left": 0,
"top": 0,
"width": 200,
},
"scroll": Object {
"x": 0,
"y": 0,
},
},
},
],
"error": [Error: An error occurred when trying to read the page for visualization panel info. You may need to increase 'xpack.reporting.capture.timeouts.waitForElements'. Error: Mock error!],
"screenshots": Array [
Object {
"base64EncodedData": "allyourBase64 of boundingClientRect,scroll",
"base64EncodedData": "allyourBase64",
"description": undefined,
"title": undefined,
},
],
"timeRange": null,
},
Object {
"elementsPositionAndAttributes": Array [
Object {
"attributes": Object {},
"position": Object {
"boundingClientRect": Object {
"height": 200,
"left": 0,
"top": 0,
"width": 200,
},
"scroll": Object {
"x": 0,
"y": 0,
},
},
},
],
"error": [Error: An error occurred when trying to read the page for visualization panel info. You may need to increase 'xpack.reporting.capture.timeouts.waitForElements'. Error: Mock error!],
"screenshots": Array [
Object {
"base64EncodedData": "allyourBase64 of boundingClientRect,scroll",
"base64EncodedData": "allyourBase64",
"description": undefined,
"title": undefined,
},
Expand Down Expand Up @@ -208,10 +303,27 @@ describe('Screenshot Observable Pipeline', () => {
await expect(getScreenshot()).resolves.toMatchInlineSnapshot(`
Array [
Object {
"elementsPositionAndAttributes": Array [
Object {
"attributes": Object {},
"position": Object {
"boundingClientRect": Object {
"height": 200,
"left": 0,
"top": 0,
"width": 200,
},
"scroll": Object {
"x": 0,
"y": 0,
},
},
},
],
"error": "Instant timeout has fired!",
"screenshots": Array [
Object {
"base64EncodedData": "allyourBase64 of boundingClientRect,scroll",
"base64EncodedData": "allyourBase64",
"description": undefined,
"title": undefined,
},
Expand All @@ -221,5 +333,69 @@ describe('Screenshot Observable Pipeline', () => {
]
`);
});

it(`uses defaults for element positions and size when Kibana page is not ready`, async () => {
// mocks
const mockBrowserEvaluate = jest.fn();
mockBrowserEvaluate.mockImplementation(() => {
const lastCallIndex = mockBrowserEvaluate.mock.calls.length - 1;
const { context: mockCall } = mockBrowserEvaluate.mock.calls[lastCallIndex][1];

if (mockCall === contexts.CONTEXT_ELEMENTATTRIBUTES) {
return Promise.resolve(null);
} else {
return Promise.resolve();
}
});
mockBrowserDriverFactory = await createMockBrowserDriverFactory(logger, {
evaluate: mockBrowserEvaluate,
});
mockLayout.getViewport = () => null;

// test
const getScreenshots$ = screenshotsObservableFactory(mockConfig, mockBrowserDriverFactory);
const getScreenshot = async () => {
return await getScreenshots$({
logger,
urls: ['/welcome/home/start/index.php3?page=./home.php3'],
conditionalHeaders: {} as ConditionalHeaders,
layout: mockLayout,
browserTimezone: 'UTC',
}).toPromise();
};

await expect(getScreenshot()).resolves.toMatchInlineSnapshot(`
Array [
Object {
"elementsPositionAndAttributes": Array [
Object {
"attributes": Object {},
"position": Object {
"boundingClientRect": Object {
"height": 1200,
"left": 0,
"top": 0,
"width": 1800,
},
"scroll": Object {
"x": 0,
"y": 0,
},
},
},
],
"error": undefined,
"screenshots": Array [
Object {
"base64EncodedData": "allyourBase64",
"description": undefined,
"title": undefined,
},
],
"timeRange": undefined,
},
]
`);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import { ScreenSetupData, ScreenshotObservableOpts, ScreenshotResults } from './
import { waitForRenderComplete } from './wait_for_render';
import { waitForVisualizations } from './wait_for_visualizations';

const DEFAULT_SCREENSHOT_CLIP_HEIGHT = 1200;
const DEFAULT_SCREENSHOT_CLIP_WIDTH = 1800;

export function screenshotsObservableFactory(
captureConfig: CaptureConfig,
browserDriverFactory: HeadlessChromiumDriverFactory
Expand All @@ -42,7 +45,7 @@ export function screenshotsObservableFactory(
mergeMap(() => openUrl(captureConfig, driver, url, conditionalHeaders, logger)),
mergeMap(() => getNumberOfItems(captureConfig, driver, layout, logger)),
mergeMap(async itemsCount => {
const viewport = layout.getViewport(itemsCount);
const viewport = layout.getViewport(itemsCount) || getDefaultViewPort();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heads up @poffdeluxe, these changes might conflict in the branch you're working on regarding re-using the page object for multiple urls

await Promise.all([
driver.setViewport(viewport, logger),
waitForVisualizations(captureConfig, driver, itemsCount, layout, logger),
Expand Down Expand Up @@ -83,7 +86,12 @@ export function screenshotsObservableFactory(
: getDefaultElementPosition(layout.getViewport(1));
const screenshots = await getScreenshots(driver, elements, logger);
const { timeRange, error: setupError } = data;
return { timeRange, screenshots, error: setupError };
return {
timeRange,
screenshots,
error: setupError,
elementsPositionAndAttributes: elements,
};
}
)
);
Expand All @@ -97,17 +105,30 @@ export function screenshotsObservableFactory(
};
}

/*
* If Kibana is showing a non-HTML error message, the viewport might not be
* provided by the browser.
*/
const getDefaultViewPort = () => ({
height: DEFAULT_SCREENSHOT_CLIP_HEIGHT,
width: DEFAULT_SCREENSHOT_CLIP_WIDTH,
zoom: 1,
});
/*
* If an error happens setting up the page, we don't know if there actually
* are any visualizations showing. These defaults should help capture the page
* enough for the user to see the error themselves
*/
const getDefaultElementPosition = ({ height, width }: { height: number; width: number }) => [
{
const getDefaultElementPosition = (dimensions: { height?: number; width?: number } | null) => {
const height = dimensions?.height || DEFAULT_SCREENSHOT_CLIP_HEIGHT;
const width = dimensions?.width || DEFAULT_SCREENSHOT_CLIP_WIDTH;

const defaultObject = {
position: {
boundingClientRect: { top: 0, left: 0, height, width },
scroll: { x: 0, y: 0 },
},
attributes: {},
},
];
};
return [defaultObject];
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ export interface ScreenshotResults {
timeRange: TimeRange | null;
screenshots: Screenshot[];
error?: Error;
elementsPositionAndAttributes?: ElementsPositionAndAttribute[]; // NOTE: for testing
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,19 +190,14 @@ export class HeadlessChromiumDriver {
}

public async screenshot(elementPosition: ElementPosition): Promise<string> {
let clip;
if (elementPosition) {
const { boundingClientRect, scroll = { x: 0, y: 0 } } = elementPosition;
clip = {
const { boundingClientRect, scroll } = elementPosition;
const screenshot = await this.page.screenshot({
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');
Expand Down
Loading
Loading