[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:
Tim Sullivan 2020-05-11 12:49:19 -07:00 committed by GitHub
parent e2d945ff0b
commit f4d27b2838
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 204 additions and 122 deletions

View file

@ -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`);
}
}

View file

@ -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
});
});
}

View file

@ -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'));
});
}

View 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);
});
});
});
}

View file

@ -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 {