-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Watcher] Retain search and pagination values when watch list refreshes #82651
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,15 +6,9 @@ | |
|
||
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'; | ||
import { ROUTES, REFRESH_INTERVALS } from '../../common/constants'; | ||
|
||
const { API_ROOT } = ROUTES; | ||
|
||
|
@@ -24,13 +18,21 @@ describe('<WatchList />', () => { | |
const { server, httpRequestsMockHelpers } = setupEnvironment(); | ||
let testBed: WatchListTestBed; | ||
|
||
beforeAll(() => { | ||
jest.useFakeTimers(); | ||
}); | ||
|
||
afterAll(() => { | ||
jest.useRealTimers(); | ||
server.restore(); | ||
}); | ||
|
||
describe('on component mount', () => { | ||
beforeEach(async () => { | ||
testBed = await setup(); | ||
await act(async () => { | ||
testBed = await setup(); | ||
}); | ||
testBed.component.update(); | ||
}); | ||
|
||
describe('watches', () => { | ||
|
@@ -40,12 +42,12 @@ describe('<WatchList />', () => { | |
}); | ||
|
||
test('should display an empty prompt', async () => { | ||
const { component, exists } = await setup(); | ||
|
||
await act(async () => { | ||
await nextTick(); | ||
component.update(); | ||
testBed = await setup(); | ||
}); | ||
const { component, exists } = testBed; | ||
|
||
component.update(); | ||
|
||
expect(exists('emptyPrompt')).toBe(true); | ||
expect(exists('emptyPrompt.createWatchButton')).toBe(true); | ||
|
@@ -76,12 +78,68 @@ describe('<WatchList />', () => { | |
beforeEach(async () => { | ||
httpRequestsMockHelpers.setLoadWatchesResponse({ watches }); | ||
|
||
testBed = await setup(); | ||
await act(async () => { | ||
testBed = await setup(); | ||
}); | ||
|
||
testBed.component.update(); | ||
}); | ||
|
||
test('should retain the search query', async () => { | ||
const { find, component, table } = testBed; | ||
|
||
const searchInput = find('watchesTableContainer').find('.euiFieldSearch'); | ||
|
||
// Enter the name of "watch1" in the search box | ||
// @ts-ignore | ||
searchInput.instance().value = watch1.name; | ||
searchInput.simulate('keyup', { key: 'Enter', keyCode: 13, which: 13 }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor DX suggestion. How about abstracting this behind a helper function in const searchWatches = (term) => {
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();
};
return {
...testBed,
actions: {
selectWatchAt,
clickWatchAt,
clickWatchActionAt,
searchWatches,
},
}; Then here we can call it like this: test('should retain the search query', async () => {
const { find, component, table, actions: { searchWatches } } = testBed;
searchWatches(watch1.name);
const { tableCellsValues } = table.getMetaData('watchesTable'); |
||
|
||
component.update(); | ||
|
||
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 getExpectedValue = (value: any) => (typeof value === 'undefined' ? '' : value); | ||
|
||
expect(row).toEqual([ | ||
'', | ||
id, | ||
getExpectedValue(name), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find it really difficult to understand why we call It smells a bit like we're testing implementation if expect(row).toEqual([
'', // checkbox
'a-id', // ID
'a-name', // name
'OK', // status
'', // comment
'', // lastMetCondition
'', // lastChecked
'', // actions
]); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. I think I may have copied this from elsewhere. I agree it's not very clear. I updated the assertion to your suggestion. |
||
watchStatus.state, | ||
getExpectedValue(watchStatus.comment), | ||
getExpectedValue(watchStatus.lastMetCondition), | ||
getExpectedValue(watchStatus.lastChecked), | ||
'', | ||
]); | ||
|
||
await act(async () => { | ||
await nextTick(); | ||
testBed.component.update(); | ||
// Advance timers to simulate another request | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar DX suggestion here about a helper function. We can add this to 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,
advanceTimeToTableRefresh,
},
}; And use it here: await advanceTimeToTableRefresh(); |
||
jest.advanceTimersByTime(REFRESH_INTERVALS.WATCH_LIST); | ||
}); | ||
|
||
component.update(); | ||
|
||
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([ | ||
'', | ||
id, | ||
getExpectedValue(name), | ||
watchStatus.state, | ||
getExpectedValue(watchStatus.comment), | ||
getExpectedValue(watchStatus.lastMetCondition), | ||
getExpectedValue(watchStatus.lastChecked), | ||
'', | ||
]); | ||
}); | ||
|
||
test('should set the correct app title', () => { | ||
|
@@ -208,10 +266,10 @@ describe('<WatchList />', () => { | |
|
||
await act(async () => { | ||
confirmButton!.click(); | ||
await nextTick(); | ||
component.update(); | ||
}); | ||
|
||
component.update(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this one needed? I was able to remove it and the test passed. |
||
|
||
const latestRequest = server.requests[server.requests.length - 1]; | ||
|
||
expect(latestRequest.method).toBe('POST'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<string[]>([]); | ||
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 = ( | ||
<EuiInMemoryTable | ||
items={availableWatches} | ||
itemId="id" | ||
columns={columns} | ||
search={searchConfig} | ||
pagination={PAGINATION} | ||
sorting={true} | ||
selection={selectionConfig} | ||
isSelectable={true} | ||
message={ | ||
<FormattedMessage | ||
id="xpack.watcher.sections.watchList.watchTable.noWatchesMessage" | ||
defaultMessage="No watches to show" | ||
/> | ||
} | ||
rowProps={() => ({ | ||
'data-test-subj': 'row', | ||
})} | ||
cellProps={() => ({ | ||
'data-test-subj': 'cell', | ||
})} | ||
data-test-subj="watchesTable" | ||
/> | ||
<div data-test-subj="watchesTableContainer"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The search box in the table doesn't appear to be able to accept a |
||
<EuiInMemoryTable | ||
onTableChange={({ page: { index, size } }: CriteriaWithPagination<never>) => | ||
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={ | ||
<FormattedMessage | ||
id="xpack.watcher.sections.watchList.watchTable.noWatchesMessage" | ||
defaultMessage="No watches to show" | ||
/> | ||
} | ||
rowProps={() => ({ | ||
'data-test-subj': 'row', | ||
})} | ||
cellProps={() => ({ | ||
'data-test-subj': 'cell', | ||
})} | ||
data-test-subj="watchesTable" | ||
/> | ||
</div> | ||
); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like each of these tests calls
setup
on its own, so I think we can remove this entirebeforeEach
.