-
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
[Security Solution][Resolver] Graph Control Tests and Update Simulator Selectors #74680
[Security Solution][Resolver] Graph Control Tests and Update Simulator Selectors #74680
Conversation
Pinging @elastic/endpoint-app-team (Feature:Resolver) |
Pinging @elastic/endpoint-data-visibility-team (Team:Endpoint Data Visibility) |
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.
thanks for the PR. tests look good. put in a few suggestions
* This manually runs the animation frames tied to a configurable timestamp in the future | ||
*/ | ||
public runAnimationFramesTimeFromNow(time: number = 0) { | ||
this.sideEffectSimulator.controls.time = new Date().getTime() + time; |
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.
this.sideEffectSimulator.controls.time = new Date().getTime() + time; | |
this.sideEffectSimulator.controls.time = time; |
new Date
isn't needed here.
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.
thx, done
/** | ||
* Simulator which allows you to explicitly simulate resize events and trigger animation frames | ||
*/ | ||
public readonly sideEffectSimulator: SideEffectSimulator; |
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.
public readonly sideEffectSimulator: SideEffectSimulator; | |
private readonly sideEffectSimulator: SideEffectSimulator; |
This could be private
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.
done
const originNode = simulator.processNodeElements({ entityID: originEntityID }); | ||
expect(originNode.getDOMNode()).toHaveStyle(originalPositionStyle); | ||
|
||
const westPanButton = simulator.graphControlElement().find('[data-test-subj="west-button"]'); |
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.
would you mind changing this data-test-subj to use the same format as the others?
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('should load graph controls', () => { | ||
expect(simulator.graphControlElement().length).toBe(1); |
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.
This test might not be needed. The existence of a wrapper element isn't important to the AC of any feature and its specific to the implementation details. Maybe check that the 4 buttons exist instead?
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.
Yea, I checked for the existence of all the functional buttons instead
expect(originNode.getDOMNode()).toHaveStyle({ left: '796.93132px', top: '535.5792px' }); | ||
}); | ||
|
||
it('should pan south', async () => { |
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.
could you phrase the spec like:
describe('when the user clicks the south panning button', () => {
beforeEach(/* the click code does here*/)
it('should show the origin node lower on the screen', () => {
// the expect here
This way we can easily add more it
blocks that have the same setup and we can easily tell which code sets up the condition vs which code asserts stuff
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.
Yea, this works really well. Thanks for the tip 👍
it('should display all cardinal panning buttons and the center button', () => { | ||
const westPanButton = simulator | ||
.graphControlElement() | ||
.find('[data-test-subj="resolver:graph-controls:west-button"]'); |
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.
.find
will return react components as well as DOM nodes. In order to test the DOM only you need to use domNodes
: https://github.com/elastic/kibana/blob/master/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx#L246
Would you consider using that instead?
Also, these tests would be more resilient to change if you use .map
. As it is, these pass because Resolver shows the controls immediately on the first render. If we (for example) made the controls show up after data had loaded then these tests would likely fail. They might even fail now if you make the mock data access layer resolve the API calls in the next event-loop cycle.
For that reason, would you consider using .map
?
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.
Or consider resolveWrapper
(uses map
indirectly)
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.
Yea, I forgot about that concern when I wrote this tbh. Updated and refactored to use .map
and domNodes
. Thanks!
@elasticmachine merge upstream |
merge conflict between base and head |
621a823
to
cf33fd5
Compare
}); | ||
|
||
it('should show the origin node further left on the screen', async () => { | ||
expect(originNode.getDOMNode()).toHaveStyle({ left: '796.93132px', top: '535.5792px' }); |
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.
I think this is fine to merge but long term I have some concerns:
This test relies on react to keep the same DOM node for the origin after the user clicks the pan element. If that component got a new DOM node for some reason then originNode
would point to an old element that may not be in the DOM any more.
Also this relies on the react code to update the style of the element in the same event loop cycle when the user clicks the panning button.
I think we should use the pattern of calling expect
on an async iterable. How about I make those changes after you merge?
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.
@michaelolo24 Here's a commit with my ideas: 3de7be9
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.
Thanks, cherry-picked it in and updated the selectors based on our zoom meeting
@elasticmachine merge upstream |
db589d3
to
e782753
Compare
@elasticmachine merge upstream |
…s before use. use yield-equal-to pattern in graph control tests. change graph control spec language
07a5ce1
to
505a348
Compare
* @param entityID The entity ID of the proocess node to select in | ||
* @param selector The selector for the child element of the process node | ||
*/ | ||
public processNodeChildElements(entityID: string, selector: string): ReactWrapper { |
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.
@bkimmel, thoughts? I wanted to generalize your method a bit for any other buttons or things that might be added to the process node in the future
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 good, generally. Two points:
- The parameter isn't really a
selector
(it only feeds the data-test-subj attrib). So I'd say adjust the comment. - To make that even more clear, you could put a "ByDataTestSubj" at the end of the method name (but that's awful long)
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.
Yea, we can talk about these patterns later today as well. Gonna merge this for now
await expect( | ||
simulator.map(() => simulator.testSubject('resolver:node-list:node-link:title').length) | ||
).toYieldEqualTo(3); | ||
await expect( |
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.
seems this is duplicated
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.
oh i see. the old version had an expect for 'text' and an expect for 'icons'
@@ -147,7 +151,10 @@ describe('Resolver, when analyzing a tree that has two related events for the or | |||
it('should render a related events button', async () => { | |||
await expect( | |||
simulator.map(() => ({ | |||
relatedEventButtons: simulator.processNodeRelatedEventButton(entityIDs.origin).length, | |||
relatedEventButtons: simulator.processNodeChildElements( |
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.
Whats the purpose of the special treatment here?
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.
Same as below. Retain the original intention here. I could move all of the actual selector
string into this test or maybe even export the processNodeElementSelector
and build the string at this level. Alternatively, I could tie the actual selector with the associated entity-id
(see below comment)
@@ -156,33 +163,35 @@ 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.processNodeRelatedEventButton(entityIDs.origin) | |||
simulator.processNodeChildElements(entityIDs.origin, 'resolver:submenu:button') |
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.
why not just testSubject
here? This couples the test to DOM structure. Is there a reason?
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.
I was just doing a one to one replacement that generalized this test a bit more. The only way to really not have this tied to the structure of the DOM would be to replace the resolver:submenu:button
with a reference to the entity-id
, maybe resolver:node-${entityID}:submenu:button
. Is that what you're suggesting?
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.
Oh I see what you mean. I wasn't necessarily suggesting anything but here's my thoughts:
- The user doesn't care about the DOM structure and so if we don't rely on it our tests will be less brittle.
- It would be cool if we are only coupled to data-test attributes. That should make it simple to keep tests working. If we remove a wrapper div, I would hope that no tests break.
Maybe at our next office hours we can discuss those ideas more.
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.
I think there is some semantic weight to. e.g. the button being a child / ("owned by" in the case of semantics) of the process node. I say keep it as is.
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.
Or to put it another way: If the relationship between the node and the interactive element it's expected to contain changes in some way, I think it's good that a test picks that up.
💚 Build SucceededBuild metricsasync chunks size
History
To update your PR or re-run it, just comment with: |
|
||
it('should show the origin node as larger on the screen', async () => { | ||
await expect(originNodeStyle()).toYieldObjectEqualTo({ | ||
width: '427.7538290724795px', |
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.
ℹ️ this comes from the yarn snapshot deal?
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.
yep
> | ||
<EuiPanel className="panning-controls" paddingSize="none" hasShadow> | ||
<div className="panning-controls-top"> | ||
<button | ||
className="north-button" | ||
data-test-subj="north-button" | ||
data-test-subj="resolver:graph-controls:north-button" | ||
title="North" |
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.
🎗️ later to fix these to better things like "Pan the scene up" or something. North is not a good description for what this does.
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.
Yea, we can talk about this during office hours :)
…r Selectors (elastic#74680) Co-authored-by: oatkiller <robert.austin@elastic.co> # Conflicts: # x-pack/plugins/security_solution/public/resolver/view/clickthrough.test.tsx
* master: (23 commits) Adding API test for custom link transaction example (elastic#74238) [Uptime] Singular alert (elastic#74659) Revert "attempt excluding a codeowners directory" (elastic#75023) [Metrics UI] Remove TSVB dependency from Metrics Explorer APIs (elastic#74804) Remove degraded state from ES status service (elastic#75007) [Reporting/Functional] unskip pagination test (elastic#74973) [Resolver] Stale query string values are removed when resolver's component instance ID changes. (elastic#74979) Add public url to Workplace Search plugin (elastic#74991) [Reporting] Update more Server Types for TaskManager (elastic#74915) [I18n] verify select icu-message options are in english (elastic#74963) Make data.search.aggs available on the server. (elastic#74472) [Security Solution][Resolver] Graph Control Tests and Update Simulator Selectors (elastic#74680) attempt excluding a codeowners directory [ML] DF Analytics: allow failed job to be stopped by force via the UI (elastic#74710) Add kibana-core-ui-designers team (elastic#74970) [Metrics UI] Fix inventory footer misalignment (elastic#74707) Remove legacy optimizer (elastic#73154) Update design-specific GH code-owners (elastic#74877) skip test Reporting paginates content elastic#74922 [Metrics UI] Add Jest tests for alert previews (elastic#74890) ...
Summary
Adds tests for the graph panning and zoom controls
Checklist