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

[7.16] [Reporting] Baseline capture tests (#113910) #115934

Merged
merged 1 commit into from
Oct 21, 2021
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,7 @@
"ora": "^4.0.4",
"parse-link-header": "^1.0.1",
"pbf": "3.2.1",
"pdf-to-img": "^1.1.1",
"pirates": "^4.0.1",
"pixelmatch": "^5.1.0",
"postcss": "^7.0.32",
Expand Down
52 changes: 43 additions & 9 deletions test/functional/services/lib/compare_pngs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,56 @@ import { parse, join } from 'path';
import Jimp from 'jimp';
import { ToolingLog } from '@kbn/dev-utils';

interface PngDescriptor {
path: string;

/**
* If a buffer is provided this will avoid the extra step of reading from disk
*/
buffer?: Buffer;
}

const toDescriptor = (imageInfo: string | PngDescriptor): PngDescriptor => {
if (typeof imageInfo === 'string') {
return { path: imageInfo };
}
return {
...imageInfo,
};
};

/**
* Override Jimp types that expect to be mapped to either string or buffer even though Jimp
* accepts both https://www.npmjs.com/package/jimp#basic-usage.
*/
const toJimp = (imageInfo: string | Buffer): Promise<Jimp> => {
return (Jimp.read as (value: string | Buffer) => Promise<Jimp>)(imageInfo);
};

/**
* Comparing pngs and writing result to provided directory
*
* @param sessionPath
* @param baselinePath
* @param session
* @param baseline
* @param diffPath
* @param sessionDirectory
* @param log
* @returns Percent
*/
export async function comparePngs(
sessionPath: string,
baselinePath: string,
sessionInfo: string | PngDescriptor,
baselineInfo: string | PngDescriptor,
diffPath: string,
sessionDirectory: string,
log: ToolingLog
) {
log.debug(`comparePngs: ${sessionPath} vs ${baselinePath}`);
const session = (await Jimp.read(sessionPath)).clone();
const baseline = (await Jimp.read(baselinePath)).clone();
const sessionDescriptor = toDescriptor(sessionInfo);
const baselineDescriptor = toDescriptor(baselineInfo);

log.debug(`comparePngs: ${sessionDescriptor.path} vs ${baselineDescriptor.path}`);

const session = (await toJimp(sessionDescriptor.buffer ?? sessionDescriptor.path)).clone();
const baseline = (await toJimp(baselineDescriptor.buffer ?? baselineDescriptor.path)).clone();

if (
session.bitmap.width !== baseline.bitmap.width ||
Expand Down Expand Up @@ -63,8 +93,12 @@ export async function comparePngs(
image.write(diffPath);

// For debugging purposes it'll help to see the resized images and how they compare.
session.write(join(sessionDirectory, `${parse(sessionPath).name}-session-resized.png`));
baseline.write(join(sessionDirectory, `${parse(baselinePath).name}-baseline-resized.png`));
session.write(
join(sessionDirectory, `${parse(sessionDescriptor.path).name}-session-resized.png`)
);
baseline.write(
join(sessionDirectory, `${parse(baselineDescriptor.path).name}-baseline-resized.png`)
);
}
return percent;
}
2 changes: 2 additions & 0 deletions x-pack/examples/reporting_example/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
export const PLUGIN_ID = 'reportingExample';
export const PLUGIN_NAME = 'reportingExample';

export { MyForwardableState } from './types';

export {
REPORTING_EXAMPLE_LOCATOR_ID,
ReportingExampleLocatorDefinition,
Expand Down
6 changes: 4 additions & 2 deletions x-pack/examples/reporting_example/common/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { SerializableRecord } from '@kbn/utility-types';
import type { LocatorDefinition } from '../../../../src/plugins/share/public';
import { PLUGIN_ID } from '../common';
import type { MyForwardableState } from '../public/types';

export const REPORTING_EXAMPLE_LOCATOR_ID = 'REPORTING_EXAMPLE_LOCATOR_ID';

Expand All @@ -20,10 +21,11 @@ export class ReportingExampleLocatorDefinition implements LocatorDefinition<{}>
'1.0.0': (state: {}) => ({ ...state, migrated: true }),
};

public readonly getLocation = async (params: {}) => {
public readonly getLocation = async (params: MyForwardableState) => {
const path = Boolean(params.captureTest) ? '/captureTest' : '/';
return {
app: PLUGIN_ID,
path: '/',
path,
state: params,
};
};
Expand Down
13 changes: 13 additions & 0 deletions x-pack/examples/reporting_example/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { Ensure, SerializableRecord } from '@kbn/utility-types';

export type MyForwardableState = Ensure<
SerializableRecord & { captureTest: 'A' },
SerializableRecord
>;
22 changes: 14 additions & 8 deletions x-pack/examples/reporting_example/public/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,29 @@

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'react-router-dom';
import { AppMountParameters, CoreStart } from '../../../../src/core/public';
import { ReportingExampleApp } from './components/app';
import { CaptureTest } from './containers/capture_test';
import { Main } from './containers/main';
import { ApplicationContextProvider } from './application_context';
import { SetupDeps, StartDeps, MyForwardableState } from './types';
import { ROUTES } from './constants';

export const renderApp = (
coreStart: CoreStart,
deps: Omit<StartDeps & SetupDeps, 'developerExamples'>,
{ appBasePath, element }: AppMountParameters, // FIXME: appBasePath is deprecated
{ appBasePath, element, history }: AppMountParameters, // FIXME: appBasePath is deprecated
forwardedParams: MyForwardableState
) => {
ReactDOM.render(
<ReportingExampleApp
basename={appBasePath}
{...coreStart}
{...deps}
forwardedParams={forwardedParams}
/>,
<ApplicationContextProvider forwardedState={forwardedParams}>
<Router history={history}>
<Switch>
<Route path={ROUTES.captureTest} exact render={() => <CaptureTest />} />
<Route render={() => <Main basename={appBasePath} {...coreStart} {...deps} />} />
</Switch>
</Router>
</ApplicationContextProvider>,
element
);

Expand Down
33 changes: 33 additions & 0 deletions x-pack/examples/reporting_example/public/application_context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React, { useContext, createContext, FC } from 'react';

import type { MyForwardableState } from './types';

interface ContextValue {
forwardedState?: MyForwardableState;
}

const ApplicationContext = createContext<undefined | ContextValue>(undefined);

export const ApplicationContextProvider: FC<{ forwardedState: ContextValue['forwardedState'] }> = ({
forwardedState,
children,
}) => {
return (
<ApplicationContext.Provider value={{ forwardedState }}>{children}</ApplicationContext.Provider>
);
};

export const useApplicationContext = (): ContextValue => {
const ctx = useContext(ApplicationContext);
if (!ctx) {
throw new Error('useApplicationContext called outside of ApplicationContext!');
}
return ctx;
};
8 changes: 8 additions & 0 deletions x-pack/examples/reporting_example/public/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export { TestImageA } from './test_image_a';

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions x-pack/examples/reporting_example/public/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

// Values based on A4 page size
export const VIS = {
width: 1950 / 2,
height: 1200 / 2,
};

export const ROUTES = {
captureTest: '/captureTest',
main: '/',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.reportingExample {
&__captureContainer {
display: flex;
flex-direction: column;
align-items: center;

margin-top: $euiSizeM;
margin-bottom: $euiSizeM;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { FunctionComponent } from 'react';
import React from 'react';
import { useHistory } from 'react-router-dom';
import { parsePath } from 'history';
import {
EuiTabbedContent,
EuiTabbedContentTab,
EuiSpacer,
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiPage,
EuiPageHeader,
EuiPageBody,
EuiPageContent,
EuiPageContentBody,
} from '@elastic/eui';

import { TestImageA } from '../components';
import { useApplicationContext } from '../application_context';
import { MyForwardableState } from '../types';
import { ROUTES } from '../constants';

import './capture_test.scss';

const ItemsContainer: FunctionComponent<{ count: string }> = ({ count, children }) => (
<div
className="reportingExample__captureContainer"
data-shared-items-container
data-shared-items-count={count}
>
{children}
</div>
);

const tabs: Array<EuiTabbedContentTab & { id: MyForwardableState['captureTest'] }> = [
{
id: 'A',
name: 'Test A',
content: (
<ItemsContainer count="4">
<TestImageA />
<TestImageA />
<TestImageA />
<TestImageA />
</ItemsContainer>
),
},
];

export const CaptureTest: FunctionComponent = () => {
const { forwardedState } = useApplicationContext();
const tabToRender = forwardedState?.captureTest;
const history = useHistory();
return (
<EuiPage>
<EuiPageBody>
<EuiPageContent>
<EuiPageHeader>
<EuiFlexGroup alignItems="center" justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
iconType="arrowLeft"
href={history.createHref(parsePath(ROUTES.main))}
>
Back to main
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageHeader>
<EuiPageContentBody>
<EuiSpacer />
<EuiTabbedContent
tabs={tabs}
initialSelectedTab={
tabToRender ? tabs.find((tab) => tab.id === tabToRender) : undefined
}
/>
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
);
};
Loading