mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Reporting/Test] Add Functional test for download CSV (#65401)
* [Reporting/Test] Add Functional test for download CSV * add todo * add fs.existsSync check to find download * debug * handle timeout * validate toast * different way of getting repo_root
This commit is contained in:
parent
e2d945ff0b
commit
f4d27b2838
5 changed files with 204 additions and 122 deletions
|
@ -198,7 +198,7 @@ export async function FindProvider({ getService }: FtrProviderContext) {
|
|||
if (isDisplayed) {
|
||||
return descendant;
|
||||
} else {
|
||||
throw new Error('Element is not displayed');
|
||||
throw new Error(`Element "${selector}" is not displayed`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { REPO_ROOT } from '@kbn/dev-utils';
|
||||
import expect from '@kbn/expect';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as Rx from 'rxjs';
|
||||
import { filter, first, map, timeout } from 'rxjs/operators';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
const csvPath = path.resolve(REPO_ROOT, 'target/functional-tests/downloads/Ecommerce Data.csv');
|
||||
|
||||
export default function({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const browser = getService('browser');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const log = getService('log');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['reporting', 'common', 'dashboard']);
|
||||
|
||||
describe('Reporting Download CSV', () => {
|
||||
before('initialize tests', async () => {
|
||||
log.debug('ReportingPage:initTests');
|
||||
await esArchiver.loadIfNeeded('reporting/ecommerce');
|
||||
await esArchiver.loadIfNeeded('reporting/ecommerce_kibana');
|
||||
await browser.setWindowSize(1600, 850);
|
||||
});
|
||||
|
||||
after('clean up archives and previous file download', async () => {
|
||||
await esArchiver.unload('reporting/ecommerce');
|
||||
await esArchiver.unload('reporting/ecommerce_kibana');
|
||||
try {
|
||||
fs.unlinkSync(csvPath);
|
||||
} catch (e) {
|
||||
// nothing to worry
|
||||
}
|
||||
});
|
||||
|
||||
it('Downloads a CSV export of a saved search panel', async function() {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard');
|
||||
const savedSearchPanel = await testSubjects.find('embeddablePanelHeading-EcommerceData');
|
||||
await dashboardPanelActions.toggleContextMenu(savedSearchPanel);
|
||||
|
||||
await testSubjects.existOrFail('embeddablePanelAction-downloadCsvReport'); // wait for the full panel to display or else the test runner could click the wrong option!
|
||||
await testSubjects.click('embeddablePanelAction-downloadCsvReport');
|
||||
await testSubjects.existOrFail('csvDownloadStarted'); // validate toast panel
|
||||
|
||||
// check every 100ms for the file to exist in the download dir
|
||||
// just wait up to 5 seconds
|
||||
const success$ = Rx.interval(100).pipe(
|
||||
map(() => fs.existsSync(csvPath)),
|
||||
filter(value => value === true),
|
||||
first(),
|
||||
timeout(5000)
|
||||
);
|
||||
|
||||
const fileExists = await success$.toPromise();
|
||||
expect(fileExists).to.be(true);
|
||||
|
||||
// no need to validate download contents, API Integration tests do that some different variations
|
||||
});
|
||||
});
|
||||
}
|
|
@ -3,125 +3,11 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { promisify } from 'util';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { checkIfPngsMatch } from './lib/compare_pngs';
|
||||
|
||||
const writeFileAsync = promisify(fs.writeFile);
|
||||
const mkdirAsync = promisify(fs.mkdir);
|
||||
|
||||
const REPORTS_FOLDER = path.resolve(__dirname, 'reports');
|
||||
|
||||
export default function({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const browser = getService('browser');
|
||||
const log = getService('log');
|
||||
const config = getService('config');
|
||||
const PageObjects = getPageObjects(['reporting', 'common', 'dashboard']);
|
||||
|
||||
describe('Reporting', () => {
|
||||
before('initialize tests', async () => {
|
||||
log.debug('ReportingPage:initTests');
|
||||
await esArchiver.loadIfNeeded('reporting/ecommerce');
|
||||
await esArchiver.loadIfNeeded('reporting/ecommerce_kibana');
|
||||
await browser.setWindowSize(1600, 850);
|
||||
});
|
||||
after('clean up archives', async () => {
|
||||
await esArchiver.unload('reporting/ecommerce');
|
||||
await esArchiver.unload('reporting/ecommerce_kibana');
|
||||
});
|
||||
|
||||
describe('Print PDF button', () => {
|
||||
it('is not available if new', async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.reporting.openPdfReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true');
|
||||
});
|
||||
|
||||
it('becomes available when saved', async () => {
|
||||
await PageObjects.dashboard.saveDashboard('My PDF Dashboard');
|
||||
await PageObjects.reporting.openPdfReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Print Layout', () => {
|
||||
it('downloads a PDF file', async function() {
|
||||
// Generating and then comparing reports can take longer than the default 60s timeout because the comparePngs
|
||||
// function is taking about 15 seconds per comparison in jenkins.
|
||||
this.timeout(300000);
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard');
|
||||
await PageObjects.reporting.openPdfReportingPanel();
|
||||
await PageObjects.reporting.checkUsePrintLayout();
|
||||
await PageObjects.reporting.clickGenerateReportButton();
|
||||
|
||||
const url = await PageObjects.reporting.getReportURL(60000);
|
||||
const res = await PageObjects.reporting.getResponse(url);
|
||||
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.headers['content-type']).to.equal('application/pdf');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Print PNG button', () => {
|
||||
it('is not available if new', async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.reporting.openPngReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true');
|
||||
});
|
||||
|
||||
it('becomes available when saved', async () => {
|
||||
await PageObjects.dashboard.saveDashboard('My PNG Dash');
|
||||
await PageObjects.reporting.openPngReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Preserve Layout', () => {
|
||||
it('matches baseline report', async function() {
|
||||
const writeSessionReport = async (name: string, rawPdf: Buffer, reportExt: string) => {
|
||||
const sessionDirectory = path.resolve(REPORTS_FOLDER, 'session');
|
||||
await mkdirAsync(sessionDirectory, { recursive: true });
|
||||
const sessionReportPath = path.resolve(sessionDirectory, `${name}.${reportExt}`);
|
||||
await writeFileAsync(sessionReportPath, rawPdf);
|
||||
return sessionReportPath;
|
||||
};
|
||||
const getBaselineReportPath = (fileName: string, reportExt: string) => {
|
||||
const baselineFolder = path.resolve(REPORTS_FOLDER, 'baseline');
|
||||
const fullPath = path.resolve(baselineFolder, `${fileName}.${reportExt}`);
|
||||
log.debug(`getBaselineReportPath (${fullPath})`);
|
||||
return fullPath;
|
||||
};
|
||||
|
||||
this.timeout(300000);
|
||||
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard');
|
||||
await PageObjects.reporting.openPngReportingPanel();
|
||||
await PageObjects.reporting.forceSharedItemsContainerSize({ width: 1405 });
|
||||
await PageObjects.reporting.clickGenerateReportButton();
|
||||
await PageObjects.reporting.removeForceSharedItemsContainerSize();
|
||||
|
||||
const url = await PageObjects.reporting.getReportURL(60000);
|
||||
const reportData = await PageObjects.reporting.getRawPdfReportData(url);
|
||||
const reportFileName = 'dashboard_preserve_layout';
|
||||
const sessionReportPath = await writeSessionReport(reportFileName, reportData, 'png');
|
||||
const percentSimilar = await checkIfPngsMatch(
|
||||
sessionReportPath,
|
||||
getBaselineReportPath(reportFileName, 'png'),
|
||||
config.get('screenshots.directory'),
|
||||
log
|
||||
);
|
||||
|
||||
expect(percentSimilar).to.be.lessThan(0.1);
|
||||
});
|
||||
});
|
||||
export default function({ loadTestFile }: FtrProviderContext) {
|
||||
describe('Reporting', function() {
|
||||
loadTestFile(require.resolve('./screenshots'));
|
||||
loadTestFile(require.resolve('./download_csv'));
|
||||
});
|
||||
}
|
||||
|
|
127
x-pack/test/functional/apps/dashboard/reporting/screenshots.ts
Normal file
127
x-pack/test/functional/apps/dashboard/reporting/screenshots.ts
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { promisify } from 'util';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { checkIfPngsMatch } from './lib/compare_pngs';
|
||||
|
||||
const writeFileAsync = promisify(fs.writeFile);
|
||||
const mkdirAsync = promisify(fs.mkdir);
|
||||
|
||||
const REPORTS_FOLDER = path.resolve(__dirname, 'reports');
|
||||
|
||||
export default function({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const browser = getService('browser');
|
||||
const log = getService('log');
|
||||
const config = getService('config');
|
||||
const PageObjects = getPageObjects(['reporting', 'common', 'dashboard']);
|
||||
|
||||
describe('Screenshots', () => {
|
||||
before('initialize tests', async () => {
|
||||
log.debug('ReportingPage:initTests');
|
||||
await esArchiver.loadIfNeeded('reporting/ecommerce');
|
||||
await esArchiver.loadIfNeeded('reporting/ecommerce_kibana');
|
||||
await browser.setWindowSize(1600, 850);
|
||||
});
|
||||
after('clean up archives', async () => {
|
||||
await esArchiver.unload('reporting/ecommerce');
|
||||
await esArchiver.unload('reporting/ecommerce_kibana');
|
||||
});
|
||||
|
||||
describe('Print PDF button', () => {
|
||||
it('is not available if new', async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.reporting.openPdfReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true');
|
||||
});
|
||||
|
||||
it('becomes available when saved', async () => {
|
||||
await PageObjects.dashboard.saveDashboard('My PDF Dashboard');
|
||||
await PageObjects.reporting.openPdfReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Print Layout', () => {
|
||||
it('downloads a PDF file', async function() {
|
||||
// Generating and then comparing reports can take longer than the default 60s timeout because the comparePngs
|
||||
// function is taking about 15 seconds per comparison in jenkins.
|
||||
this.timeout(300000);
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard');
|
||||
await PageObjects.reporting.openPdfReportingPanel();
|
||||
await PageObjects.reporting.checkUsePrintLayout();
|
||||
await PageObjects.reporting.clickGenerateReportButton();
|
||||
|
||||
const url = await PageObjects.reporting.getReportURL(60000);
|
||||
const res = await PageObjects.reporting.getResponse(url);
|
||||
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.headers['content-type']).to.equal('application/pdf');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Print PNG button', () => {
|
||||
it('is not available if new', async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.reporting.openPngReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true');
|
||||
});
|
||||
|
||||
it('becomes available when saved', async () => {
|
||||
await PageObjects.dashboard.saveDashboard('My PNG Dash');
|
||||
await PageObjects.reporting.openPngReportingPanel();
|
||||
expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Preserve Layout', () => {
|
||||
it('matches baseline report', async function() {
|
||||
const writeSessionReport = async (name: string, rawPdf: Buffer, reportExt: string) => {
|
||||
const sessionDirectory = path.resolve(REPORTS_FOLDER, 'session');
|
||||
await mkdirAsync(sessionDirectory, { recursive: true });
|
||||
const sessionReportPath = path.resolve(sessionDirectory, `${name}.${reportExt}`);
|
||||
await writeFileAsync(sessionReportPath, rawPdf);
|
||||
return sessionReportPath;
|
||||
};
|
||||
const getBaselineReportPath = (fileName: string, reportExt: string) => {
|
||||
const baselineFolder = path.resolve(REPORTS_FOLDER, 'baseline');
|
||||
const fullPath = path.resolve(baselineFolder, `${fileName}.${reportExt}`);
|
||||
log.debug(`getBaselineReportPath (${fullPath})`);
|
||||
return fullPath;
|
||||
};
|
||||
|
||||
this.timeout(300000);
|
||||
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.loadSavedDashboard('Ecom Dashboard');
|
||||
await PageObjects.reporting.openPngReportingPanel();
|
||||
await PageObjects.reporting.forceSharedItemsContainerSize({ width: 1405 });
|
||||
await PageObjects.reporting.clickGenerateReportButton();
|
||||
await PageObjects.reporting.removeForceSharedItemsContainerSize();
|
||||
|
||||
const url = await PageObjects.reporting.getReportURL(60000);
|
||||
const reportData = await PageObjects.reporting.getRawPdfReportData(url);
|
||||
const reportFileName = 'dashboard_preserve_layout';
|
||||
const sessionReportPath = await writeSessionReport(reportFileName, reportData, 'png');
|
||||
const percentSimilar = await checkIfPngsMatch(
|
||||
sessionReportPath,
|
||||
getBaselineReportPath(reportFileName, 'png'),
|
||||
config.get('screenshots.directory'),
|
||||
log
|
||||
);
|
||||
|
||||
expect(percentSimilar).to.be.lessThan(0.1);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -9,10 +9,11 @@ import { FtrProviderContext } from 'test/functional/ftr_provider_context';
|
|||
import { parse } from 'url';
|
||||
|
||||
export function ReportingPageProvider({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const retry = getService('retry');
|
||||
const log = getService('log');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const browser = getService('browser');
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
const testSubjects = getService('testSubjects');
|
||||
|
||||
const PageObjects = getPageObjects(['common', 'security' as any, 'share', 'timePicker']); // FIXME: Security PageObject is not Typescript
|
||||
|
||||
class ReportingPage {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue