diff --git a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts index e511dcdc58606..ca5d962e4dd21 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/helpers/watch_list.helpers.ts @@ -14,7 +14,7 @@ import { nextTick, } from '../../../../../test_utils'; import { WatchList } from '../../../public/application/sections/watch_list/components/watch_list'; -import { ROUTES } from '../../../common/constants'; +import { ROUTES, REFRESH_INTERVALS } from '../../../common/constants'; import { withAppContext } from './app_context.mock'; const testBedConfig: TestBedConfig = { @@ -31,6 +31,8 @@ export interface WatchListTestBed extends TestBed { selectWatchAt: (index: number) => void; clickWatchAt: (index: number) => void; clickWatchActionAt: (index: number, action: 'delete' | 'edit') => void; + searchWatches: (term: string) => void; + advanceTimeToTableRefresh: () => Promise; }; } @@ -73,12 +75,35 @@ export const setup = async (): Promise => { }); }; + const searchWatches = (term: string) => { + const { find, component } = testBed; + const searchInput = find('watchesTableContainer').find('.euiFieldSearch'); + + // Enter input into the search box + // @ts-ignore + searchInput.instance().value = term; + searchInput.simulate('keyup', { key: 'Enter', keyCode: 13, which: 13 }); + + component.update(); + }; + + const advanceTimeToTableRefresh = async () => { + const { component } = testBed; + await act(async () => { + // Advance timers to simulate another request + jest.advanceTimersByTime(REFRESH_INTERVALS.WATCH_LIST); + }); + component.update(); + }; + return { ...testBed, actions: { selectWatchAt, clickWatchAt, clickWatchActionAt, + searchWatches, + advanceTimeToTableRefresh, }, }; }; @@ -95,4 +120,5 @@ export type TestSubjects = | 'createWatchButton' | 'emptyPrompt' | 'emptyPrompt.createWatchButton' - | 'editWatchButton'; + | 'editWatchButton' + | 'watchesTableContainer'; diff --git a/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts b/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts index e436971edbb69..844493ea35261 100644 --- a/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts +++ b/x-pack/plugins/watcher/__jest__/client_integration/watch_list.test.ts @@ -6,13 +6,7 @@ import { act } from 'react-dom/test-utils'; import * as fixtures from '../../test/fixtures'; -import { - setupEnvironment, - pageHelpers, - nextTick, - getRandomString, - findTestSubject, -} from './helpers'; +import { setupEnvironment, pageHelpers, getRandomString, findTestSubject } from './helpers'; import { WatchListTestBed } from './helpers/watch_list.helpers'; import { ROUTES } from '../../common/constants'; @@ -24,28 +18,29 @@ describe('', () => { const { server, httpRequestsMockHelpers } = setupEnvironment(); let testBed: WatchListTestBed; + beforeAll(() => { + jest.useFakeTimers(); + }); + afterAll(() => { + jest.useRealTimers(); server.restore(); }); describe('on component mount', () => { - beforeEach(async () => { - testBed = await setup(); - }); - describe('watches', () => { describe('when there are no watches', () => { - beforeEach(() => { + beforeEach(async () => { httpRequestsMockHelpers.setLoadWatchesResponse({ watches: [] }); - }); - - test('should display an empty prompt', async () => { - const { component, exists } = await setup(); await act(async () => { - await nextTick(); - component.update(); + testBed = await setup(); }); + testBed.component.update(); + }); + + test('should display an empty prompt', async () => { + const { exists } = testBed; expect(exists('emptyPrompt')).toBe(true); expect(exists('emptyPrompt.createWatchButton')).toBe(true); @@ -76,12 +71,47 @@ describe('', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadWatchesResponse({ watches }); - testBed = await setup(); - await act(async () => { - await nextTick(); - testBed.component.update(); + testBed = await setup(); }); + + testBed.component.update(); + }); + + test('should retain the search query', async () => { + const { table, actions } = testBed; + + actions.searchWatches(watch1.name); + + const { tableCellsValues } = table.getMetaData('watchesTable'); + + // Expect "watch1" is only visible in the table + expect(tableCellsValues.length).toEqual(1); + const row = tableCellsValues[0]; + const { name, id, watchStatus } = watch1; + + const expectedRow = [ + '', // checkbox + id, + name, + watchStatus.state, + '', // comment + '', // lastMetCondition + '', // lastChecked + '', // actions + ]; + + expect(row).toEqual(expectedRow); + + await actions.advanceTimeToTableRefresh(); + + const { tableCellsValues: updatedTableCellsValues } = table.getMetaData('watchesTable'); + + // Verify "watch1" is still the only watch visible in the table + expect(updatedTableCellsValues.length).toEqual(1); + const updatedRow = updatedTableCellsValues[0]; + + expect(updatedRow).toEqual(expectedRow); }); test('should set the correct app title', () => { @@ -185,7 +215,7 @@ describe('', () => { }); test('should send the correct HTTP request to delete watch', async () => { - const { component, actions, table } = testBed; + const { actions, table } = testBed; const { rows } = table.getMetaData('watchesTable'); const watchId = rows[0].columns[2].value; @@ -208,8 +238,6 @@ describe('', () => { await act(async () => { confirmButton!.click(); - await nextTick(); - component.update(); }); const latestRequest = server.requests[server.requests.length - 1]; diff --git a/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx b/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx index 729e37475fc99..a42704f37dc56 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx @@ -7,6 +7,7 @@ import React, { useState, useMemo, useEffect, Fragment } from 'react'; import { + CriteriaWithPagination, EuiButton, EuiButtonEmpty, EuiFlexGroup, @@ -57,6 +58,11 @@ export const WatchList = () => { // Filter out deleted watches on the client, because the API will return 200 even though some watches // may not really be deleted until after they're done firing and this could take some time. const [deletedWatches, setDeletedWatches] = useState([]); + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: PAGINATION.initialPageSize, + }); + const [query, setQuery] = useState(''); useEffect(() => { setBreadcrumbs([listBreadcrumb]); @@ -379,7 +385,14 @@ export const WatchList = () => { : '', }; + const handleOnChange = (search: { queryText: string }) => { + setQuery(search.queryText); + return true; + }; + const searchConfig = { + query, + onChange: handleOnChange, box: { incremental: true, }, @@ -409,29 +422,43 @@ export const WatchList = () => { }; content = ( - - } - rowProps={() => ({ - 'data-test-subj': 'row', - })} - cellProps={() => ({ - 'data-test-subj': 'cell', - })} - data-test-subj="watchesTable" - /> +
+ ) => + setPagination({ pageIndex: index, pageSize: size }) + } + items={availableWatches} + itemId="id" + columns={columns} + search={searchConfig} + pagination={{ + ...PAGINATION, + pageIndex: pagination.pageIndex, + pageSize: pagination.pageSize, + }} + sorting={{ + sort: { + field: 'name', + direction: 'asc', + }, + }} + selection={selectionConfig} + isSelectable={true} + message={ + + } + rowProps={() => ({ + 'data-test-subj': 'row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="watchesTable" + /> +
); }