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 元素没有错。有人可以帮我吗?
更新:
在切换到 iframe 之前在主 class 添加一个 Thread.sleep(3000)。
Thread.sleep(3000);
driver.switchTo().frame("content_ifr");
更改了 Page Factory 中 "Body" 字段的 XPATH。
@FindBy(how=How.XPATH,using="//html/body/p")
WebElement post_body;
调试时发现 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.
}
}
我会给你一些关于如何尝试处理它的建议。希望对你有所帮助。
- 将
driver.switchTo().frame("content_ifr");
代码添加到construct_body
方法中,以避免将来在使用此方法之前忘记切换到框架时出错。
- 可能你没有切换到正确的框架。要检查这个,请获取框架的外部 HTML 或获取任何其他易于定位的元素。如果您找不到任何元素,则框架是错误的。但是最好看看它的外部HTML 去确保它是一个正确的框架。有几种方法可以得到outerHTML Get HTML Source of WebElement in Selenium WebDriver using Python
- 确保您的 xPath 是相对于您的 iframe,而不是您的主 HTML 文档。帧的开始应该是它的起点。
当您设法切换到您的框架并获取元素时,请不要忘记切换回来!)
这里发生的所有事情:
1) 您收到 Element Not Visible exception
,这意味着元素存在于 DOM 中,但是当您想要交互时,它还没有呈现,因此您需要使用 wait
.
2) 您无法在呈现页面上的元素上聚焦,这可能由于各种原因而发生;这就是为什么我们使用 Action.moveToElement(elementToBeInFocus)
明确地将焦点传递给该特定元素
我正在遵循页面对象模型来自动化一个应用程序中的流程。在其中一个模块中,我必须添加一个新的 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 元素没有错。有人可以帮我吗?
更新:
在切换到 iframe 之前在主 class 添加一个 Thread.sleep(3000)。
Thread.sleep(3000); driver.switchTo().frame("content_ifr");
更改了 Page Factory 中 "Body" 字段的 XPATH。
@FindBy(how=How.XPATH,using="//html/body/p") WebElement post_body;
调试时发现 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.
}
}
我会给你一些关于如何尝试处理它的建议。希望对你有所帮助。
- 将
driver.switchTo().frame("content_ifr");
代码添加到construct_body
方法中,以避免将来在使用此方法之前忘记切换到框架时出错。 - 可能你没有切换到正确的框架。要检查这个,请获取框架的外部 HTML 或获取任何其他易于定位的元素。如果您找不到任何元素,则框架是错误的。但是最好看看它的外部HTML 去确保它是一个正确的框架。有几种方法可以得到outerHTML Get HTML Source of WebElement in Selenium WebDriver using Python
- 确保您的 xPath 是相对于您的 iframe,而不是您的主 HTML 文档。帧的开始应该是它的起点。
当您设法切换到您的框架并获取元素时,请不要忘记切换回来!)
这里发生的所有事情:
1) 您收到 Element Not Visible exception
,这意味着元素存在于 DOM 中,但是当您想要交互时,它还没有呈现,因此您需要使用 wait
.
2) 您无法在呈现页面上的元素上聚焦,这可能由于各种原因而发生;这就是为什么我们使用 Action.moveToElement(elementToBeInFocus)
明确地将焦点传递给该特定元素