I am following Page Object Model to automate a flow in one application. In one of the module I have to add a new post which have a "Title" and a "Body" field. As of now, I am able to send the text in the "Title" field as it is in the Top Window. But the "Body" is within an iframe. After passing the text in "Title" I tried to switch to the iframe before writing in the "Body". This piece of code I have written in the main file. But Selenium shows an error as org.openqa.selenium.ElementNotVisibleException: element not visible
My PageFactory code is as follows:
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");
}
}
I am using testNG to schedule the testcases. Here is my main file code:
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();
}
}
The HTML DOM is as:
<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>
I feel the elements identified in the PageFactory for the body is not incorrect. Can someone help me out please?
Update:
Add a Thread.sleep(3000) in the main class before switching to the iframe.
Thread.sleep(3000); driver.switchTo().frame("content_ifr");
Changed the XPATH of the "Body" field in Page Factory.
@FindBy(how=How.XPATH,using="//html/body/p") WebElement post_body;
On debugging found that WebDriver does clicks on the Body field and I can sysout but won't send the keys in the Body field. So I was forced to use 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"); }
I am able to pass the text now. But I am still not sure why would I need the Action class even after clicking on the Body element. Finally would like your opinion if my approach is correct here following the Page Object Model.
I'll give you several advice of how to try to deal with it. Hope it will help you.
driver.switchTo().frame("content_ifr");
code to theconstruct_body
method to avoid mistakes in future when you forget to switch to the frame before using this method.And when you manage to switch to your frame and to get element, don't forget to switch back!)
All the Things going on here:
1) You were receiving
Element Not Visible exception
that means element is present in the DOM, but by the time you want to interact, it is just not rendered yet hence you need to use thewait
.2) You were not able to FOCUS on the element on the rendered page, which can happen due to various reasons; that is why we use
Action.moveToElement(elementToBeInFocus)
to explicitly deliver focus to that particular elementIF you are asking about strategy there are different ways to achieve this, but what I do is I simple ask this question to my self. What is this component?
i.e. What is body?
body is part of New Post (right?). And so simply you can create a new Page Object class just for body and create a object inside your NewPost Class. This is Has-A Relationship in my opinion.
You can read more about this in below post. http://www.w3resource.com/java-tutorial/inheritance-composition-relationship.php
About your particular problem, few things.
Following is just an example how you can handle this scenario.
Base Page: Initialize the driver and some global function
Body Class: Responsible for handling all the function related to body part of post. It's not public so if tests are in different package they won't have direct access to this class. They will have to get access through Post Class only.
Post Class: Responsible for iterating with whole page. BodyPage object is private, so you can't directly interact it in test. Now those who are writing test cases, they only know about Post Class.