diff --git a/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap b/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap index ddba7842f1199..66c3aea8acc13 100644 --- a/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap +++ b/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap @@ -30,6 +30,7 @@ Array [ }, ] } + data-test-page={0} data-test-subj="reportJobListing" isSelectable={true} itemId="id" @@ -56,6 +57,7 @@ Array [ >
@@ -366,6 +368,7 @@ Array [ ,
diff --git a/x-pack/plugins/reporting/public/components/report_listing.tsx b/x-pack/plugins/reporting/public/components/report_listing.tsx index a397a74cb8932..8150d0ccc557e 100644 --- a/x-pack/plugins/reporting/public/components/report_listing.tsx +++ b/x-pack/plugins/reporting/public/components/report_listing.tsx @@ -513,6 +513,7 @@ class ReportListingUi extends Component { isSelectable={true} onChange={this.onTableChange} data-test-subj="reportJobListing" + data-test-page={this.state.page} /> {this.state.selectedJobs.length > 0 ? this.renderDeleteButton() : null} diff --git a/x-pack/plugins/reporting/server/routes/jobs.ts b/x-pack/plugins/reporting/server/routes/jobs.ts index 4033719b053ba..e8eac9e577beb 100644 --- a/x-pack/plugins/reporting/server/routes/jobs.ts +++ b/x-pack/plugins/reporting/server/routes/jobs.ts @@ -35,7 +35,13 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { router.get( { path: `${MAIN_ENTRY}/list`, - validate: false, + validate: { + query: schema.object({ + page: schema.string({ defaultValue: '0' }), + size: schema.string({ defaultValue: '10' }), + ids: schema.maybe(schema.string()), + }), + }, }, userHandler(async (user, context, req, res) => { // ensure the async dependencies are loaded @@ -50,7 +56,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { page: queryPage = '0', size: querySize = '10', ids: queryIds = null, - } = req.query as ListQuery; + } = req.query as ListQuery; // NOTE: type inference is not working here. userHandler breaks it? const page = parseInt(queryPage, 10) || 0; const size = Math.min(100, parseInt(querySize, 10) || 10); const jobIds = queryIds ? queryIds.split(',') : null; diff --git a/x-pack/test/functional/apps/dashboard/reporting/screenshots.ts b/x-pack/test/functional/apps/dashboard/reporting/screenshots.ts index da1131d051581..cf70e5a7b8b6c 100644 --- a/x-pack/test/functional/apps/dashboard/reporting/screenshots.ts +++ b/x-pack/test/functional/apps/dashboard/reporting/screenshots.ts @@ -16,12 +16,13 @@ const mkdirAsync = promisify(fs.mkdir); const REPORTS_FOLDER = path.resolve(__dirname, 'reports'); -export default function ({ getService, getPageObjects }: FtrProviderContext) { +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const PageObjects = getPageObjects(['reporting', 'common', 'dashboard']); const esArchiver = getService('esArchiver'); const browser = getService('browser'); const log = getService('log'); const config = getService('config'); - const PageObjects = getPageObjects(['reporting', 'common', 'dashboard']); + const es = getService('es'); describe('Screenshots', () => { before('initialize tests', async () => { @@ -33,6 +34,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after('clean up archives', async () => { await esArchiver.unload('reporting/ecommerce'); await esArchiver.unload('reporting/ecommerce_kibana'); + await es.deleteByQuery({ + index: '.reporting-*', + refresh: true, + body: { query: { match_all: {} } }, + }); }); describe('Print PDF button', () => { diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 32ccc59913dbc..7181bf0c74271 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -9,6 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); + const es = getService('es'); const esArchiver = getService('esArchiver'); const browser = getService('browser'); const PageObjects = getPageObjects(['reporting', 'common', 'discover']); @@ -22,6 +23,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after('clean up archives', async () => { await esArchiver.unload('reporting/ecommerce'); + await es.deleteByQuery({ + index: '.reporting-*', + refresh: true, + body: { query: { match_all: {} } }, + }); }); describe('Generate CSV button', () => { diff --git a/x-pack/test/functional/apps/lens/lens_reporting.ts b/x-pack/test/functional/apps/lens/lens_reporting.ts index 5fa2bd1a049a7..2adcee0c5e145 100644 --- a/x-pack/test/functional/apps/lens/lens_reporting.ts +++ b/x-pack/test/functional/apps/lens/lens_reporting.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'dashboard', 'reporting']); + const es = getService('es'); const esArchiver = getService('esArchiver'); const listingTable = getService('listingTable'); @@ -20,6 +21,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await esArchiver.unload('lens/reporting'); + await es.deleteByQuery({ + index: '.reporting-*', + refresh: true, + body: { query: { match_all: {} } }, + }); }); it('should not cause PDF reports to fail', async () => { diff --git a/x-pack/test/functional/apps/reporting_management/index.ts b/x-pack/test/functional/apps/reporting_management/index.ts index f44d5858d53a1..8606c46053ab0 100644 --- a/x-pack/test/functional/apps/reporting_management/index.ts +++ b/x-pack/test/functional/apps/reporting_management/index.ts @@ -9,6 +9,6 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext) => { describe('reporting management app', function () { this.tags('ciGroup7'); - loadTestFile(require.resolve('./report_delete_pagination')); + loadTestFile(require.resolve('./report_listing')); }); }; diff --git a/x-pack/test/functional/apps/reporting_management/report_delete_pagination.ts b/x-pack/test/functional/apps/reporting_management/report_delete_pagination.ts deleted file mode 100644 index 488314030085f..0000000000000 --- a/x-pack/test/functional/apps/reporting_management/report_delete_pagination.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 { FtrProviderContext } from '../../ftr_provider_context'; - -export default ({ getPageObjects, getService }: FtrProviderContext) => { - const pageObjects = getPageObjects(['common', 'reporting']); - const log = getService('log'); - const retry = getService('retry'); - const security = getService('security'); - - const testSubjects = getService('testSubjects'); - const esArchiver = getService('esArchiver'); - - describe('Delete reports', function () { - before(async () => { - await security.testUser.setRoles(['kibana_admin', 'reporting_user']); - await esArchiver.load('empty_kibana'); - await esArchiver.load('reporting/archived_reports'); - await pageObjects.common.navigateToApp('reporting'); - await testSubjects.existOrFail('reportJobListing', { timeout: 200000 }); - }); - - after(async () => { - await esArchiver.unload('empty_kibana'); - await esArchiver.unload('reporting/archived_reports'); - await security.testUser.restoreDefaults(); - }); - - it('Confirm single report deletion works', async () => { - log.debug('Checking for reports.'); - await retry.try(async () => { - await testSubjects.click('checkboxSelectRow-k9a9xlwl0gpe1457b10rraq3'); - }); - const deleteButton = await testSubjects.find('deleteReportButton'); - await retry.waitFor('delete button to become enabled', async () => { - return await deleteButton.isEnabled(); - }); - await deleteButton.click(); - await testSubjects.exists('confirmModalBodyText'); - await testSubjects.click('confirmModalConfirmButton'); - await retry.try(async () => { - await testSubjects.waitForDeleted('checkboxSelectRow-k9a9xlwl0gpe1457b10rraq3'); - }); - }); - - // functional test for report pagination: https://github.com/elastic/kibana/pull/62881 - it('Report pagination', async () => { - const previousButton = await testSubjects.find('pagination-button-previous'); - expect(await previousButton.getAttribute('disabled')).to.be('true'); - await testSubjects.click('pagination-button-1'); - expect(await previousButton.getAttribute('disabled')).to.be(null); - }); - }); -}; diff --git a/x-pack/test/functional/apps/reporting_management/report_listing.ts b/x-pack/test/functional/apps/reporting_management/report_listing.ts new file mode 100644 index 0000000000000..5bb36103fc6f6 --- /dev/null +++ b/x-pack/test/functional/apps/reporting_management/report_listing.ts @@ -0,0 +1,121 @@ +/* + * 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 { WebElementWrapper } from 'test/functional/services/lib/web_element_wrapper'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +const getTableTextFromElement = async (tableEl: WebElementWrapper) => { + const rows = await tableEl.findAllByCssSelector('tbody tr'); + return ( + await Promise.all( + rows.map(async (row) => { + return await row.getVisibleText(); + }) + ) + ).join('\n'); +}; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const pageObjects = getPageObjects(['common', 'reporting']); + const log = getService('log'); + const retry = getService('retry'); + const security = getService('security'); + + const testSubjects = getService('testSubjects'); + const findInstance = getService('find'); + const esArchiver = getService('esArchiver'); + + describe('Listing of Reports', function () { + before(async () => { + await security.testUser.setRoles(['kibana_admin', 'reporting_user']); + await esArchiver.load('empty_kibana'); + }); + + beforeEach(async () => { + // to reset the data after deletion testing + await esArchiver.load('reporting/archived_reports'); + await pageObjects.common.navigateToApp('reporting'); + await testSubjects.existOrFail('reportJobListing', { timeout: 200000 }); + }); + + after(async () => { + await esArchiver.unload('empty_kibana'); + await security.testUser.restoreDefaults(); + }); + + afterEach(async () => { + await esArchiver.unload('reporting/archived_reports'); + }); + + it('Confirm single report deletion works', async () => { + log.debug('Checking for reports.'); + await retry.try(async () => { + await testSubjects.click('checkboxSelectRow-k9a9xlwl0gpe1457b10rraq3'); + }); + const deleteButton = await testSubjects.find('deleteReportButton'); + await retry.waitFor('delete button to become enabled', async () => { + return await deleteButton.isEnabled(); + }); + await deleteButton.click(); + await testSubjects.exists('confirmModalBodyText'); + await testSubjects.click('confirmModalConfirmButton'); + await retry.try(async () => { + await testSubjects.waitForDeleted('checkboxSelectRow-k9a9xlwl0gpe1457b10rraq3'); + }); + }); + + it('Paginates content', async () => { + const previousButton = await testSubjects.find('pagination-button-previous'); + + // previous CAN NOT be clicked + expect(await previousButton.getAttribute('disabled')).to.be('true'); + + // scan page 1 + let tableText = await getTableTextFromElement(await testSubjects.find('reportJobListing')); + const PAGE_CONTENT_1 = `[Logs] File Type Scatter Plot\nvisualization\n2020-04-21 @ 07:01 PM\ntest_user\nCompleted at 2020-04-21 @ 07:02 PM +[Logs] File Type Scatter Plot\nvisualization\n2020-04-21 @ 07:01 PM\ntest_user\nCompleted at 2020-04-21 @ 07:02 PM +[Logs] Heatmap\nvisualization\n2020-04-21 @ 07:00 PM\ntest_user\nCompleted at 2020-04-21 @ 07:01 PM +[Logs] Heatmap\nvisualization\n2020-04-21 @ 07:00 PM\ntest_user\nCompleted at 2020-04-21 @ 07:01 PM +[Flights] Flight Delays\nvisualization\n2020-04-21 @ 07:00 PM\ntest_user\nCompleted at 2020-04-21 @ 07:01 PM +[Flights] Flight Delays\nvisualization\n2020-04-21 @ 07:00 PM\ntest_user\nCompleted at 2020-04-21 @ 07:01 PM +pdf\ndashboard\n2020-04-21 @ 07:00 PM\ntest_user\nCompleted at 2020-04-21 @ 07:00 PM +pdf\ndashboard\n2020-04-21 @ 07:00 PM\ntest_user\nCompleted at 2020-04-21 @ 07:00 PM +[Flights] Flight Cancellations\nvisualization\n2020-04-21 @ 06:59 PM\ntest_user\nCompleted at 2020-04-21 @ 07:00 PM +[Flights] Markdown Instructions\nvisualization\n2020-04-21 @ 06:59 PM\ntest_user\nCompleted at 2020-04-21 @ 07:00 PM`; + expect(tableText).to.be(PAGE_CONTENT_1); + + // click page 2 + await testSubjects.click('pagination-button-1'); + await findInstance.byCssSelector('[data-test-page="1"]'); + + // previous CAN be clicked + expect(await previousButton.getAttribute('disabled')).to.be(null); + + // scan page 2 + tableText = await getTableTextFromElement(await testSubjects.find('reportJobListing')); + const PAGE_CONTENT_2 = `[eCommerce] Revenue Tracking\ncanvas workpad\n2020-04-21 @ 06:58 PM\ntest_user\nCompleted at 2020-04-21 @ 06:59 PM +[Logs] Web Traffic\ncanvas workpad\n2020-04-21 @ 06:58 PM\ntest_user\nCompleted at 2020-04-21 @ 06:59 PM +[Flights] Overview\ncanvas workpad\n2020-04-21 @ 06:58 PM\ntest_user\nCompleted at 2020-04-21 @ 06:59 PM +[eCommerce] Revenue Dashboard\ndashboard\n2020-04-21 @ 06:57 PM\ntest_user\nCompleted at 2020-04-21 @ 06:58 PM +[Logs] Web Traffic\ndashboard\n2020-04-21 @ 06:57 PM\ntest_user\nCompleted at 2020-04-21 @ 06:58 PM +[Flights] Global Flight Dashboard\ndashboard\n2020-04-21 @ 06:56 PM\ntest_user\nCompleted at 2020-04-21 @ 06:57 PM +[Flights] Global Flight Dashboard\ndashboard\n2020-04-21 @ 06:56 PM\ntest_user\nCompleted at 2020-04-21 @ 06:57 PM +report4csv\n2020-04-21 @ 06:55 PM\ntest_user\nCompleted at 2020-04-21 @ 06:56 PM - Max size reached\nreport3csv\n2020-04-21 @ 06:55 PM +test_user\nCompleted at 2020-04-21 @ 06:55 PM - Max size reached\nreport2csv\n2020-04-21 @ 06:54 PM\ntest_user\nCompleted at 2020-04-21 @ 06:55 PM - Max size reached`; + expect(tableText).to.be(PAGE_CONTENT_2); + + // click page 3 + await testSubjects.click('pagination-button-2'); + await findInstance.byCssSelector('[data-test-page="2"]'); + + // scan page 3 + tableText = await getTableTextFromElement(await testSubjects.find('reportJobListing')); + const PAGE_CONTENT_3 = `report1csv\n2020-04-21 @ 06:54 PM\ntest_user\nCompleted at 2020-04-21 @ 06:54 PM - Max size reached`; + expect(tableText).to.be(PAGE_CONTENT_3); + }); + }); +}; diff --git a/x-pack/test/functional/apps/visualize/reporting.ts b/x-pack/test/functional/apps/visualize/reporting.ts index 02fd74e9480f7..d1cea5a4481b1 100644 --- a/x-pack/test/functional/apps/visualize/reporting.ts +++ b/x-pack/test/functional/apps/visualize/reporting.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { + const es = getService('es'); const esArchiver = getService('esArchiver'); const browser = getService('browser'); const log = getService('log'); @@ -29,6 +30,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after('clean up archives', async () => { await esArchiver.unload('reporting/ecommerce'); await esArchiver.unload('reporting/ecommerce_kibana'); + await es.deleteByQuery({ + index: '.reporting-*', + refresh: true, + body: { query: { match_all: {} } }, + }); }); describe('Print PDF button', () => {