-
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
[Resolver] simulator tests select elements directly instead of using descendant selectors. #75058
Conversation
*/ | ||
public processNodeChildElements(entityID: string, selector: string): ReactWrapper { | ||
public processNodeSubmenuButton( |
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 no longer relies on the DOM structure.
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.
Cool, I wonder if it's better to just remove this method entirely to just use the testSubject
and make the processNodeSubmenuButton
a separate utility function? Only rationale is keeping the simulator as generic as possible. so you would have something like expect(simulator().testSubject(processNodeSubmenuButton(entityId))).toBe(blah)
...then again that looks a bit gross 🤷♂️
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 actually considered this, but the testSubject
method takes just a single test subject string while processNodeSubmenuButton
involves two data-attribute selectors.
I also considered packing all of the info we need into the data-test-subj
attribute.
I wasn't 100% on either of those, but I think this PR is still an improvement.
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, it can really go either way. We could have testSubject take an options obj that builds the selector based on what's defined a la your processNodeElementSelector
. So testSubject would now take the following
{
dataTestSubj: string,
dataTestResolverNodeId: string,
...potentially any other future options
}
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.
yah that might work. I first want to discuss this topic: is it important that the buttons are descendants of the node's wrapper <div />
. Having methods like processNodeSubmenuButton
provides a level of abstraction that will allow us to easily change our mind on that. In this PR it selects an element using two attribute selectors. If we decide that the DOM structure does matter then we could change that to use a descendant selector.
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 seems to be resolved by @bkimmel's comment below. Thanks
/** | ||
* The primary button (used to select a node) which contains a label for the node as its content. | ||
*/ | ||
public processNodePrimaryButton( |
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.
Node's have 2 buttons, one to select it, one to open its submenu. This is the one that selects it.
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 comment as above, but if we decide to stay this route, would a name like processNodeShowDetailsButton
work? But then again, that could be confusing considering the process cube is also clickable as well and has the same effect?
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.
That name could also work. We could also drop process
from the name. We could also do something involving aria roles somehow. For example, if the graph has a test subj, we could select [role="treeitem"]
descendants to get the node wrapper elements. We could also select some other role
to get this 'primary' button perhaps. I don't know enough about it yet.
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.
aria attributes could work. The primary reason I lean towards naming this the effect the button has is that it provides the reader an initial idea of what any related tests should be doing.
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 see what you mean. Related idea: perhaps we could have a selectNodeViaButtonClick
method.
@@ -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, |
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 used to check for the presence of a div, now it checks for a button (that the user can see and interact w/)
@@ -404,6 +404,8 @@ const UnstyledProcessEventDot = React.memo( | |||
}} | |||
tabIndex={-1} | |||
title={eventModel.processNameSafeVersion(event)} | |||
data-test-subj="resolver:node:primary-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.
thoughts on this pattern?
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 don't see a scenario where we add more buttons in the future, but if we do, then we can change it then. The possible future scenario I'm thinking about is something like this potentially around a process node: https://tympanus.net/codrops/2013/08/09/building-a-circular-navigation-with-css-transforms/
Probably a lot of accessibility concerns with that that I have not thought about though
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 like it
Pinging @elastic/endpoint-data-visibility-team (Team:Endpoint Data Visibility) |
Pinging @elastic/endpoint-app-team (Feature:Resolver) |
return this.domNodes( | ||
`${processNodeElementSelector({ entityID })} [data-test-subj="${selector}"]` |
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 is one case where the structure of the selector before ("button that is owned by the process") was valuable I think. I don't see that reflected as much in simplifying it to "a button with an ID". Someone could move that button out from the node, changing the semantics and this test would still pass.
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.
How exactly would removing a wrapper div change the semantics?
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.
The wrapper gets an aria-selected
attribute. is that what you're thinking about?
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.
Even though the submenu button gets tagged with the data-test-resolver-node-id
that doesn't really say the same thing as the button being contained by the node. A well-meaning dev could move that button outside the node (while finding another way to populate data-test-resolver-node-id
as the test expects here and break the semantic meaning without tripping the test up at all. I don't see that as an "improvement" to what's there or easier to read. We could discuss at office hours.
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 guess we could assert this "contains" stuff in the test itself, but then to Michael's point earlier, it kinda beggars the purpose of this separate method altogether.
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.
A well-meaning dev could move that button outside the node (while finding another way to populate data-test-resolver-node-id as the test expects here
That's exactly what I'm going for. Why would we want that to break the test? Is there some observable behavior that's being broken?
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.
📏
Post discussion at office hours: We do want to test things like that buttons are contained by certain elements (say with certain aria-roles or they have some other kind of equivalent aria- relationship like owns
) but that is perhaps better to assert in individual tests (i.e. write a test that asserts that all sumbenu button are children of a role=treeitem
or have some equivalent structural relationship established via other attributes.)
That allows us to keep methods on the simulator more simple/single-purpose ("just get this element") and write tests for the things we care to assert.
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.
we discussed this. The DOM structure is important. These abstractions are still useful. With them, not every tests needs to be coupled to the DOM structure. These methods may change in the future to rely on the DOM structure, that should be fine. Also, we will have separate tests that check the DOM structure and a11y roles.
@@ -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} |
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.
sweeet
…descendant selectors. (elastic#75058) Our tests shouldn't rely on the DOM structure of Resolver (when its arbitrary) because that will make them brittle. If the user doesn't care about the DOM structure, then neither should our tests. Note: sometimes the user does care about the DOM structure, and in those cases the tests should as well.
* master: (24 commits) [ML] Functional tests - skip regression and classification tests [Ingest Manager] fix removing ingest pipelines from elasticsearch (elastic#75092) move tests for placeholder indices to setup (elastic#75096) [jest] temporarily extend default test timeout (elastic#75118) [cli] remove reference to removed --optimize flag (elastic#75083) skip flaky suite (elastic#75044) Adding /etc/rc.d/init.d/functions to the init script when present to … (elastic#22985) [jenkins] add pipeline for hourly security solution cypress tests (elastic#75087) [Reporting/Flaky Test] Skip test for paging list of reports (elastic#75075) remove .kbn-optimizer-cache upload (elastic#75086) skip flaky suite (elastic#74814) Actions add proxy support (elastic#74289) [ILM] TS conversion of Edit policy components (elastic#74747) [Resolver] simulator tests select elements directly instead of using descendant selectors. (elastic#75058) [Enterprise Search] Add Workplace Search side navigation (elastic#74894) [Security solution] Sourcerer: Kibana index pattern selector for security views (elastic#74706) [Logs UI] Remove apollo deps from log link-to routes (elastic#74502) [Maps] add map configurations to docker list (elastic#75035) [functional test][saved objects] update tests for additional copy saved objects to space (elastic#74907) Make the alerts plugin support generics (elastic#72716) ...
…descendant selectors. (#75058) (#75084) Our tests shouldn't rely on the DOM structure of Resolver (when its arbitrary) because that will make them brittle. If the user doesn't care about the DOM structure, then neither should our tests. Note: sometimes the user does care about the DOM structure, and in those cases the tests should as well. Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Summary
Our tests shouldn't rely on the DOM structure of Resolver (when its arbitrary) because that will make them brittle. If the user doesn't care about the DOM structure, then neither should our tests.
Note: sometimes the user does care about the DOM structure, and in those cases the tests should as well.
Checklist
For maintainers