Skip to content

Commit

Permalink
[Fleet] Fix agent details page for agents without components (#160134)
Browse files Browse the repository at this point in the history
## Summary

Fix a bug in the health reporting UI change in
#158826 where the page breaks when
the agent has no components.

Closes #159975

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
jillguyonnet and kibanamachine authored Jun 22, 2023
1 parent 5fd4db8 commit 74ba8c5
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';

import { ThemeProvider } from 'styled-components';

import type { Agent } from '../../../../../types';
import { useLink } from '../../../../../hooks';
import { createPackagePolicyMock } from '../../../../../../../../common/mocks';

import { AgentDetailsIntegrationInputs } from './agent_details_integration_inputs';

jest.mock('../../../../../hooks');
const mockUseLink = useLink as jest.Mock;

describe('AgentDetailsIntegrationInputs', () => {
const agent: Agent = {
id: '123',
packages: [],
type: 'PERMANENT',
active: true,
enrolled_at: `${Date.now()}`,
user_provided_metadata: {},
local_metadata: {},
};

const packageMock = createPackagePolicyMock();

beforeEach(() => {
mockUseLink.mockReturnValue({ getHref: jest.fn() });
});

const renderComponent = () => {
return render(
<IntlProvider locale="en">
<ThemeProvider theme={() => ({ eui: { euiSizeS: '15px' } })}>
<AgentDetailsIntegrationInputs agent={agent} packagePolicy={packageMock} />
</ThemeProvider>
</IntlProvider>
);
};

it('renders a default health icon when the agent has no components at all', () => {
const component = renderComponent();
userEvent.click(component.getByTestId('agentIntegrationsInputsTitle'));
expect(
component.getByTestId('agentDetailsIntegrationsInputStatusHealthDefault')
).toBeInTheDocument();
});

it('renders a default health icon when the package input has no match in the agent component units', () => {
agent.components = [
{
id: 'endpoint-default',
type: 'endpoint',
status: 'HEALTHY',
message: 'Healthy',
units: [
{
id: 'endpoint-default',
type: 'input',
status: 'HEALTHY',
message: 'Applied policy',
},
],
},
];

const component = renderComponent();
userEvent.click(component.getByTestId('agentIntegrationsInputsTitle'));
expect(
component.getByTestId('agentDetailsIntegrationsInputStatusHealthDefault')
).toBeInTheDocument();
});

it('renders a success health icon when the package input has a match in the agent component units', () => {
agent.components = [
{
id: 'endpoint-default',
type: 'endpoint',
status: 'HEALTHY',
message: 'Healthy',
units: [
{
id: `endpoint-default-${packageMock.id}`,
type: 'input',
status: 'HEALTHY',
message: 'Applied policy',
},
],
},
];

const component = renderComponent();
userEvent.click(component.getByTestId('agentIntegrationsInputsTitle'));
expect(
component.getByTestId('agentDetailsIntegrationsInputStatusHealthSuccess')
).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -94,31 +94,39 @@ export const AgentDetailsIntegrationInputs: React.FunctionComponent<{

const getInputStatusIcon = (inputType: string) => {
const inputStatus = inputStatusMap.get(inputType)!;
if (inputStatus.status === undefined) {
if (inputStatus?.status === undefined) {
return (
<EuiHealth
color="default"
data-test-subj="xpack.fleet.agentDetailsIntegrations.inputStatusSuccessHealth"
data-test-subj="agentDetailsIntegrationsInputStatusHealthDefault"
className="inputStatusHealth"
/>
);
}
return inputStatus.status === 'HEALTHY' ? (
<EuiHealth
color="success"
data-test-subj="xpack.fleet.agentDetailsIntegrations.inputStatusSuccessHealth"
data-test-subj="agentDetailsIntegrationsInputStatusHealthSuccess"
className="inputStatusHealth"
/>
) : (
<EuiNotificationBadge data-test-subj="xpack.fleet.agentDetailsIntegrations.inputStatusAttentionHealth">
<EuiNotificationBadge data-test-subj="agentDetailsIntegrationsInputStatusAttentionHealth">
{1}
</EuiNotificationBadge>
);
};

const generateInputReponse = () => {
const generateInputResponse = () => {
return packagePolicy.inputs.reduce(
(acc: Array<{ label: JSX.Element; id: string }>, current) => {
(
acc: Array<{
label: JSX.Element;
id: string;
icon: JSX.Element;
children: Array<{ label: JSX.Element; id: string }>;
}>,
current
) => {
if (current.enabled) {
return [
...acc,
Expand Down Expand Up @@ -196,7 +204,7 @@ export const AgentDetailsIntegrationInputs: React.FunctionComponent<{
{inputsTotalErrors}
</EuiNotificationBadge>
) : undefined,
children: generateInputReponse(),
children: generateInputResponse(),
},
];
};
Expand Down

0 comments on commit 74ba8c5

Please sign in to comment.