I'm trying to implement Page Factory pattern for my testing framework, but I'm getting NPE while trying to reach or interact with elements. BTW, I'm using Spring Dependency Injection for sharing WebDriver instance among tests (instead of constructor), so I implemented PageFactory initElements() inside non-static block to be able to reach it.
BTW, without PageFactory (without #FindBy and with commented By items) it works perfect.
Here is my code of PO.class:
#Component
public class HomePage extends BasePage {
#Autowired
private DatabasesPage databasesPage;
#Autowired
private UserAccountsPage userAccountsPage;
public static Logger log = LogManager.getLogger(HomePage.class.getName());
private String themeLabelColorHex = "#235a81";
private Select themeList;
/* private By databasesHeaderButton = By.cssSelector("#topmenu > li:nth-child(1)"),
userAccountsHeaderButton = By.cssSelector("#topmenu > li:nth-child(4)"),
languagesDropdown = By.id("sel-lang"),
themeDropdown = By.name("set_theme"),
themeLabel = By.xpath("//*[#id='li_select_theme']//a");*/
#FindBy(how = How.CSS, css = "#topmenu > li:nth-child(1)") private WebElement databasesHeaderButton;
#FindBy(how = How.CSS, css = "#topmenu > li:nth-child(4)") private WebElement userAccountsHeaderButton;
#FindBy(how = How.ID, id = "sel-lang") private WebElement languagesDropdown;
#FindBy(how = How.NAME, name = "set_theme") private WebElement themeDropdown;
#FindBy(how = How.XPATH, xpath = "//*[#id='li_select_theme']//a") private WebElement themeLabel;
{
PageFactory.initElements(driver,this);
System.out.println("**************** THIS IS A NON-STATIC FIELD REACHED BY DEP INJ ****************");
}
public HomePage openUp() {
String propertiesPath = get(System.getProperty("user.dir"),
"src", "main", "java", "base", "configuration", "config.properties").normalize().toString();
try {
Properties properties = new Properties();
properties.load(new FileInputStream(propertiesPath));
String url = properties.getProperty("url");
driver.get(url);
}
catch ( IOException e) {
log.error("Properties file is not found");
log.error("\n " + ExceptionUtils.getStackTrace(e));
}
return this;
}
public DatabasesPage goToDatabasesPage() {
databasesHeaderButton.click();
return databasesPage;
}
public UserAccountsPage goToUserAccountsPage() {
userAccountsHeaderButton.click();
return userAccountsPage;
}
public HomePage changeLanguage(String langValue) {
try {
Select langList = new Select(languagesDropdown);
String currentLang = langList.getFirstSelectedOption().getAttribute("value");
if (langValue.equalsIgnoreCase(currentLang)) log.warn("Desired language is already selected!");
else langList.selectByValue(langValue);
}
catch (Exception e) {
log.error("\n" + ExceptionUtils.getStackTrace(e));
}
return this;
}
public HomePage changeTheme(String themeValue) {
try {
themeList = new Select(themeDropdown);
String currentTheme = themeList.getFirstSelectedOption().getAttribute("value");
if (themeValue.equalsIgnoreCase(currentTheme))
log.warn("Desired theme is already selected!");
else {
themeList.selectByValue(themeValue);
driver.navigate().refresh();
themeLabelColorHex = "#0000ff";
}
}
catch (Exception e) {
log.error("\n" + ExceptionUtils.getStackTrace(e));
}
return this;
}
public HomePage setDefaultTheme() {
themeList = new Select(themeDropdown);
themeList.selectByValue("pmahomme");
themeLabelColorHex = "#235a81";
return this;
}
public boolean isLanguageChanged() {
return true; // TO DO
}
public boolean isThemeChanged() {
String RGBColor = themeLabel.getCssValue("color"); // I'm getting NPE here somehow
String HexColor = Color.fromString(RGBColor).asHex();
return HexColor.equalsIgnoreCase(themeLabelColorHex);
}
}
Here is my Test method:
#Test
#Description("Change website theme")
public void changeWebsiteTheme() {
homePage.openUp().changeTheme("original");
assertThat(true).isEqualTo(homePage.isThemeChanged()); // and it fails here but it didn't perform previous step - changeTheme();
homePage.setDefaultTheme();
assertThat(true).isEqualTo(homePage.isThemeChanged());
}
enter code here
to initiate the PageFactory which is written in constructor, it has to be initiated by create the object of the class.
this helped me to achieve this.
Related
I want to iterate over Object[] within a class with Reflection
this is my class :
public class Lab {
public Browser[] browser;
}
class Browser {
String url;
}
I want to reach browser[] from the Lab class at index 3 and check value of url
You can achieve that with something like the following snippet:
public boolean urlEquals(Lab lab, String other){
try{
Field browsersField = Lab.class.getDeclaredField("browsers");
Object browsers = browsersField.get(lab);
Object browser = Array.get(browsers, 3);
Field urlField = Browser.class.getDeclaredField("url");
urlField.setAccessible(true);
Object url = urlField.get(browser);
return url.equals(other);
} catch(Exception e){ // probably catch specific exceptions than all
throw new IllegalStateException(e);
}
}
Maybe in this way:
public class Lab
{
public Browser[] browser;
public static void main(String[] args)
{
Lab myLabInstance = new Lab();
myLabInstance.browser = new Browser[] { new Browser(), new Browser(), new Browser(), new Browser(), };
for (Field field : Lab.class.getDeclaredFields())
{
System.out.println(field.getName());
if (field.getName().equalsIgnoreCase("browser"))
{
field.setAccessible(true);
Browser[] browsers = (Browser[]) field.get(myLabInstance);
System.out.println(browsers[3].url.equals("myvalue"));
}
}}}
class Browser
{
public String url = "hallo";
}
To upload files to the repository, I use the following Java-backed WebScript:
public class CustomFileUploader extends DeclarativeWebScript {
private static final String FIRM_DOC = "{http://www.firm.com/model/content/1.0}doc";
private static final String FIRM_DOC_FOLDER = "workspace://SpacesStore/8caf07c3-6aa9-4a41-bd63-404cb3e3ef0f";
private FileFolderService fileFolderService;
private ContentService contentService;
private NodeService nodeService;
private SearchService searchService;
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
processUpload(req);
return null;
}
private void writeContent(NodeRef node, FirmFile firmFile) {
try {
ContentWriter contentWriter = contentService.getWriter(node, ContentModel.PROP_CONTENT, true);
contentWriter.setMimetype(firmFile.getFileMimetype());
contentWriter.putContent(firmFile.getFileContent().getInputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
private NodeRef checkIfNodeExists(String fileName) {
StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
ResultSet resultSet = searchService.query(storeRef, SearchService.LANGUAGE_LUCENE/*LANGUAGE_FTS_ALFRESCO*/,
"TYPE:\"firm:doc\" AND #cm\\:name:" + fileName.replaceAll(" ", "\\ ")+ "");
int len = resultSet.length();
if(len == 0) {
return null;
}
NodeRef node = resultSet.getNodeRef(0);
return node;
}
private NodeRef createNewNode(FirmFile firmFile) {
NodeRef parent = new NodeRef(FIRM_DOC_FOLDER);
NodeRef node = createFileNode(parent, firmFile.getFileName());
return node;
}
private void processUpload(WebScriptRequest req) {
FormData formData = (FormData) req.parseContent();
FormData.FormField[] fields = formData.getFields();
for(FormData.FormField field : fields) {
String fieldName = field.getName();
if(fieldName.equalsIgnoreCase("firm_file") && field.getIsFile()) {
String fileName = field.getFilename();
Content fileContent = field.getContent();
String fileMimetype = field.getMimetype();
NodeRef node = checkIfNodeExists(fileName);
// POJO
FirmFile firm = new FirmFile(fileName, fileContent, fileMimetype, FIRM_DOC);
if(node == null) {
node = createNewNode(firmFile);
}
writeContent(node, firmFile);
}
}
}
private NodeRef createFileNode(NodeRef parentNode, String fileName) {
try {
QName contentQName = QName.createQName(FIRM_DOC);
FileInfo fileInfo = fileFolderService.create(parentNode, fileName, contentQName);
return fileInfo.getNodeRef();
} catch (Exception e) {
e.printStackTrace();
}
}
public FileFolderService getFileFolderService() {
return fileFolderService;
}
public void setFileFolderService(FileFolderService fileFolderService) {
this.fileFolderService = fileFolderService;
}
public ContentService getContentService() {
return contentService;
}
public void setContentService(ContentService contentService) {
this.contentService = contentService;
}
public NodeService getNodeService() {
return nodeService;
}
public void setNodeService(NodeService nodeService) {
this.nodeService = nodeService;
}
public SearchService getSearchService() {
return searchService;
}
public void setSearchService(SearchService searchService) {
this.searchService = searchService;
}
}
This WebScript works.
There is one problem: if the uploaded file does not exist in the repository, then two versions are created at once: 1.0 and 1.1. Version 1.0 has a size of 0 bytes and has no content.
I think version 1.0 is created here:
FileInfo fileInfo = fileFolderService.create(parentNode, fileName, contentQName);
Version 1.1, perhaps, is created here, when writing the content:
ContentWriter contentWriter = contentService.getWriter(node, ContentModel.PROP_CONTENT, true);
contentWriter.setMimetype(firmFile.getFileMimetype());
contentWriter.putContent(firmFile.getFileContent().getInputStream());
How to prevent the creation of "empty" version 1.0?
Axel Faust gave an excellent answer to this question here.
The problem was in the fileuploader.post.desc.xml descriptor, I didn't set transaction level required to run the web script:
<transaction>none</transaction>
Thus, methods writeContent() and createFileNode() were transactional by default and each of them created its own version of the content.
I set the following:
<transaction>requiresnew</transaction>
The problem is solved. Thank you, #Axel Faust!
I need to automate links in my website. I want to pass xpath values once in each iteration of loop. So that I can minimize my coding
public class Popup
{
private WebDriver driver;
private String baseUrl;
//private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();
#Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseUrl = "http://www.example.com/info.php";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void testPopup() throws Exception {
driver.findElement(By.xpath("//div[#id='info-list']/div[2]/div/div/div/div/a[2]/i")).click();
driver.findElement(By.xpath("//div[#id='info-list']/div[2]/div/div/div/div/a[3]/i")).click();
driver.findElement(By.xpath("//div[#id='info-list']/div[2]/div/div/div/div/a[4]/i")).click();
driver.findElement(By.xpath("//div[#id='info-list']/div[2]/div/div/div/div/a[5]/i")).click();
Can you try this?
for(int j=2; j<=5; j++) {
driver.findElement(By.xpath("//div[#id='info-list']/div[2]/div/div/div/div/a["+j+"]/i")).click();
}
Hi Sanchit Khera Try this one :
int i = 0;
//extract the link texts of each link element
for (WebElement e : linkElements)
{
linkTitles[i] = e.getText();
i++;
}
//Test each link
for (String t : linkTitles)
{
// Titles Click
driver.findElement(By.linkText(t)).click();
Good day, everyone! I have a little question about testing and generating a stub for dependence through reflection. So let's assume I have a class named UnderTest:
class UnderTest{
/*field*/
SomeLogic someLogic;
/*method, that i testing*/
List<MyObject> getCalculatedObjects(params) {/*logic,based on result getSomeStuff of someLogic*/ }
}
class SomeLogic {
List<String> getSomeStuff(String param) { /*Some complex and slow code, actually don't want test this code, and want to use some reflection invocation handler*/ }
}
For me it's important to not change legacy code, which doesn't design for testing. And i don't have any reason, except testing to make SomeLogic as an interface and so on.
I can't remember how to handle method invocation of someLogic using reflection. But google search isn't helping me.
Class MainAPI is... main api of my module. NetworkProvider long open stream operation, that's why i want to stub it, on my local files. But don't using directly reference on NetworkProvider. Again sorry for my English.
public class MainAPI {
private final XPath xPath;
private final ItemParser itemParser;
private final ListItemsParser listItemsParser;
private final DateParser dateParser;
private final HtmlCleanUp htmlCleanUp;
private final NetworkProvider networkProvider;
public MainAPI(XPath xPath, ItemParser itemParser, ListItemsParser listItemsParser, DateParser dateParser, HtmlCleanUp htmlCleanUp, NetworkProvider networkProvider) {
this.xPath = xPath;
this.itemParser = itemParser;
this.listItemsParser = listItemsParser;
this.dateParser = dateParser;
this.htmlCleanUp = htmlCleanUp;
this.networkProvider = networkProvider;
}
public MainAPI() throws XPathExpressionException, IOException {
dateParser = new DateParser();
xPath = XPathFactory.newInstance().newXPath();
networkProvider = new NetworkProvider();
listItemsParser = new ListItemsParser(xPath, dateParser, item -> true);
itemParser = new ItemParser(xPath, dateParser, networkProvider);
htmlCleanUp = new HtmlCleanUpByCleaner();
}
public List<Item> getItemsFromSessionParsing(SessionParsing sessionParsing) {
listItemsParser.setCondition(sessionParsing.getFilter());
List<Item> result = new ArrayList<>();
Document cleanDocument;
InputStream inputStream;
for (int currentPage = sessionParsing.getStartPage(); currentPage <= sessionParsing.getLastPage(); currentPage++) {
try {
inputStream = networkProvider.openStream(sessionParsing.getUrlAddressByPageNumber(currentPage));
} catch (MalformedURLException e) {
e.printStackTrace();
break;
}
cleanDocument = htmlCleanUp.getCleanDocument(inputStream);
List<Item> list = null;
try {
list = listItemsParser.getList(cleanDocument);
} catch (XPathExpressionException e) {
e.printStackTrace();
break;
}
for (Item item : list) {
inputStream = null;
try {
inputStream = networkProvider.openStream("http://www.avito.ru" + item.getUrl());
} catch (MalformedURLException e) {
e.printStackTrace();
break;
}
cleanDocument = htmlCleanUp.getCleanDocument(inputStream);
try {
item.setDescription(itemParser.getDescription(cleanDocument));
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
result.addAll(list);
}
return result;
}
}
public class NetworkProvider {
private final ListCycleWrapper<Proxy> proxyList;
public NetworkProvider(List<Proxy> proxyList) {
this.proxyList = new ListCycleWrapper<>(proxyList);
}
public NetworkProvider() throws XPathExpressionException, IOException {
this(new ProxySiteParser().getProxyList(new HtmlCleanUpByCleaner().getCleanDocument(new URL("http://www.google-proxy.net").openStream())));
}
public int getSizeOfProxy() {
return proxyList.size();
}
public InputStream openStream(String urlAddress) throws MalformedURLException {
URL url = new URL(urlAddress);
while (!proxyList.isEmpty()) {
URLConnection con = null;
try {
con = url.openConnection(proxyList.getNext());
con.setConnectTimeout(6000);
con.setReadTimeout(6000);
return con.getInputStream();
} catch (IOException e) {
proxyList.remove();
}
}
return null;
}
}
All the dependencies of your class to tests are injectable using its constructor, so there shouldn't be any problem to stub these dependencies and injecting the stubs. You don't even need reflection. For example, using Mockito:
NetworkProvider stubbedNetworkProvider = mock(NetworkProvider.class);
MainAPI mainApi = new MainAPI(..., stubbedNetworkProvider);
You can also write a stub by yourself if you want:
NetworkProvider stubbedNetworkProvider = new NetworkProvider(Collections.emptyList()) {
// TODO override the methods to stub
};
MainAPI mainApi = new MainAPI(..., stubbedNetworkProvider);
Has anyone an idea about what is wrong with my attempt to call a method from a C# dll in my Java code?
Here is my example:
Java code:
public class CsDllHandler {
public interface IKeywordRun extends Library {
public String KeywordRun(String action, String xpath, String inputData,
String verifyData);
}
private static IKeywordRun jnaInstance = null;
public void runDllMethod(String action, String xpath, String inputData,
String verifyData) {
NativeLibrary.addSearchPath(${projectDllName},
"${projectPath}/bin/x64/Debug");
jnaInstance = (IKeywordRun) Native.loadLibrary(
${projectDllName}, IKeywordRun.class);
String csResult = jnaInstance.KeywordRun(action, xpath, inputData,
verifyData);
System.out.println(csResult);
}
}
And in C#:
[RGiesecke.DllExport.DllExport]
public static string KeywordRun(string action, string xpath, string inputData, string verifyData) {
return "C# here";
}
The Unmanaged Exports nuget should be enough for me to call this method (in theory) but I have some strange error:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokePointer(Native Method)
at com.sun.jna.Function.invokePointer(Function.java:470)
at com.sun.jna.Function.invokeString(Function.java:651)
at com.sun.jna.Function.invoke(Function.java:395)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at com.sun.proxy.$Proxy0.KeywordRun(Unknown Source)
at auto.test.keywords.utils.CsDllHandler.runDllMethod(CsDllHandler.java:34)
at auto.test.keywords.runner.MainClass.main(MainClass.java:24)
Well, after another day of research and "trial and error" I have found the cause of my problem and a solution.
The cause was that my C# dll had a dependency on log4net.dll. For running a static method from a standalone C# dll the code from the question is all you need.
The solution for using C# dll with dependencies is to create another dll with no dependency and to load the original dll in this adapter with reflection. In Java you should load the adapter dll with jna and call any exported method. I was able not only to execute methods from the adapter but also to configure log4net with reflection and Java
Here is my code:
(C#)
public class CSharpDllHandler {
private static Logger log = Logger.getLogger(CSharpDllHandler.class);
public interface IFrameworkAdapter extends Library {
public String runKeyword(String action, String xpath, String inputData,
String verifyData);
public String configureLog4net(String log4netConfigPath);
public String loadAssemblies(String frameworkDllPath,
String log4netDllPath);
}
private static IFrameworkAdapter jnaAdapterInstance = null;
private String jnaSearchPath = null;
public CSharpDllHandler(String searchPath) {
this.jnaSearchPath = searchPath;
// add to JNA search path
System.setProperty("jna.library.path", jnaSearchPath);
// load attempt
jnaAdapterInstance = (IFrameworkAdapter) Native.loadLibrary(
"FrameworkAdapter", IFrameworkAdapter.class);
}
public String loadAssemblies(String frameworkDllPath, String log4netDllPath) {
String csResult = jnaAdapterInstance.loadAssemblies(frameworkDllPath,
log4netDllPath);
log.debug(csResult);
return csResult;
}
public String runKeyword(String action, String xpath, String inputData,
String verifyData) {
String csResult = jnaAdapterInstance.runKeyword(action, xpath,
inputData, verifyData);
log.debug(csResult);
return csResult;
}
public String configureLogging(String log4netConfigPath) {
String csResult = jnaAdapterInstance
.configureLog4net(log4netConfigPath);
log.debug(csResult);
return csResult;
}
public String getJnaSearchPath() {
return jnaSearchPath;
}
}
In the main method just use something like this:
CSharpDllHandler dllHandler = new CSharpDllHandler(
${yourFrameworkAdapterDllLocation});
dllHandler.loadAssemblies(
${yourOriginalDllPath},${pathToTheUsedLog4netDllFile});
dllHandler.configureLogging(${log4net.config file path});
dllHandler.runKeyword("JAVA Action", "JAVA Xpath", "JAVA INPUT",
"JAVA VERIFY");
dllHandler.runKeyword("JAVA Action2", "JAVA Xpath2", "JAVA INPUT2",
"JAVA VERIFY2");
In C# I have the desired methods on the original dll:
public static string KeywordRun(string action, string xpath, string inputData, string verifyData) {
log.Debug("Action = " + action);
log.Debug("Xpath = " + xpath);
log.Debug("InputData = " + inputData);
log.Debug("VerifyData = " + verifyData);
return "C# UserActions result: "+ action+" "+xpath+" "+inputData+" "+verifyData;
}
and all the magic is in the DLL Adapter:
namespace FrameworkAdapter {
[ComVisible(true)]
public class FwAdapter {
private const String OK="OK";
private const String frameworkEntryClassName = "${nameOfTheDllClass with method to run }";
private const String log4netConfiguratorClassName = "log4net.Config.XmlConfigurator";
private static Assembly frameworkDll = null;
private static Type frameworkEntryClass = null;
private static MethodInfo keywordRunMethod = null;
private static Assembly logDll = null;
private static Type logEntryClass = null;
private static MethodInfo logConfigureMethod = null;
private static String errorMessage = "OK";
[RGiesecke.DllExport.DllExport]
public static string loadAssemblies(string frameworkDllPath, string log4netDllPath) {
try {
errorMessage = LoadFrameworkDll(frameworkDllPath, frameworkEntryClassName);
LoadFrameworkMethods("KeywordRun", "Setup", "TearDown");
errorMessage = LoadLogAssembly(log4netDllPath, log4netConfiguratorClassName);
if (errorMessage.CompareTo(OK) == 0)
errorMessage = LoadLogMethods("Configure");
}
catch (Exception e) {
return e.Message;
}
return errorMessage;
}
[RGiesecke.DllExport.DllExport]
public static string configureLog4net(string log4netConfigPath) {
if (errorMessage.CompareTo("OK") == 0) {
StringBuilder sb = new StringBuilder();
sb.AppendLine("Try to configure Log4Net");
try {
FileInfo logConfig = new FileInfo(log4netConfigPath);
logConfigureMethod.Invoke(null, new object[] { logConfig });
sb.AppendLine("Log4Net configured");
}
catch (Exception e) {
sb.AppendLine(e.InnerException.Message);
}
return sb.ToString();
}
return errorMessage;
}
[RGiesecke.DllExport.DllExport]
public static string runKeyword(string action, string xpath, string inputData, string verifyData) {
StringBuilder sb = new StringBuilder();
object result = null;
try {
result = keywordRunMethod.Invoke(null, new object[] { action, xpath, inputData, verifyData });
sb.AppendLine(result.ToString());
}
catch (Exception e) {
sb.AppendLine(e.InnerException.Message);
}
return sb.ToString();
}
private static String LoadFrameworkDll(String dllFolderPath, String entryClassName) {
try {
frameworkDll = Assembly.LoadFrom(dllFolderPath);
Type[] dllTypes = frameworkDll.GetExportedTypes();
foreach (Type t in dllTypes)
if (t.FullName.Equals(entryClassName)) {
frameworkEntryClass = t;
break;
}
}
catch (Exception e) {
return e.InnerException.Message;
}
return OK;
}
private static String LoadLogAssembly(String dllFolderPath, String entryClassName) {
try {
logDll = Assembly.LoadFrom(dllFolderPath);
Type[] dllTypes = logDll.GetExportedTypes();
foreach (Type t in dllTypes)
if (t.FullName.Equals(entryClassName)) {
logEntryClass = t;
break;
}
}
catch (Exception e) {
return e.InnerException.Message;
}
return OK;
}
private static String LoadLogMethods(String logMethodName) {
try {
logConfigureMethod = logEntryClass.GetMethod(logMethodName, new Type[] { typeof(FileInfo) });
}
catch (Exception e) {
return e.Message;
}
return OK;
}
private static void LoadFrameworkMethods(String keywordRunName, String scenarioSetupName, String scenarioTearDownName) {
///TODO load the rest of the desired methods here
keywordRunMethod = frameworkEntryClass.GetMethod(keywordRunName);
}
}
}
Running this code will provide all the logged messages from the original C# DLL to the Java console output (and to a file if configured). In a similar way, we can load any other needed dll files for runtime.
Please forgive my [very probable wrong] way of doing things in C# with reflection, I'm new to this language.