How to recursively locate element within nested iframes in Selenium?

Viewed 56

I found these two topics:

Finding a given element in nested iframes *recursively*

Recursively locate element within nested iframes

But they are not selenium based or C#, below you may see what I have so far:

public static IWebElement FindWebElementByXPath(ChromeDriver chromeDriver, string xPath, string frameType = "iframe")
{
    Console.WriteLine("         Searching for Element: " + xPath + "\n");
    Console.WriteLine();

    IWebElement element;
    try
    {
        chromeDriver.SwitchTo().DefaultContent();
        element = chromeDriver.FindElement(By.XPath(xPath));
        if (element != null)
        {
            Console.WriteLine("     Found Element: " + xPath + " (" + element.Text + ")\n");
            Console.WriteLine();
            return element;
        }

    }
    catch (Exception)
    {
        // ignored
    }

    var windowHandles = chromeDriver.WindowHandles;

    foreach (var window in windowHandles)
    {

        chromeDriver.SwitchTo().Window(window);

        var frames = chromeDriver.FindElements(By.TagName(frameType));

        foreach (var frame in frames)
        {
            chromeDriver.SwitchTo().DefaultContent();
            chromeDriver.SwitchTo().Frame(frame);
            try
            {
                element = chromeDriver.FindElement(By.XPath(xPath));
                if (element != null)
                {
                    Console.WriteLine("     Found Element: " + xPath + " (" + element.Text + ")\n");
                    Console.WriteLine();
                    return element;
                }
            }
            catch (Exception)
            {
                // ignored
            }


            var frameChildren = chromeDriver.FindElements(By.TagName(frameType));
            foreach (var child in frameChildren)
            {
                chromeDriver.SwitchTo().DefaultContent();
                chromeDriver.SwitchTo().Frame(frame);
                chromeDriver.SwitchTo().Frame(child);

                try
                {
                    element = chromeDriver.FindElement(By.XPath(xPath));
                    if (element != null)
                    {
                        Console.WriteLine("     Found Element: " + xPath + " (" + element.Text + ")\n");
                        Console.WriteLine();
                        return element;
                    }
                }
                catch (Exception)
                {
                    // ignored
                }
            }
        }
    }

    Console.WriteLine("Failed to find Element: " + xPath + "\n");
    Console.WriteLine();
    return null;
}

My current code can only handle the 1 frame and the children of said frame, but not the children of children and so on.

My brain hurts because I can't figure out how to write a recursive function to crawl through all of this.

1 Answers

This is the solution I came up with:

public static IWebElement FindWebElementByXPath(ChromeDriver chromeDriver, string XPath, string FrameType = "iframe")
{

IWebElement element = null;
Console.WriteLine("         Searching for Element: " + XPath + "\n");

chromeDriver.SwitchTo().DefaultContent();
try
{
    element = chromeDriver.FindElement(By.XPath(XPath));
    if (element != null)
    {
        Console.WriteLine("     Found Element: " + XPath + " (" + element.Text + ")\n");
        return element;
    }
}
catch
{
                
}

var iframes = chromeDriver.FindElements(By.TagName(FrameType)).ToList<IWebElement>();
var index = 0;

Reset:
for (; index < iframes.Count; index++)
{
    retry:
    try
    {
        var item = iframes[index];
            
        try
        {
            chromeDriver.SwitchTo().Frame(item);
            try
            {
                element = chromeDriver.FindElement(By.XPath(XPath));
                if (element != null)
                {
                    Console.WriteLine("     Found Element: " + XPath + " (" + element.Text + ")\n");
                    return element;
                }
            }
            catch
            {
                
            }
        }
        catch
        {
            chromeDriver.SwitchTo().ParentFrame();
            goto retry;
        }


        var children = chromeDriver.FindElements(By.TagName(FrameType)).ToList();
            
        if (children.Count > 0)
        {
            if (iframes.Any(x => children.Any(y => y.Equals(x))) == false)
            {
                iframes.InsertRange(index+1,children);
                goto Reset;
            }
        }
            
    }
    catch
    {

    }
}
    
return element;
}

Here you go, literally the only hit on SO with a snippet for crawling through nested iframes in C# Selenium.

Related