Skip to content

Commit

Permalink
Fix skipped alerting UI tests (#55058) (#55869)
Browse files Browse the repository at this point in the history
* Fix skipped alerting UI tests

* Fix switch click to use new pageobject function

* Use .click function directly instead of find then click

* Merge state variables into one for alerts and alert types

* Fix flaky tests by fixing react code

* Could this be it?? The one thing missing that caused all this flakiness??

* Cleanup convertAlertsToTableItems function

* Remove I from interface names, fix disabled boolean logic

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
mikecote and elasticmachine committed Jan 24, 2020
1 parent da76703 commit 231ddfe
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ import { hasDeleteAlertsCapability, hasSaveAlertsCapability } from '../../../lib

const ENTER_KEY = 13;

interface AlertTypeState {
isLoading: boolean;
isInitialized: boolean;
data: AlertTypeIndex;
}
interface AlertState {
isLoading: boolean;
data: Alert[];
totalItemCount: number;
}

export const AlertsList: React.FunctionComponent = () => {
const {
http,
Expand All @@ -43,20 +54,24 @@ export const AlertsList: React.FunctionComponent = () => {
const createAlertUiEnabled = injectedMetadata.getInjectedVar('createAlertUiEnabled');

const [actionTypes, setActionTypes] = useState<ActionType[]>([]);
const [alertTypesIndex, setAlertTypesIndex] = useState<AlertTypeIndex | undefined>(undefined);
const [alerts, setAlerts] = useState<Alert[]>([]);
const [data, setData] = useState<AlertTableItem[]>([]);
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const [isLoadingAlertTypes, setIsLoadingAlertTypes] = useState<boolean>(false);
const [isLoadingAlerts, setIsLoadingAlerts] = useState<boolean>(false);
const [isPerformingAction, setIsPerformingAction] = useState<boolean>(false);
const [totalItemCount, setTotalItemCount] = useState<number>(0);
const [page, setPage] = useState<Pagination>({ index: 0, size: 10 });
const [searchText, setSearchText] = useState<string | undefined>();
const [inputText, setInputText] = useState<string | undefined>();
const [typesFilter, setTypesFilter] = useState<string[]>([]);
const [actionTypesFilter, setActionTypesFilter] = useState<string[]>([]);
const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState<boolean>(false);
const [alertTypesState, setAlertTypesState] = useState<AlertTypeState>({
isLoading: false,
isInitialized: false,
data: {},
});
const [alertsState, setAlertsState] = useState<AlertState>({
isLoading: false,
data: [],
totalItemCount: 0,
});

useEffect(() => {
loadAlertsData();
Expand All @@ -66,22 +81,21 @@ export const AlertsList: React.FunctionComponent = () => {
useEffect(() => {
(async () => {
try {
setIsLoadingAlertTypes(true);
setAlertTypesState({ ...alertTypesState, isLoading: true });
const alertTypes = await loadAlertTypes({ http });
const index: AlertTypeIndex = {};
for (const alertType of alertTypes) {
index[alertType.id] = alertType;
}
setAlertTypesIndex(index);
setAlertTypesState({ isLoading: false, data: index, isInitialized: true });
} catch (e) {
toastNotifications.addDanger({
title: i18n.translate(
'xpack.triggersActionsUI.sections.alertsList.unableToLoadAlertTypesMessage',
{ defaultMessage: 'Unable to load alert types' }
),
});
} finally {
setIsLoadingAlertTypes(false);
setAlertTypesState({ ...alertTypesState, isLoading: false });
}
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -104,23 +118,8 @@ export const AlertsList: React.FunctionComponent = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
// Avoid flickering before alert types load
if (typeof alertTypesIndex === 'undefined') {
return;
}
const updatedData = alerts.map(alert => ({
...alert,
tagsText: alert.tags.join(', '),
alertType: alertTypesIndex[alert.alertTypeId]
? alertTypesIndex[alert.alertTypeId].name
: alert.alertTypeId,
}));
setData(updatedData);
}, [alerts, alertTypesIndex]);

async function loadAlertsData() {
setIsLoadingAlerts(true);
setAlertsState({ ...alertsState, isLoading: true });
try {
const alertsResponse = await loadAlerts({
http,
Expand All @@ -129,8 +128,11 @@ export const AlertsList: React.FunctionComponent = () => {
typesFilter,
actionTypesFilter,
});
setAlerts(alertsResponse.data);
setTotalItemCount(alertsResponse.total);
setAlertsState({
isLoading: false,
data: alertsResponse.data,
totalItemCount: alertsResponse.total,
});
} catch (e) {
toastNotifications.addDanger({
title: i18n.translate(
Expand All @@ -140,8 +142,7 @@ export const AlertsList: React.FunctionComponent = () => {
}
),
});
} finally {
setIsLoadingAlerts(false);
setAlertsState({ ...alertsState, isLoading: false });
}
}

Expand Down Expand Up @@ -200,7 +201,7 @@ export const AlertsList: React.FunctionComponent = () => {
<TypeFilter
key="type-filter"
onChange={(types: string[]) => setTypesFilter(types)}
options={Object.values(alertTypesIndex || {})
options={Object.values(alertTypesState.data)
.map(alertType => ({
value: alertType.id,
name: alertType.name,
Expand Down Expand Up @@ -241,7 +242,10 @@ export const AlertsList: React.FunctionComponent = () => {
{selectedIds.length > 0 && canDelete && (
<EuiFlexItem grow={false}>
<BulkActionPopover
selectedItems={pickFromData(data, selectedIds)}
selectedItems={convertAlertsToTableItems(
filterAlertsById(alertsState.data, selectedIds),
alertTypesState.data
)}
onPerformingAction={() => setIsPerformingAction(true)}
onActionPerformed={() => {
loadAlertsData();
Expand Down Expand Up @@ -282,8 +286,13 @@ export const AlertsList: React.FunctionComponent = () => {
<EuiSpacer size="l" />

<EuiBasicTable
loading={isLoadingAlerts || isLoadingAlertTypes || isPerformingAction}
items={data}
loading={alertsState.isLoading || alertTypesState.isLoading || isPerformingAction}
/* Don't display alerts until we have the alert types initialized */
items={
alertTypesState.isInitialized === false
? []
: convertAlertsToTableItems(alertsState.data, alertTypesState.data)
}
itemId="id"
columns={alertsTableColumns}
rowProps={() => ({
Expand All @@ -296,7 +305,9 @@ export const AlertsList: React.FunctionComponent = () => {
pagination={{
pageIndex: page.index,
pageSize: page.size,
totalItemCount,
/* Don't display alert count until we have the alert types initialized */
totalItemCount:
alertTypesState.isInitialized === false ? 0 : alertsState.totalItemCount,
}}
selection={
canDelete
Expand All @@ -318,13 +329,14 @@ export const AlertsList: React.FunctionComponent = () => {
);
};

function pickFromData(data: AlertTableItem[], ids: string[]): AlertTableItem[] {
const result: AlertTableItem[] = [];
for (const id of ids) {
const match = data.find(item => item.id === id);
if (match) {
result.push(match);
}
}
return result;
function filterAlertsById(alerts: Alert[], ids: string[]): Alert[] {
return alerts.filter(alert => ids.includes(alert.id));
}

function convertAlertsToTableItems(alerts: Alert[], alertTypesIndex: AlertTypeIndex) {
return alerts.map(alert => ({
...alert,
tagsText: alert.tags.join(', '),
alertType: alertTypesIndex[alert.alertTypeId]?.name ?? alert.alertTypeId,
}));
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ export const CollapsedItemActions: React.FunctionComponent<ComponentOpts> = ({
const canDelete = hasDeleteAlertsCapability(capabilities.get());
const canSave = hasSaveAlertsCapability(capabilities.get());

const [isEnabled, setIsEnabled] = useState<boolean>(item.enabled);
const [isMuted, setIsMuted] = useState<boolean>(item.muteAll);
const [isPopoverOpen, setIsPopoverOpen] = useState<boolean>(false);

const button = (
Expand All @@ -72,14 +70,12 @@ export const CollapsedItemActions: React.FunctionComponent<ComponentOpts> = ({
<EuiSwitch
name="enable"
disabled={!canSave}
checked={isEnabled}
checked={item.enabled}
data-test-subj="enableSwitch"
onChange={async () => {
if (isEnabled) {
setIsEnabled(false);
if (item.enabled) {
await disableAlerts({ http, ids: [item.id] });
} else {
setIsEnabled(true);
await enableAlerts({ http, ids: [item.id] });
}
onAlertChanged();
Expand All @@ -95,15 +91,13 @@ export const CollapsedItemActions: React.FunctionComponent<ComponentOpts> = ({
<EuiFormRow>
<EuiSwitch
name="mute"
checked={isMuted}
disabled={!canSave || !isEnabled}
checked={item.muteAll}
disabled={!(canSave && item.enabled)}
data-test-subj="muteSwitch"
onChange={async () => {
if (isMuted) {
setIsMuted(false);
if (item.muteAll) {
await unmuteAlerts({ http, ids: [item.id] });
} else {
setIsMuted(true);
await muteAlerts({ http, ids: [item.id] });
}
onAlertChanged();
Expand Down
Loading

0 comments on commit 231ddfe

Please sign in to comment.