0

I am trying to create a WebElement object. I saw that there is a IWebElement interface which i could implement.

I also saw this question and did't manage to implement it sucessfully.

In my usecase I get from a webpage all forms and then take the one with the most input tags which haven't got the type attribute set to hidden. this is my usecase code:

using System;
using System.Linq;

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace AutoWinner
{
    class Program
    {
        static void Main(string[] args)
        {
            IWebDriver driver = new ChromeDriver();
            driver.Url = "https://keepass.info/help/kb/testform.html";
            var forms = driver.FindElements(By.TagName("form"));

            var longestFormLengthOfAllForms = 0;

            // I don't the p element. 
            // It's more here to just get a webElement which ic can later overwrite.
            var mainForm = driver.FindElement(By.TagName("p"));
            foreach (var form in forms)
            {
                Console.WriteLine(form.GetAttribute("outerHTML"));
                var children = form.FindElements(By.TagName("input"));
                var lengthOfCurrentForm = children.Count(x => x.GetAttribute("type") != "hidden");
                if (lengthOfCurrentForm > longestFormLengthOfAllForms)
                {
                    longestFormLengthOfAllForms = lengthOfCurrentForm;
                    mainForm = form;
                }
            }

            Console.WriteLine(mainForm.GetAttribute("outerHTML"));
        }
    }
}

The line var mainForm = driver.FindElement(By.TagName("p")); is meant to be a global variable where later save my main form in it. I don't need the p element.

my Idea was to remove by creating a standard webElement.

How could i get rid of it or improve it?

Nightscape
  • 464
  • 6
  • 19
  • IWebElement is an interface, where are you implementing it ? – cruisepandey May 06 '19 at 06:34
  • I am not implementing it. Thats my question, if there is a way to create a WebElement without having to implement the IWebElement interface. – Nightscape May 06 '19 at 06:36
  • When u create object of `RemoteWebElement` class, it implements `IWebElement` interface. In your code `var forms = driver.FindElements(By.TagName("form"));`, forms is an webelement. You don't need `IWebElement` for that. – cruisepandey May 06 '19 at 06:40
  • Though I don't get this part of the code `mainForm = form`, why would anyone wanna do that ? – cruisepandey May 06 '19 at 06:41
  • @cruisepandey I have a global form named mainForm. In my foreach loop i filter for the biggest form and when I find it, I overwrite the global main form with it. – Nightscape May 06 '19 at 06:43
  • @cruisepandey how would you do it else? – Nightscape May 06 '19 at 06:44
  • Are you getting compile-time error ? – cruisepandey May 06 '19 at 06:53
  • yes i do. The code above doesn‘t run like that – Nightscape May 06 '19 at 06:54
  • It's because `mainForm` is a reference of object of `RemoteWebElement`, Now think it's referring to an object. `form` is an element from `forms`. Compiler will not allow you to refer to the web element. Cause it's already been used. – cruisepandey May 06 '19 at 06:57
  • What is your use case ? what do you wanna achieve ? – cruisepandey May 06 '19 at 06:58
  • @cruisepandey i think my example code is more confusing then helpful. I trying to create a "standard" WebElement object. – Nightscape May 06 '19 at 06:59
  • The page you reference in your code only has a single form on it... why are you trying to filter out `INPUT`s, etc.? Is this supposed to be an example page of another page you can't show or ? I'm confused still as to what your scenario is. – JeffC May 06 '19 at 20:11
  • @JeffC i am trying to code contact form filler. Most websites have beside the contact form also a newsletter form and the search form. The contact form is in most cases the one with the most input fields. The other ones like the newsletter and search form have in the most cases only one input field. – Nightscape May 06 '19 at 20:47
  • @Nightscape OK. My answer should work then. I tested it on the sample HTML I provided that fits the scenario you described. – JeffC May 06 '19 at 20:56

2 Answers2

2

Given your current usecase, I would suggest the code below. It grabs the FORM tags, loops through each one and counts the INPUTs that aren't type='hidden'. Once it falls out of the for-each, mainForm is the FORM with the largest number of desired INPUTs.

IWebElement mainForm = null;
IReadOnlyCollection<IWebElement> forms = Driver.FindElements(By.CssSelector("form"));
int maxCount = 0;
foreach (IWebElement form in forms)
{
    int count = form.FindElements(By.CssSelector("input:not([type='hidden'])")).Count;
    if (count > maxCount)
    {
        maxCount = count;
        mainForm = form;
    }
}

// do something with mainForm
Console.WriteLine(mainForm?.GetAttribute("name"));

I tested this with the sample HTML page I created, below

<!DOCTYPE html>
<html>

<head>
    <title></title>
</head>

<body>

<table border="1">
<tr><td>
<form name="form1">
<p>Field1:<br><input type="text"></p>
<p>Field2:<br><input type="hidden"></p>
<p>Field3:<br><input type="hidden"></p>
<p>Field4:<br><input type="hidden"></p>
<p>Field5:<br><input type="text"></p>
<p><input type="submit" value="Submit">
</form>
</td></tr>

<tr><td>
<form name="form2">
<p>Field1:<br><input type="text"></p>
<p>Field2:<br><input type="hidden"></p>
<p>Field3:<br><input type="text"></p>
<p>Field4:<br><input type="hidden"></p>
<p>Field5:<br><input type="text"></p>
<p><input type="submit" value="Submit">
</form>
</td></tr>

<tr><td>
<form name="form3">
<p>Field1:<br><input type="text"></p>
<p>Field2:<br><input type="text"></p>
<p>Field3:<br><input type="text"></p>
<p>Field4:<br><input type="hidden"></p>
<p>Field5:<br><input type="text"></p>
<p><input type="submit" value="Submit">
</form>
</td></tr>
</table>

</body>
</html>
JeffC
  • 22,180
  • 5
  • 32
  • 55
  • Thanks for the answer! You have made a good approach with the css selector compared to my. For my the most important line in your code is this one: IWebElement mainform = null Like the title of my question says I was wondering how I can create a standard, empty WebElement. The funny thing is its just a line but still nobody could answer my question. It might be because question wasn‘t clear enough :/ – Nightscape May 06 '19 at 21:04
  • 1
    I think the question just wasn't clear on what you were trying to do. There is no such thing as `WebElement` in C# as there is in Java. `IWebElement` is what you are looking for and yes, you can assign `null` to a variable of type `IWebElement`. – JeffC May 06 '19 at 21:09
0

I still do not get your use case. But anyway if you are looking for something like this :

Let's say you have two web element like this :

var ele1 = driver.FindElement(By.Xpath("//"));

var ele2 = driver.FindElement(By.Xpath("//"));

ele1 is pointing to one element, whereas ele2 is pointing to second element.

ele2 = ele1

Now, ele2 should point to ele1.

Not sure if you are looking for the same thing. Can't add this much as comment also.

cruisepandey
  • 28,520
  • 6
  • 20
  • 38