diff --git a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx index 14cdc26c80f53..43a03bb771501 100644 --- a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx +++ b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx @@ -175,14 +175,24 @@ export class Simulator { } /** - * Return an Enzyme ReactWrapper for any child elements of a specific processNodeElement - * - * @param entityID The entity ID of the proocess node to select in - * @param selector The selector for the child element of the process node + * The button that opens a node's submenu. */ - public processNodeChildElements(entityID: string, selector: string): ReactWrapper { + public processNodeSubmenuButton( + /** nodeID for the related node */ entityID: string + ): ReactWrapper { return this.domNodes( - `${processNodeElementSelector({ entityID })} [data-test-subj="${selector}"]` + `[data-test-subj="resolver:submenu:button"][data-test-resolver-node-id="${entityID}"]` + ); + } + + /** + * The primary button (used to select a node) which contains a label for the node as its content. + */ + public processNodePrimaryButton( + /** nodeID for the related node */ entityID: string + ): ReactWrapper { + return this.domNodes( + `[data-test-subj="resolver:node:primary-button"][data-test-resolver-node-id="${entityID}"]` ); } diff --git a/x-pack/plugins/security_solution/public/resolver/view/clickthrough.test.tsx b/x-pack/plugins/security_solution/public/resolver/view/clickthrough.test.tsx index 09fcd273a9c9b..3265ee8bcfca0 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/clickthrough.test.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/clickthrough.test.tsx @@ -62,13 +62,13 @@ describe('Resolver, when analyzing a tree that has no ancestors and 2 children', selectedOriginCount: simulator.selectedProcessNode(entityIDs.origin).length, unselectedFirstChildCount: simulator.unselectedProcessNode(entityIDs.firstChild).length, unselectedSecondChildCount: simulator.unselectedProcessNode(entityIDs.secondChild).length, - processNodeCount: simulator.processNodeElements().length, + nodePrimaryButtonCount: simulator.testSubject('resolver:node:primary-button').length, })) ).toYieldEqualTo({ selectedOriginCount: 1, unselectedFirstChildCount: 1, unselectedSecondChildCount: 1, - processNodeCount: 3, + nodePrimaryButtonCount: 3, }); }); @@ -82,13 +82,14 @@ describe('Resolver, when analyzing a tree that has no ancestors and 2 children', }); describe("when the second child node's first button has been clicked", () => { - beforeEach(() => { - // Click the first button under the second child element. - simulator - .processNodeElements({ entityID: entityIDs.secondChild }) - .find('button') - .first() - .simulate('click'); + beforeEach(async () => { + const button = await simulator.resolveWrapper(() => + simulator.processNodePrimaryButton(entityIDs.secondChild) + ); + // Click the second child node's primary button + if (button) { + button.simulate('click'); + } }); it('should render the second child node as selected, and the origin as not selected, and the query string should indicate that the second child is selected', async () => { await expect( @@ -141,23 +142,20 @@ describe('Resolver, when analyzing a tree that has two related events for the or graphElements: simulator.testSubject('resolver:graph').length, graphLoadingElements: simulator.testSubject('resolver:graph:loading').length, graphErrorElements: simulator.testSubject('resolver:graph:error').length, - originNode: simulator.processNodeElements({ entityID: entityIDs.origin }).length, + originNodeButton: simulator.processNodePrimaryButton(entityIDs.origin).length, })) ).toYieldEqualTo({ graphElements: 1, graphLoadingElements: 0, graphErrorElements: 0, - originNode: 1, + originNodeButton: 1, }); }); it('should render a related events button', async () => { await expect( simulator.map(() => ({ - relatedEventButtons: simulator.processNodeChildElements( - entityIDs.origin, - 'resolver:submenu:button' - ).length, + relatedEventButtons: simulator.processNodeSubmenuButton(entityIDs.origin).length, })) ).toYieldEqualTo({ relatedEventButtons: 1, @@ -166,7 +164,7 @@ describe('Resolver, when analyzing a tree that has two related events for the or describe('when the related events button is clicked', () => { beforeEach(async () => { const button = await simulator.resolveWrapper(() => - simulator.processNodeChildElements(entityIDs.origin, 'resolver:submenu:button') + simulator.processNodeSubmenuButton(entityIDs.origin) ); if (button) { button.simulate('click'); @@ -183,7 +181,7 @@ describe('Resolver, when analyzing a tree that has two related events for the or describe('and when the related events button is clicked again', () => { beforeEach(async () => { const button = await simulator.resolveWrapper(() => - simulator.processNodeChildElements(entityIDs.origin, 'resolver:submenu:button') + simulator.processNodeSubmenuButton(entityIDs.origin) ); if (button) { button.simulate('click'); diff --git a/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx b/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx index 2a5d91028d9f5..2bb104801866f 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx @@ -404,6 +404,8 @@ const UnstyledProcessEventDot = React.memo( }} tabIndex={-1} title={eventModel.processNameSafeVersion(event)} + data-test-subj="resolver:node:primary-button" + data-test-resolver-node-id={nodeID} > @@ -433,6 +435,7 @@ const UnstyledProcessEventDot = React.memo( menuTitle={subMenuAssets.relatedEvents.title} projectionMatrix={projectionMatrix} optionsWithActions={relatedEventStatusOrOptions} + nodeID={nodeID} /> )} diff --git a/x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts b/x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts index 26c25cfab2c21..a86237e0e2b45 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts +++ b/x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts @@ -34,12 +34,12 @@ describe('Resolver, when analyzing a tree that has no ancestors and 2 children', describe("when the second child node's first button has been clicked", () => { beforeEach(async () => { - const node = await simulator.resolveWrapper(() => - simulator.processNodeElements({ entityID: entityIDs.secondChild }).find('button') + const button = await simulator.resolveWrapper(() => + simulator.processNodePrimaryButton(entityIDs.secondChild) ); - if (node) { + if (button) { // Click the first button under the second child element. - node.first().simulate('click'); + button.simulate('click'); } }); const expectedSearch = urlSearch(resolverComponentInstanceID, { @@ -68,12 +68,12 @@ describe('Resolver, when analyzing a tree that has no ancestors and 2 children', }); describe("when the user clicks the second child node's button again", () => { beforeEach(async () => { - const node = await simulator.resolveWrapper(() => - simulator.processNodeElements({ entityID: entityIDs.secondChild }).find('button') + const button = await simulator.resolveWrapper(() => + simulator.processNodePrimaryButton(entityIDs.secondChild) ); - if (node) { + if (button) { // Click the first button under the second child element. - node.first().simulate('click'); + button.simulate('click'); } }); it(`should have a url search of ${urlSearch(newInstanceID, { diff --git a/x-pack/plugins/security_solution/public/resolver/view/submenu.tsx b/x-pack/plugins/security_solution/public/resolver/view/submenu.tsx index 359a4e2dafd2e..14d6470c95207 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/submenu.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/submenu.tsx @@ -137,6 +137,7 @@ const NodeSubMenuComponents = React.memo( optionsWithActions, className, projectionMatrix, + nodeID, }: { menuTitle: string; className?: string; @@ -148,6 +149,7 @@ const NodeSubMenuComponents = React.memo( * Receive the projection matrix, so we can see when the camera position changed, so we can force the submenu to reposition itself. */ projectionMatrix: Matrix3; + nodeID: string; } & { optionsWithActions?: ResolverSubmenuOptionList | string | undefined; }) => { @@ -236,6 +238,7 @@ const NodeSubMenuComponents = React.memo( iconSide="right" tabIndex={-1} data-test-subj="resolver:submenu:button" + data-test-resolver-node-id={nodeID} > {count ? : ''} {menuTitle}