+ );
+
+ wrapper
+ .find(`.field-browser-category-pane-${notTheSelectedCategoryId}-${timelineId}`)
+ .first()
+ .simulate('click');
+
+ expect(onCategorySelected).toHaveBeenCalledWith(notTheSelectedCategoryId);
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/category_columns.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/category_columns.tsx
index b5bd86a55b83f..0cbf188a7f27f 100644
--- a/x-pack/legacy/plugins/siem/public/components/fields_browser/category_columns.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/category_columns.tsx
@@ -78,6 +78,7 @@ export const getCategoryColumns = ({
}) => [
{
field: 'categoryId',
+ name: '',
sortable: true,
truncateText: false,
render: (categoryId: string) => (
@@ -133,7 +134,7 @@ export const getCategoryColumns = ({
-
+
{getFieldCount(filteredBrowserFields[categoryId])}
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/category_title.test.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/category_title.test.tsx
new file mode 100644
index 0000000000000..d283a8aafab91
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/category_title.test.tsx
@@ -0,0 +1,72 @@
+/*
+ * 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 { mount } from 'enzyme';
+import * as React from 'react';
+import 'jest-styled-components';
+
+import { mockBrowserFields } from '../../containers/source/mock';
+
+import { CategoryTitle } from './category_title';
+import { getFieldCount } from './helpers';
+
+describe('CategoryTitle', () => {
+ const timelineId = 'test';
+
+ test('it renders the category id as the value of the title', () => {
+ const categoryId = 'client';
+ const wrapper = mount(
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="selected-category-title"]')
+ .first()
+ .text()
+ ).toEqual(categoryId);
+ });
+
+ test('when `categoryId` specifies a valid category in `filteredBrowserFields`, a count of the field is displayed in the badge', () => {
+ const validCategoryId = 'client';
+ const wrapper = mount(
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="selected-category-count-badge"]`)
+ .first()
+ .text()
+ ).toEqual(`${getFieldCount(mockBrowserFields[validCategoryId])}`);
+ });
+
+ test('when `categoryId` specifies an INVALID category in `filteredBrowserFields`, a count of zero is displayed in the badge', () => {
+ const invalidCategoryId = 'this.is.not.happening';
+ const wrapper = mount(
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="selected-category-count-badge"]`)
+ .first()
+ .text()
+ ).toEqual('0');
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/category_title.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/category_title.tsx
index ba84b2d90335e..a81f80334f1ac 100644
--- a/x-pack/legacy/plugins/siem/public/components/fields_browser/category_title.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/category_title.tsx
@@ -40,7 +40,7 @@ export const CategoryTitle = pure(({ filteredBrowserFields, categoryId, t
{categoryId}
@@ -49,7 +49,9 @@ export const CategoryTitle = pure(({ filteredBrowserFields, categoryId, t
- {getFieldCount(filteredBrowserFields[categoryId])}
+
+ {getFieldCount(filteredBrowserFields[categoryId])}
+
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_browser.test.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_browser.test.tsx
new file mode 100644
index 0000000000000..91b561a156f9e
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_browser.test.tsx
@@ -0,0 +1,259 @@
+/*
+ * 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 { mount } from 'enzyme';
+import * as React from 'react';
+
+import { mockBrowserFields } from '../../containers/source/mock';
+import { TestProviders } from '../../mock';
+
+import { FieldsBrowser } from './field_browser';
+import { FIELD_BROWSER_HEIGHT, FIELD_BROWSER_WIDTH } from './helpers';
+
+describe('FieldsBrowser', () => {
+ const timelineId = 'test';
+
+ // `enzyme` doesn't mount the components into the global jsdom `document`
+ // but that's where the click detector listener is, so for testing, we
+ // pass the top-level mounted component's click event on to document
+ const triggerDocumentMouseDown = () => {
+ const event = new Event('mousedown');
+ document.dispatchEvent(event);
+ };
+
+ const triggerDocumentMouseUp = () => {
+ const event = new Event('mouseup');
+ document.dispatchEvent(event);
+ };
+
+ test('it invokes onOutsideClick when onFieldSelected is undefined, and the user clicks outside the fields browser', () => {
+ const onOutsideClick = jest.fn();
+
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ wrapper.find('[data-test-subj="outside"]').simulate('mousedown');
+ wrapper.find('[data-test-subj="outside"]').simulate('mouseup');
+
+ expect(onOutsideClick).toHaveBeenCalled();
+ });
+
+ test('it does NOT invoke onOutsideClick when onFieldSelected is defined, and the user clicks outside the fields browser', () => {
+ const onOutsideClick = jest.fn();
+
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ wrapper.find('[data-test-subj="outside"]').simulate('mousedown');
+ wrapper.find('[data-test-subj="outside"]').simulate('mouseup');
+
+ expect(onOutsideClick).not.toHaveBeenCalled();
+ });
+
+ test('it renders the header', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="header"]').exists()).toBe(true);
+ });
+
+ test('it renders the categories pane', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="left-categories-pane"]').exists()).toBe(true);
+ });
+
+ test('it renders the fields pane', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find('[data-test-subj="fields-pane"]').exists()).toBe(true);
+ });
+
+ test('focuses the search input when the component mounts', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="field-search"]')
+ .first()
+ .getDOMNode().id === document.activeElement!.id
+ ).toBe(true);
+ });
+
+ test('it invokes onSearchInputChange when the user types in the field search input', () => {
+ const onSearchInputChange = jest.fn();
+ const inputText = 'event.category';
+
+ const wrapper = mount(
+
+
+
+ );
+
+ const searchField = wrapper.find('[data-test-subj="field-search"]').first();
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const changeEvent: any = { target: { value: inputText } };
+ const onChange = searchField.props().onChange;
+
+ onChange!(changeEvent);
+ searchField.simulate('change').update();
+
+ expect(onSearchInputChange).toBeCalledWith(inputText);
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_browser.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_browser.tsx
index c2c878f6585a8..1453ab56e3df6 100644
--- a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_browser.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_browser.tsx
@@ -25,7 +25,7 @@ import { Header } from './header';
import { CategoriesPane } from './categories_pane';
import { FieldsPane } from './fields_pane';
-const TOP_OFFSET = 207;
+const TOP_OFFSET = 267;
const FieldsBrowserContainer = styled.div<{
top: number;
@@ -148,6 +148,7 @@ export class FieldsBrowser extends React.PureComponent {
width={width}
>
{
+ const timelineId = 'test';
+
+ describe('getFieldItems', () => {
+ Object.keys(selectedCategoryFields!).forEach(fieldId => {
+ test(`it renders the name of the ${fieldId} field`, () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="field-name-${fieldId}"]`)
+ .first()
+ .text()
+ ).toEqual(fieldId);
+ });
+ });
+
+ Object.keys(selectedCategoryFields!).forEach(fieldId => {
+ test(`it renders a checkbox for the ${fieldId} field`, () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="field-${fieldId}-checkbox"]`)
+ .first()
+ .exists()
+ ).toBe(true);
+ });
+ });
+
+ test('it renders a checkbox in the checked state when the field is selected to be displayed as a column in the timeline', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="field-${timestampFieldId}-checkbox"]`)
+ .first()
+ .props().checked
+ ).toBe(true);
+ });
+
+ test('it does NOT render a checkbox in the checked state when the field is NOT selected to be displayed as a column in the timeline', () => {
+ const wrapper = mount(
+
+ header.id !== timestampFieldId),
+ highlight: '',
+ isLoading: false,
+ onUpdateColumns: jest.fn(),
+ timelineId,
+ toggleColumn: jest.fn(),
+ })}
+ width={FIELDS_PANE_WIDTH}
+ onCategorySelected={jest.fn()}
+ timelineId={timelineId}
+ />
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="field-${timestampFieldId}-checkbox"]`)
+ .first()
+ .props().checked
+ ).toBe(false);
+ });
+
+ test('it invokes `toggleColumn` when the user interacts with the checkbox', () => {
+ const toggleColumn = jest.fn();
+
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper
+ .find('input[type="checkbox"]')
+ .first()
+ .simulate('change', {
+ target: { checked: true },
+ });
+ wrapper.update();
+
+ expect(toggleColumn).toBeCalledWith({
+ columnHeaderType: 'not-filtered',
+ id: '@timestamp',
+ width: 180,
+ });
+ });
+
+ test('it renders the expected icon for a field', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="field-${timestampFieldId}-icon"]`)
+ .first()
+ .props().type
+ ).toEqual('clock');
+ });
+
+ test('it renders the expected field description', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="field-${timestampFieldId}-description"]`)
+ .first()
+ .text()
+ ).toEqual(
+ 'Date/time when the event originated. For log events this is the date/time when the event was generated, and not when it was read. Required field for all events. Example: 2016-05-23T08:05:34.853Z'
+ );
+ });
+ });
+
+ describe('getFieldColumns', () => {
+ test('it returns the expected column definitions', () => {
+ expect(getFieldColumns().map(column => omit('render', column))).toEqual([
+ { field: 'field', name: 'Field', sortable: true, width: '250px' },
+ {
+ field: 'description',
+ name: 'Description',
+ sortable: true,
+ truncateText: true,
+ width: '400px',
+ },
+ ]);
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_items.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_items.tsx
index 8b8758facbe8e..068c545721c38 100644
--- a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_items.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_items.tsx
@@ -36,6 +36,13 @@ const TypeIcon = styled(EuiIcon)`
TypeIcon.displayName = 'TypeIcon';
+export const Description = styled.span`
+ user-select: text;
+ width: 150px;
+`;
+
+Description.displayName = 'Description';
+
/**
* An item rendered in the table
*/
@@ -73,8 +80,8 @@ export const getFieldItems = ({
...Object.values(category != null && category.fields != null ? category.fields : {}),
]).map(field => ({
description: (
-
- {`${field.description || getEmptyValue()} ${getExampleText(field.example)}`}{' '}
+
+ {`${field.description || getEmptyValue()} ${getExampleText(field.example)}`}
),
field: (
@@ -107,22 +114,28 @@ export const getFieldItems = ({
{!snapshot.isDragging ? (
- c.id === field.name) !== -1}
- id={field.name || ''}
- onChange={() =>
- toggleColumn({
- columnHeaderType: defaultColumnHeaderType,
- id: field.name || '',
- width: DEFAULT_COLUMN_MIN_WIDTH,
- })
- }
- />
+
+ c.id === field.name) !== -1}
+ data-test-subj={`field-${field.name}-checkbox`}
+ id={field.name || ''}
+ onChange={() =>
+ toggleColumn({
+ columnHeaderType: defaultColumnHeaderType,
+ id: field.name || '',
+ width: DEFAULT_COLUMN_MIN_WIDTH,
+ })
+ }
+ />
+
-
+
@@ -170,7 +183,7 @@ export const getFieldColumns = () => [
name: i18n.DESCRIPTION,
render: (description: string) => (
-
+
{description}
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_name.test.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_name.test.tsx
new file mode 100644
index 0000000000000..afca98b70a625
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_name.test.tsx
@@ -0,0 +1,152 @@
+/*
+ * 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 { mount } from 'enzyme';
+import * as React from 'react';
+
+import { mockBrowserFields } from '../../containers/source/mock';
+import { TestProviders } from '../../mock';
+import { getColumnsWithTimestamp } from '../event_details/helpers';
+
+import { FieldName } from './field_name';
+
+const categoryId = 'base';
+const timestampFieldId = '@timestamp';
+
+describe('FieldName', () => {
+ test('it renders the field name', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="field-name-${timestampFieldId}"]`)
+ .first()
+ .text()
+ ).toEqual(timestampFieldId);
+ });
+
+ test('it renders a copy to clipboard action menu item a user hovers over the name', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper.simulate('mouseenter');
+ wrapper.update();
+ expect(wrapper.find('[data-test-subj="copy-to-clipboard"]').exists()).toBe(true);
+ });
+
+ test('it renders a view category action menu item a user hovers over the name', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper.simulate('mouseenter');
+ wrapper.update();
+ expect(wrapper.find('[data-test-subj="view-category"]').exists()).toBe(true);
+ });
+
+ test('it invokes onUpdateColumns when the view category action menu item is clicked', () => {
+ const onUpdateColumns = jest.fn();
+
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper.simulate('mouseenter');
+ wrapper.update();
+ wrapper
+ .find('[data-test-subj="view-category"]')
+ .first()
+ .simulate('click');
+
+ expect(onUpdateColumns).toBeCalledWith([
+ {
+ aggregatable: true,
+ category: 'base',
+ columnHeaderType: 'not-filtered',
+ description:
+ 'Date/time when the event originated. For log events this is the date/time when the event was generated, and not when it was read. Required field for all events.',
+ example: '2016-05-23T08:05:34.853Z',
+ id: '@timestamp',
+ type: 'date',
+ width: 240,
+ },
+ ]);
+ });
+
+ test('it highlights the text specified by the `highlight` prop', () => {
+ const highlight = 'stamp';
+
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('strong')
+ .first()
+ .text()
+ ).toEqual(highlight);
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_name.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_name.tsx
index 0661d456a25b6..1e2fe28b811d4 100644
--- a/x-pack/legacy/plugins/siem/public/components/fields_browser/field_name.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/field_name.tsx
@@ -83,7 +83,11 @@ export const FieldName = pure<{
>
-
+
@@ -94,6 +98,7 @@ export const FieldName = pure<{
{
onUpdateColumns(categoryColumns);
}}
@@ -110,7 +115,9 @@ export const FieldName = pure<{
}
render={() => (
- {fieldId}
+
+ {fieldId}
+
)}
/>
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/fields_pane.test.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/fields_pane.test.tsx
new file mode 100644
index 0000000000000..3be4fd356ee2d
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/fields_pane.test.tsx
@@ -0,0 +1,134 @@
+/*
+ * 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 { mount } from 'enzyme';
+import * as React from 'react';
+
+import { mockBrowserFields } from '../../containers/source/mock';
+import { TestProviders } from '../../mock';
+
+import { FIELDS_PANE_WIDTH } from './helpers';
+import { FieldsPane } from './fields_pane';
+
+const timelineId = 'test';
+
+describe('FieldsPane', () => {
+ test('it renders the selected category', () => {
+ const selectedCategory = 'auditd';
+
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="selected-category-title"]`)
+ .first()
+ .text()
+ ).toEqual(selectedCategory);
+ });
+
+ test('it renders a unknown category that does not exist in filteredBrowserFields', () => {
+ const selectedCategory = 'unknown';
+
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="selected-category-title"]`)
+ .first()
+ .text()
+ ).toEqual(selectedCategory);
+ });
+
+ test('it renders the expected message when `filteredBrowserFields` is empty and `searchInput` is empty', () => {
+ const searchInput = '';
+
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="no-fields-match"]`)
+ .first()
+ .text()
+ ).toEqual('No fields match ');
+ });
+
+ test('it renders the expected message when `filteredBrowserFields` is empty and `searchInput` is an unknown field name', () => {
+ const searchInput = 'thisFieldDoesNotExist';
+
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="no-fields-match"]`)
+ .first()
+ .text()
+ ).toEqual(`No fields match ${searchInput}`);
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/header.test.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/header.test.tsx
new file mode 100644
index 0000000000000..7e36a028961c4
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/header.test.tsx
@@ -0,0 +1,298 @@
+/*
+ * 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 { mount } from 'enzyme';
+import * as React from 'react';
+
+import { mockBrowserFields } from '../../containers/source/mock';
+import { TestProviders } from '../../mock';
+import { defaultHeaders } from '../timeline/body/column_headers/default_headers';
+
+import { Header } from './header';
+
+const timelineId = 'test';
+
+describe('Header', () => {
+ test('it renders the field browser title', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="field-browser-title"]')
+ .first()
+ .text()
+ ).toEqual('Customize Columns');
+ });
+
+ test('it renders the Reset Fields button', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="reset-fields"]')
+ .first()
+ .text()
+ ).toEqual('Reset Fields');
+ });
+
+ test('it invokes onUpdateColumns when the user clicks the Reset Fields button', () => {
+ const onUpdateColumns = jest.fn();
+
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper
+ .find('[data-test-subj="reset-fields"]')
+ .first()
+ .simulate('click');
+
+ expect(onUpdateColumns).toBeCalledWith(defaultHeaders);
+ });
+
+ test('it invokes onOutsideClick when the user clicks the Reset Fields button', () => {
+ const onOutsideClick = jest.fn();
+
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper
+ .find('[data-test-subj="reset-fields"]')
+ .first()
+ .simulate('click');
+
+ expect(onOutsideClick).toBeCalled();
+ });
+
+ test('it renders the field search input with the expected placeholder text when the searchInput prop is empty', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="field-search"]')
+ .first()
+ .props().placeholder
+ ).toEqual('Field name');
+ });
+
+ test('it renders the "current" search value in the input when searchInput is not empty', () => {
+ const searchInput = 'aFieldName';
+
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(wrapper.find('input').props().value).toEqual(searchInput);
+ });
+
+ test('it renders the field search input with a spinner when isSearching is true', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('.euiLoadingSpinner')
+ .first()
+ .exists()
+ ).toBe(true);
+ });
+
+ test('it invokes onSearchInputChange when the user types in the search field', () => {
+ const onSearchInputChange = jest.fn();
+
+ const wrapper = mount(
+
+
+
+ );
+
+ wrapper
+ .find('input')
+ .first()
+ .simulate('change', { target: { value: 'timestamp' } });
+ wrapper.update();
+
+ expect(onSearchInputChange).toBeCalled();
+ });
+
+ test('it returns the expected categories count when filteredBrowserFields is empty', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="categories-count"]')
+ .first()
+ .text()
+ ).toEqual('0 categories');
+ });
+
+ test('it returns the expected categories count when filteredBrowserFields is NOT empty', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="categories-count"]')
+ .first()
+ .text()
+ ).toEqual('9 categories');
+ });
+
+ test('it returns the expected fields count when filteredBrowserFields is empty', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="fields-count"]')
+ .first()
+ .text()
+ ).toEqual('0 fields');
+ });
+
+ test('it returns the expected fields count when filteredBrowserFields is NOT empty', () => {
+ const wrapper = mount(
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find('[data-test-subj="fields-count"]')
+ .first()
+ .text()
+ ).toEqual('25 fields');
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/fields_browser/header.tsx b/x-pack/legacy/plugins/siem/public/components/fields_browser/header.tsx
index 24368ba4847e5..76d4f0c4b12e2 100644
--- a/x-pack/legacy/plugins/siem/public/components/fields_browser/header.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/fields_browser/header.tsx
@@ -100,13 +100,14 @@ const TitleRow = pure<{ onOutsideClick: () => void; onUpdateColumns: OnUpdateCol
gutterSize="none"
>
-
+