Is it possible to uniquely identify DOM elements in React code? - reactjs

I am using React Dev Tools to inspect a React App in Chrome. Here is a screenshot of what I see:
Now I would like to identify the highlighted input object in my React code, in order to modify the event that is called when I type in some input. My problem is that there are several input elements in the DOM. I can easily type in some random number in one of the input fields and then identify which element in the DOM I have modified by my input. But I do not know how to identify that element in the code since there are several input elements of the same type in the code. That makes it hard to identify the specific line or the specific element in the code that I modified in the DOM.
Is there a way to find a specific DOM element in the code? Or to modify my code such that I find out which element in the code has called the event handler?
I have tried to log this in the console in the event handler but this in my case returns a reference to the entire component and not the specific element that called the event handler.

Use React Dev Tools
As the main image of React Dev Tools shows, you can inspect the element on the screen and see the structure of the code. This will be a helpfull tool for you.
If you want to know exactly what field to change, just add so prop to the field like id='123' and you will be able to see it in the Dev Tools.
To learn how to install and use that Chrome plugin, you can do a little search and you will find it ;)
Edit: I said to add a prop field like id='123' but you can add any prop like elementIWantToSee='here'and with the Dev Tools you would easily find the element

Related

Cannot get XPath selector to work using Robocorp Selenium library

I am attempting web automation with a platform called Robocorp using the Selenium library.
When I run my program, I have no issues until I encounter this page where I am trying to get the program to click on the icon that says SQL.
I want the <a> element with the #href attribute.
Here are some (of many) XPaths I have tried that have all failed:
xpath://a[contains(#href,'sql_form.jsp')]
xpath://*[text()='SQL']
xpath://a[#target='frame2]
Snapshot of the element:
I circled the element in red ^^^
I cannot get the selector to be recognized on this page. I have tried adding delays, waiting until the element is active, waiting until the element is visible, etc.
Nothing seems to work.
Here is an image of the elements I am trying to select.
(The link in the href element takes me to the page I am trying to access).
I thought that the third one would for sure work but is still failing.
I am using a platform called Robocorp which only needs the raw selector to work (CSS or XPath)
I was unaware that iframe needed to be handled differently or that it even existed
https://robocorp.com/docs/development-guide/browser/how-to-work-with-iframes
I first needed to switch frames.
To identify the element with text as SQL you can use you can use either of the following locator strategies:
Using Wait Until Element Is Visible:
Wait Until Element Is Visible xpath=//a[starts-with(#href, 'sql_form.jsp') and #target='frame2']/font[text()='SQL'] 10 seconds
Using Wait Until Element Is Enabled:
Wait Until Element Is Enabled xpath=//a[starts-with(#href, 'sql_form.jsp') and #target='frame2']/font[text()='SQL'] 10 seconds
References
You can find a couple of relevant detailed discussions in:
How to click a row that has javascript on click event in RIDE
Robot Framework: Wait Until Element Is Visible vs. Element Should Be Visible, which one is better to use?

How to make Visual Studio Code Autocomplete for Library Function, not user-defined element as first suggestion

I'm using JavaScript React in VSCode and the autocomplete's first suggestion is to make an element of whatever word I'm using. See image:
After pressing tab:
This makes me always have to press the down arrow each time and is annoying. How can I make suggestions like isRequired the first result so I dont need to always press the down key to select it
I changed the language to JavaScript react but it still thinks i'm creating my own elements, and only suggests react syntax below it.

How to get the TipTap Editor to recognize updated external state values

This is likely an issue with my inexperience using React generally, but I'd still greatly appreciate any insights.
I've added a commenting plugin to the TipTap editor.
When I create a new comment, it creates a DB record for the comment and I store that new comment in a state value (React) which is an array of all comments.
Then I return the ID which I use in a setComment (Mark) command that wraps the selection in a span with a commentId on the data-comment attribute.
When I click on that span, I can get the ID value, but the editor selectionUpdate function doesn't see the updated value. The page can access it fine, but that function can't see it until the page is reloaded.
How do I convince the editor to recognize the updated value in that function?
A minimal app demo can be found here:
Once you make a comment, and click on it, you'll see that it doesn't find the newly added comment. That's what I'm try to fix. It should be able to find it.
I understanding the the useEffect isn't being updated because the dependency array does not include chapterComments - but if I add it, then selectionUpdate runs multiple times and only the last one is accurate. I don't know how to appropriate destroy or update the editor instance - though I assume that's what I need to do.
The TipTap editor hook, const editor = useEditor, has it's own dependency array. Instead of trying to use useEffect with an editor dependency, just use the built in one for any values the editor needs to keep track of.
/facepalm

How can I access the selector field of a By object?

I'm using Java, Selenium Webdriver in Eclipse.
I wrote a helper method to wait for an element present, scroll to it, wait for the element to be visible and click it. Here's what I have:
protected void waitScrollWaitClick(By by, String scroll)
{
wait.until(ExpectedConditions.presenceOfElementLocated(by));
getJse().executeScript("$('.mCustomScrollbar#" + scroll + "').mCustomScrollbar('scrollTo',document.querySelector(\"" + by.selector + "\"), {scrollInertia:0})");
wait.until(ExpectedConditions.visibilityOfElementLocated(by));
getDriver().findElement(by).click();
Now the issue I'm having is in that second line in the method. I am passing a By object. This works for the conventional Webdriver methods on lines 1,3,4. But since we are using a custom scrollbar for our web app, I need to use that JavascriptExecutor class (the getJse()) to scroll on the proper div #id (thus passing in the 'scroll' argument). To use that JSE I just need the CSS selector, not the whole By object. If I add a breakpoint and look, the By object contains a 'selector' field that has what I want (in Eclipse there's a red square icon with an 'F' on it), but I can't seem to access it. I tried with the "by.selector" in the code above, but that is a compile error.
How can use that selector field? I'm not Java expert, so maybe I'm missing something obvious. I guess I don't understand why I can stop on a breakpoint, see the By object I created in the Variables tab, expand the By object and see the 'selector' field I want, but just can't access it.
The easy answer is that you cannot get the CSS selector from a By type, or even WebElement type. This is because the WebElements themselves are found by the By class. In case the By specified was a xpath there would be no way to populate the CSS selector.
The long answer specifically for your issue, to get the CSS Selector would be to create it using Javascript. An example would be Florent B.'s answer here. However, I didn't tried myself and I have no idea if it works for all cases.
Now, to address the general issue, instead of using document.querySelector use document.getElementById in case your element has an id.
Or by using document.evaluate to get your element by xpath. You can find an example in the answer posted here.

Are there any tools for recording web browser events for seleniumn2?

I am looking for something very simple. It can use the Selenium IDE recording tool, but it does not allow me to pick what kind of locators I get.
I want to use:
driver.findElement(By.className(str))
to locate things. All I need is something which watches which UI elements on a web page get clicked and writes out the class attributes of those tags.
If I use the Selenium IDE recording (and export to the right type of thing), I get:
#Test
public void testNav() throws Exception {
driver.get(baseUrl + "/");
driver.findElement(By.name("3.1.1.5.1.1")).clear();
driver.findElement(By.name("3.1.1.5.1.1")).sendKeys("dan");
driver.findElement(By.name("3.1.1.5.1.5")).click();
driver.findElement(By.linkText("Products")).click();
driver.findElement(By.linkText("Categories")).click();
driver.findElement(By.linkText("Create a Category")).click();
driver.findElement(By.linkText("Cancel")).click();
driver.findElement(By.linkText("Products")).click();
driver.findElement(By.cssSelector("a.DisplayAdminProductsLink")).click();
driver.findElement(By.linkText("Product1")).click();
There are problems with this. First, it is not give me any By.className() calls. Why? Those first 3 calls will not help me. The framework I am using puts arbitrary things into the name. How can I get it to see the class attribute?
There actually are unique words in the class attribute of all of the above tags. I design my apps so that this is so. Yet it will not use them.
Earlier I asked:
Why is it doing a "driver.findElement().click()"? This is fragile and does not
end up working.
What I need is:
elt = driver.waitFor(By.className("c")); elt.click();
This will work reproducibly.....
I am considering to be removed from the question, as the findElement() code does work. You need to set a general time-out on the driver. It is not very obvious that this can be done, but it can.
So, continuing on....
I can go to the "Options" and change the order of the "Locator Builders" in eclipse. I can put "css" at the top. Then I get:
driver.findElement(By.cssSelector("input[name=\"3.1.1.5.1.1\"]")).clear();
driver.findElement(By.cssSelector("input[name=\"3.1.1.5.1.1\"]")).sendKeys("dan");
driver.findElement(By.cssSelector("input[name=\"3.1.1.5.1.5\"]")).click();
The tags are like:
<input class="form-control LoginUsernameField" ... />
But it does not see the class attribute.... Or I can do this manually.
Selenium looks for a unique identifier to identify elements in a webpage. classNames are a very less desired option for this purpose as they are generally not unique. Ids and names on the other hand are generally unique. This might be the reason why Selenium IDE is not selecting classNames and going for other identifiers.
Selenium IDE records user actions. You would have clicked on the element for Selenium IDE to identify it and that is why you are getting driver.findElement().click().
If you want to wait for element to wait you can try implicit wait.
When you want to use driver.findElement(By.className(str)), are you sure that there is one and only one element in the webpage that is associated with a className? If that is the case you can modify the webdriver code manually to use className.

Resources