Selenium WebDriver [Java] 如何将 iframe 的元素存储在 PageFactory 中

Selenium WebDriver [Java] How do I store the elements of an iframe in a PageFactory

我正在遵循页面对象模型来自动化一个应用程序中的流程。在其中一个模块中,我必须添加一个新的 post,它有一个 "Title" 和一个 "Body" 字段。截至目前,我能够发送 "Title" 字段中的文本,就像在 Top Window 中一样。但是 "Body" 在 iframe 中。在 "Title" 中传递文本后,我尝试在 "Body" 中写入之前切换到 iframe。这段代码我已经写在了主文件中。但是 Selenium 显示错误 org.openqa.selenium.ElementNotVisibleException: element not visible

我的PageFactory代码如下:

package com.wordpress.pom.Pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;

public class AddNewPost {

    WebDriver driver;

    public AddNewPost(WebDriver addNewPostDriver)
    {
        this.driver=addNewPostDriver;
    }

    @FindBy(how=How.ID,using="title")
    WebElement post_title;

    @FindBy(how=How.XPATH,using=".//*[@id='tinymce']/p/br")
    WebElement post_body;

    public void construct_title()
    {
        post_title.sendKeys("This is the Title");
        System.out.println("Title written");

    }

    public void construct_body()
    {

        post_body.sendKeys("This is the body");
        System.out.println("Body written");
    }

}

我正在使用 testNG 来安排测试用例。这是我的主要文件代码:

package com.wordpress.pom.Testcase;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import com.wordpress.pom.Helper.BrowserFactory;
import com.wordpress.pom.Pages.AddNewPost;
import com.wordpress.pom.Pages.Dashboard;
import com.wordpress.pom.Pages.LoginPageNew;
import com.wordpress.pom.Pages.Posts;

public class VerifyValidLogin 
{

    WebDriver driver;

    //code ommitted

    @Test (priority=3)
    public void construct_title()
    {
        //Created Page Object using Page Factory
        AddNewPost add_new_post = PageFactory.initElements(driver, AddNewPost.class);

        //Call the method
        add_new_post.construct_title();
    }

    @Test (priority=4)
    public void construct_body()
    {
        //Created Page Object using Page Factory
        AddNewPost add_new_post = PageFactory.initElements(driver, AddNewPost.class);

        driver.switchTo().frame("content_ifr");

        //Call the method
        add_new_post.construct_body();
    }

}

HTML DOM 为:

<iframe id="content_ifr" src="javascript:""" allowtransparency="true" title="Rich Text Area Press ALT F10 for toolbar. Press ALT 0 for help." style="width: 100%; height: 330px; display: block;" frameborder="0">
<!DOCTYPE >
<html>
<head xmlns="http://www.w3.org/1999/xhtml">
<body id="tinymce" class="mceContentBody content post-type-post wp-editor" onload="window.parent.tinyMCE.get('content').onLoad.dispatch();" dir="ltr" contenteditable="true">
<p>
<br data-mce-bogus="1">
</p>
</body>
</html>
</iframe>

我觉得 PageFactory 中标识的 body 元素没有错。有人可以帮我吗?

更新:

  1. 在切换到 iframe 之前在主 class 添加一个 Thread.sleep(3000)。

    Thread.sleep(3000);
    driver.switchTo().frame("content_ifr");
    
  2. 更改了 Page Factory 中 "Body" 字段的 XPATH。

    @FindBy(how=How.XPATH,using="//html/body/p")
    WebElement post_body;
    
  3. 调试时发现 WebDriver 确实点击了 Body 字段,我可以 sysout 但不会发送 Body 字段中的密钥。所以我被迫使用Action class.

    public void construct_body()
    {
     Actions actions = new Actions(driver);
     actions.moveToElement(post_body);
     actions.click();
     actions.sendKeys("Some Name");
     actions.build().perform();
     System.out.println("Body written");
    }
    

我现在可以传课文了。但是我仍然不确定为什么即使在单击 Body 元素后我还需要 Action class 。如果我的方法在页面对象模型下是正确的,最后想听听您的意见。

如果你问的是策略,有不同的方法可以实现,但我只是简单地问自己这个问题。这个组件是什么?

即什么是 body?

body 是新 Post 的一部分(对吧?)。因此,您可以简单地为 body 创建一个新页面 Object class,并在您的新 Post Class 中创建一个 object。这是我认为的Has-A关系。

您可以在下方阅读更多相关信息 post。 http://www.w3resource.com/java-tutorial/inheritance-composition-relationship.php

关于您的特定问题,很少有事情。

  • 不要直接与测试中的元素交互,比如切换到框架。在 class 或函数中处理它。在你的情况下可能在 construct_body 函数中。
  • 您不会收到元素不可见的错误,这意味着元素存在并且这是一件好事。您可以使用 Explicit Wait 等待元素可见。 阅读以下文章了解更多详情。 http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp

以下只是您如何处理这种情况的示例。

Base Page: 初始化 driver 和一些全局函数

abstract public class BasePage {
}

Body Class:负责处理post的body部分相关的所有功能。它不是 public,因此如果测试在不同的包中,它们将无法直接访问此 class。他们只能通过 Post Class 获得访问权限。

class BodyPage extends BasePage {

    public BodyPage(WebDriver driver){
        PageFactory.initElements(driver, this);
        //Switch to frame
    }

    public void save(){
        //Do some action here
        // Switch Back to main page
    }
}

Post Class:负责遍历整个页面。 BodyPage object 是私有的,所以你不能在测试中直接交互它。现在写测试用例的,只知道PostClass.

public class PostPage extends BasePage {

    private BodyPage bodyPage;
    public PostPage(WebDriver driver){
        PageFactory.initElements(driver, this);
        //Or Switch to frame here
        bodyPage = PageFactory.initElements(driver, BodyPage.class);
    }

    public void enterBody(){
        //Call other functions
        bodyPage.save();

        //you can switch back to main window here as well.

    }
}

我会给你一些关于如何尝试处理它的建议。希望对你有所帮助。

  1. driver.switchTo().frame("content_ifr");代码添加到construct_body方法中,以避免将来在使用此方法之前忘记切换到框架时出错。
  2. 可能你没有切换到正确的框架。要检查这个,请获取框架的外部 HTML 或获取任何其他易于定位的元素。如果您找不到任何元素,则框架是错误的。但是最好看看它的外部HTML 去确保它是一个正确的框架。有几种方法可以得到outerHTML Get HTML Source of WebElement in Selenium WebDriver using Python
  3. 确保您的 xPath 是相对于您的 iframe,而不是您的主 HTML 文档。帧的开始应该是它的起点。

当您设法切换到您的框架并获取元素时,请不要忘记切换回来!)

这里发生的所有事情:

1) 您收到 Element Not Visible exception,这意味着元素存在于 DOM 中,但是当您想要交互时,它还没有呈现,因此您需要使用 wait.

2) 您无法在呈现页面上的元素上聚焦,这可能由于各种原因而发生;这就是为什么我们使用 Action.moveToElement(elementToBeInFocus) 明确地将焦点传递给该特定元素