GEB: driver is not set as Browser.driver - java

I'm writing tests with GEB and Spock (I'm new to both).
Driver is declared in GebConfig (updated - the full config file added):
import geb.report.ReportState
import geb.report.Reporter
import geb.report.ReportingListener
import io.github.bonigarcia.wdm.WebDriverManager
import io.qameta.allure.Allure
import org.openqa.selenium.Dimension
import org.openqa.selenium.Point
import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.chrome.ChromeOptions
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.firefox.FirefoxOptions
import org.openqa.selenium.firefox.FirefoxProfile
import org.slf4j.LoggerFactory
import utils.Configuration
def logger = LoggerFactory.getLogger(this.class)
baseUrl = "${Configuration.getStringProperty("BASE_URL")}/${Configuration.getStringProperty("CONTEXT_PATH")}"
baseNavigatorWaiting = true
autoClearCookies = false
cacheDriver = false
reportsDir = 'build/test-reports'
driver = {
WebDriver dr
switch (Configuration.getStringProperty("BROWSER_NAME", "chrome").trim().toLowerCase()) {
case "firefox":
case "ff":
dr = new FirefoxDriver(setUpFirefoxOptions())
break
case "google chrome":
case "chrome":
default:
dr = new ChromeDriver(setUpGoogleChromeOptions())
}
if (Configuration.getBooleanProperty("SET_DRIVER_POSITION", false)) {
dr.manage().window().setPosition(new Point(
Configuration.getIntProperty("BROWSER_X_POS", 0),
Configuration.getIntProperty("BROWSER_Y_POS", 0)))
dr.manage().window().setSize(new Dimension(
Configuration.getIntProperty("BROWSER_WIDTH", 1600),
Configuration.getIntProperty("BROWSER_HEIGHT", 900)));
} else {
dr.manage().window().maximize()
}
return dr
}
static ChromeOptions setUpGoogleChromeOptions() {
WebDriverManager.chromedriver().setup()
ChromeOptions options = new ChromeOptions()
String args = Configuration.getStringProperty("BROWSER_ARGS")
if (args) {
Arrays.stream(args.split("\\s")).each { options.addArguments(it) }
}
return options
}
static FirefoxOptions setUpFirefoxOptions() {
WebDriverManager.firefoxdriver().setup()
FirefoxOptions options = new FirefoxOptions()
FirefoxProfile profile = new FirefoxProfile()
profile.setPreference("network.automatic-ntlm-auth.trusted-uris", "http://,https://")
options.setProfile(profile).setLegacy(false)
return options
}
reportingListener = new ReportingListener() {
void onReport(Reporter reporter, ReportState reportState, List<File> reportFiles) {
def fileGroups = reportFiles.groupBy { it.name.split("\\.")[-1] }
fileGroups['png']?.each {
Allure.addAttachment(it.name, "image/png", new FileInputStream(it), "png")
}
}
}
Test example looks like (BaseTest code is added below):
class SimulationsRunningSpec extends BaseTest {
def "My great test"() {
println("test started")
setup:
to LoginPage
when:
println("when")
then:
println("then")
}
def cleanupSpec() {
browser.quit()
println "Clean up specification"
}
}
And I get the following log sequence:
test started
Created driver
when
then
Created driver
Clean up specification
So the driver gets created when to LoginPage is called.
Issue:
It is not set as Browser driver, so when the browser.quit() is called, a new instance is created and then closed (the first one still is opened).
Questions:
How to set the driver to browser properly to close it then via browser.quit()?
Am I right assuming that if I need to create a driver in setupSpec I can simply call to LoginPage there? Or what is the best way to init the driver in preconditions?
UPDATE:
After some debugging I found out that for some reason, browser gecomes null and is created again in cleanupSpec(). It doesn't matter whether the Spec extends Geb classes of custom base class. This reproduces my issue:
class TestSpec extends GebReportingSpec {
def setupSpec() {
to Page
println "setupSpec browser: $browser"
}
def setup(){
println "setup browser: $browser"
}
def "My first test"() {
println("test started")
when:
println ''
then:
println ''
}
def cleanup() {
println "cleanup browser: $browser"
}
def cleanupSpec() {
println "cleanupSpec browser: $browser"
}
}
This produces the following output:
setupSpec browser: geb.Browser#4beeb0e
setup browser: geb.Browser#4beeb0e
test started
cleanup browser: geb.Browser#4beeb0e
cleanupSpec browser: geb.Browser#5c73f672
The last two rows show that the browser object in cleanupSpec is different from created object in setupSpec.

I'm not sure, why the browser was closed before your cleanupSpec. Probably some other mechanism already took care of it.
The fact that you are getting a different instance in your cleanupSpec however is simply due to the fact, that getBrowser is implemented as a lazy getter. It creates a new instance if necessary, as you can see in the code.
Generally you don't need to call browser.quit using Geb. Geb takes care of that just fine.
Update
Here is what happens in GebSpec and YourSpec:
GebSpec.setupSpec is triggered ⇒ _browser is null
YourSpec.setupSpec is triggered ⇒ _browser is still null unless you use it here
GebSpec.setup is triggered ⇒ _browser is not changed
YourSpec.setup is triggered ⇒ _browser might be changed
YouSpec's first feature is triggered ⇒ _browser is used, so it won't be null anymore
YourSpec.cleanup is triggered ⇒ _browser is not changed
GebSpec.cleanup is triggered ⇒ _browser is set to null! As you can see in the code, resetBrowser is called unless YourSpec is #Stepwise and that sets _browser to null as you can see here.
YourSpec.cleanupSpec is triggered ⇒ _browser is null unless you use it, so it gets reinitialized
GebSpec.cleanupSpec is triggered ⇒ _browser is still null

This seems strange that you are seeing the browser reinitialise for the cleanup, what you have shown is correct.
For point 1: You are setting it correctly within the gebconfig.
For point 2: You don't need to initialise the browser within the setupSpec(), the config entry is all you need.
The browser should close automatically once all tests are run, UNLESS you have added the following to your gebconfig and set to false:
quitCachedDriverOnShutdown = false
setupSpec() is called after all methods within the spec have been run. Is what you have shown us the only code within your spec? Is your spec extending GebSpec or GebReportingSpec or a custom base class?
The only other thing i can think is that you have 2 tests in that spec, so you're seeing "Created driver" twice, and the cleanUpSpec() is called after all tests are run so you see that called at the end. If you had called cleanup() it would run between each test.

Related

Clear all notification from notification bar of any android device using appium

How to clear all notification from notification bar in android using appium in any of the android devices.
I tried
MobileElement clearallnotification=null;
driver.openNotifications();
try {
clearallnotification= driver.findElement(By.xpath("//android.widget.ImageView[contains(#content-desc, 'Clear all notifications')]"));
clearallnotification.click();
}catch(ElementNotFoundException e) {
clearallnotification= driver.findElementById("com.android.systemui:id/delete");
clearallnotification.click();
}
driver.pressKeyCode(AndroidKeyCode.BACK);
But It works only for specific devices how to make it generic for all kind of devices?
The below code will do that. It worked for me.
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
from time import sleep
import pytest
class TestScrollAndroid:
"Class to run tests against the Chess Free app"
#pytest.fixture(scope='function')
def driver(self, request):
"Setup for the test"
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '8.1.0'
desired_caps['deviceName'] = 'Realme 2 Pro'
desired_caps['noReset'] = True
desired_caps['udid'] = '2032609e'
desired_caps['allowTestPackages'] = True
# Returns abs path relative to this file and not cwd
desired_caps['app'] = "D:\\Chess Free.apk"
desired_caps['appPackage'] = 'uk.co.aifactory.chessfree'
desired_caps['appActivity'] = '.ChessFreeActivity'
#desired_caps['autoWebview'] = True
#calling_request = request._pyfuncitem.name
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
driver.implicitly_wait(10)
def tearDown():
print("Tear down the test")
driver.quit()
request.addfinalizer(tearDown)
return driver
def test_scroll_notificaion(self,driver):
driver.open_notifications()
def test_clear_all_notification(self, driver):
driver.open_notifications()
if(driver.find_elements_by_id("com.android.systemui:id/clear_all_button"))
element = driver.find_element_by_id("com.android.systemui:id/clear_all_button")
element.click()
assert(not driver.find_elements_by_id("android:id/title"))
If you use Webdriver.IO here is the solution:
$('~Clear,Button').click()

Scala URLClassLoader is not reloading class file

I am running a scala project where I need to execute some rules. The rules will be dynamically added or removed from scala class file at runtime.
So, I want whenever the rules class modify, it should reload to get the changes without stopping the execution process.
I used runtime.getruntime.exec() to compile it
and am URL Class loader to get the modified code from classes
The exec() run fines. and in target folder classes gets modifies also, even when I am using URL Class Loader, not getting any error.
But it is giving me same result which i have on starting of the project. It's not giving me modification code.
Below is the code which I am using.
package RuleEngine
import akka.actor._
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import akka.util.Timeout
import scala.io.StdIn
import Executor.Compute
import scala.concurrent.{Await, ExecutionContextExecutor}
import scala.concurrent.duration._
object StatsEngine {
def main(args: Array[String]) {
implicit val system: ActorSystem = ActorSystem("StatsEngine")
implicit val materializer: ActorMaterializer = ActorMaterializer()
implicit val executionContext: ExecutionContextExecutor = system.dispatcher
implicit val timeout = Timeout(10 seconds)
val computeDataActor = system.actorOf(Props[Compute],"ComputeData")
val route = {
post {
path("computedata"/) {
computeDataActor ! "Execute"
complete("done")
}
}
}
val bindingFuture = Http().bindAndHandle(route , "localhost", 9000)
println(s"Server online at http://localhost:9000/\nPress RETURN to stop...")
}
}
This is the main object file where I have created Akka HTTP to make API's
It will call computeDataActor whose code is below.
package Executor
import java.io.File
import java.net.URLClassLoader
import CompiledRules.RulesList
import akka.actor.Actor
class Compute extends Actor{
def exceuteRule(): Unit ={
val rlObj = new RulesList
rlObj.getClass.getDeclaredMethods.map(name=>name).foreach(println)
val prcs = Runtime.getRuntime().exec("scalac /home/hduser/MStatsEngine/Test/RuleListCollection/src/main/scala/CompiledRules/RuleList.scala -d /home/hduser/MStatsEngine/Test/RuleListCollection/target/scala-2.11/classes/")
prcs.waitFor()
val fk = new File("/home/hduser/MStatsEngine/Test/RuleListCollection/target/scala-2.11/classes/").toURI.toURL
val classLoaderUrls = Array(fk)
val urlClassLoader = new URLClassLoader(classLoaderUrls)
val beanClass = urlClassLoader.loadClass("CompiledRules.RulesList")
val constructor = beanClass.getConstructor()
val beanObj = constructor.newInstance()
beanClass.getDeclaredMethods.map(x=>x.getName).foreach(println)
}
override def receive: Receive ={
case key:String => {
exceuteRule()
}
}
}
Rules are imported which is mentioned below.
package CompiledRules
class RulesList{
def R1 : Any = {
return "executing R1"
}
def R2 : Any = {return "executing R2"}
// def R3 : Any = {return "executing R3"}
//def R4 : Any = {return "executing R4"}
def R5 : Any = {return "executing R5"}
}//Replace
So, whene i execute code, and on calling API, I will get ouput as
R1
R2
R5
Now, without stopping the project, I will uncomment R3 and R4. And I will call API again,
As I am executing code again, using
runtime.getruntime.exec()
it will compile the file and update classes in target
So, i used URLClassLoader to get new object of modification code.
But Unfortunately I am getting same result always which i have on starting of the project
R1
R2
R5
Below is link for complete project
Source Code
val beanClass = urlClassLoader.loadClass("CompiledRules.RulesList")
val constructor = beanClass.getConstructor()
val beanObj = constructor.newInstance()
Is just creating the newInstance of Already loaded class.
Java's builtin Class loaders always checks if a class is already loaded before loading it.
loadClass
protected Class<?> loadClass(String name,
boolean resolve)
throws ClassNotFoundException
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
Invoke findLoadedClass(String) to check if the class has already been loaded.
Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
Invoke the findClass(String) method to find the class.
To reload a class you will have to implement your own ClassLoader subclass as in this link

Illegal Argument Exception in Appium framework

After (foolishly) upgrading Appium Server along with various project libraries, such that I cannot tell which, if any, caused the problem, my previously running Appium framework suddenly started failing upon attempting to locate any elements.
The server starts (either manually via desktop or through the java code) and it launches my emulator (if not already loaded), makes the connection, opens the app (in the case show, simply settings) and fails as soon as it tries to validate that the settings main page is displayed by checking the existence of the "Settings" text:
Given the settings app is displayed (FAILED)
(java.lang.IllegalArgumentException: Can not set
io.appium.java_client.android.AndroidElement field
com.mindtree.pageobjects.SettingsMainPage.header to
org.openqa.selenium.remote.RemoteWebElement$$EnhancerByCGLIB$$d27c0df4)
The Appium server versions for both desktop and nodeJS is currently 1.7.2 I believe the problem started when I was originally at 1.7.1 or 1.7.2 and it succeeded in doing an auto-update on the desktop version to 1.8.1.
Selenium version is 3.11.0 (tried various flavors from 3.9.0 through 3.13.0)
Appium Java client is 6.0.0-BETA5 (tried 6.0.0-BETA4, 6.0.0, 6.1.0)
Java is 1.8
The JBehave test step that reports the error:
#Given("the settings app is displayed")
public void givenTheSettingsAppIsDisplayed() {
main = new SettingsMainPage(driver);
if (main.pageLoaded())
test.logGivenPass("the settings app is displayed");
else {
test.logGivenFail("the settings app is displayed");
fail();
}
}
The corresponding page object snippet:
public class SettingsMainPage extends MobilePageObject {
public SettingsMainPage(AndroidDriver<AndroidElement> driver) {
super(driver);
System.out.println("Settings Main page class has been initialized");
}
#AndroidFindBy(xpath = "//android.widget.TextView[#text='Settings']")
AndroidElement header;
#AndroidFindBy(id= "android:id/title")
List<AndroidElement> titles;
#AndroidFindBy(id= "android:id/summary")
List<AndroidElement> summaries;
public Boolean pageLoaded() {
return helper.isDisplayed(header);
}
}
Googling this particular error returns a few hits, but no offered solutions.
Any guidance appreciated.
edit: I should add that the failure seems to happen upon initialization of the page object via the page factory, since the text "initialized" is never shown, it fails while trying to initialize all the page elements, specifically the first one, at least according to the error message.
My base page object is below:
import java.time.Duration;
import org.openqa.selenium.support.PageFactory;
import com.mindtree.helpers.AppiumUtils;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
public class MobilePageObject {
AndroidDriver<AndroidElement> driver;
AppiumUtils helper;
public MobilePageObject(AndroidDriver<AndroidElement> driver) {
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver, Duration.ofSeconds(15)), this);
helper = new AppiumUtils();
}
}
Edit Update: Downgraded the Appium Server through NodeJS from 1.7.2 to
1.7.1. Result: no change, same error reported.
I am using Appium server 1.8.1, selenium 3.13.0 and java client 6.1.0. I use the page object model like following and it works fine.
public class SettingsMainPage{
public SettingsMainPage(AndroidDriver<AndroidElement> driver) {
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
System.out.println("Settings Main page class has been initialized");
}
#AndroidFindBy(xpath = "//android.widget.TextView[#text='Settings']")
AndroidElement header;
#AndroidFindBy(id= "android:id/title")
List<AndroidElement> titles;
#AndroidFindBy(id= "android:id/summary")
List<AndroidElement> summaries;
public boolean pageLoaded() {
try{
(new WebDriverWait(driver, 20)).until(ExpectedConditions.visibilityOfElementLocated(header));
return header.isDisplayed();
}
catch(Exception e){
return false;
}
}
}
And you must define your desiredCapabilities like following:
public static AppiumDriver<MobileElement> driver;
public static AppiumDriver<MobileElement> setupDesiredCapabilities(String appPackage, String appActivity,
String udid, String platformVersion, boolean noReset) {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("deviceName", "Android phone"); //any name
caps.setCapability("udid", udid);
caps.setCapability("platformName", "Android");
caps.setCapability("platformVersion", platformVersion);
caps.setCapability("appPackage", appPackage);
caps.setCapability("appActivity", appActivity);
caps.setCapability("noReset", noReset); //optional
try {
driver = new AndroidDriver<MobileElement>(new URL(
"http://127.0.0.1:4723/wd/hub"), caps);
} catch (MalformedURLException e) {
//
} catch (Exception ex) {
//
}
return driver;
}
Make sure you have define static AppiumDriver and use the same
driver object to call constructor of each page.

How would I make my methods loop through an enum?

I have an Environment enum and an Application enum. Each application also has its own class which has a test for that app. I want to run each test in all the environments before it goes on to the next test. Here is part of what I have in the main method
for(Environment env :Environment.values())
{
new AccountInventory(env);
AccountInventory.accountInventoryTests(null, env);
new AuditActionItems( env);
AuditActionItems.auditActionItemTests(null, env);
new SalesPipeline(env);
SalesPipeline.salesPipelineTests(null, env);
Here is an example of what I have in a class
public static boolean accountInventoryTests(Application app, Environment env)
{
WebDriver driver = new InternetExplorerDriver();
try{
driver.get(env.getDomain() + Application.ACCOUNTINVENTORY.getContextRoot());
driver.findElement(By.name("j_username")).sendKeys(USER);
driver.findElement(By.name("j_password")).sendKeys(PASSWORD);
driver.findElement(By.cssSelector("input[type='submit']")).click();
Right now it runs all the tests in one environment, then runs all of them in the next environment. Thanks in advance.
Your code looks like that you doesn't need to iterate your application-enum for your test, because you access them in your test-methods(see Application.ACCOUNTINVENTORY.getContextRoot()).
If you realy want to iterate your enum, you can try mabye this:
for(Environment env :Environment.values())
{
new AccountInventory(env);
for(Application app: Application.values())
{
AccountInventory.accountInventoryTests(app, env);
}
new AuditActionItems( env);
for(Application app: Application.values())
{
AuditActionItems.auditActionItemTests(app, env);
}
...
}
Hope it helps

The method verifyTrue(boolean) is undefined for type

Chaps,
Newbie here so please be gentle!
I have a class where I am first trying to determine 'If' text
'Fictitious Test company' exsists anywehre on the page then I want to
click and delete that company 'Else' I want to add a new test
company..
problem I have is with follwing line:
if(verifyTrue(selenium.isTextPresent("Fictitious Test Company"))){;
Compiler keeps complains that the 'The method verifyTrue(boolean) is
undefined for the type Delete_old_Or_Add_New_Company' */
Can you please advise where am I going wrong? Please specific as to what i need to do to correct the problem.
Here is the whole code from my class:
- I am using xml to run my testsuite in Eclipse
package Realtime;
import com.thoughtworks.selenium.*;
import org.testng.annotations.*;
import static org.testng.Assert.*;
public class Delete_old_Or_Add_New_Company {
private Selenium selenium;
public static SeleneseTestBase SV = new
SeleneseTestBase();
#BeforeClass
#Parameters ({"url","browser","speed"})
public void startSelenium(String Site_URL, String Browser, String
Speed) {
selenium = new DefaultSelenium("localhost", 4444, Browser, Site_URL);
selenium.start();
selenium.setSpeed(Speed);
}
#AfterClass(alwaysRun=true)
public void stopSelenium() {
this.selenium.stop();
}
#Test
public void DeletOldOrAddNewCompany() throws Exception {
Login_Logout NewObject=new Login_Logout();
selenium.getEval("selenium.browserbot.setShouldHighlightElement(true)");
NewObject.Login(selenium);
selenium.waitForPageToLoad("5000");
selenium.click("//table[#id='maincontent']/tbody/tr/td[3]/table[2]/
tbody/tr[3]/td[5]/strong");
selenium.waitForPageToLoad("5000");
selenium.click("link=Companies");
selenium.waitForPageToLoad("5000");
selenium.click("//input[#value='Search for Companies']");
selenium.waitForPageToLoad("5000");
selenium.type("//input[#name=\"companyname\"]", "Fictitious Test
Company");
selenium.click("//input[#name=\"submitbutton\"]");
if(verifyTrue(selenium.isTextPresent("Fictitious Test Company"))){; /
* It is at this line the compiler complains that the 'The method
verifyTrue(boolean) is undefined for the type
Delete_old_Or_Add_New_Company' */
selenium.waitForPageToLoad("5000");
selenium.click("css=td.tablelastrownew");
selenium.waitForPageToLoad("5000");
selenium.click("//input[#value='Delete Company']");
assertTrue(selenium.getConfirmation().matches("^Note: This action
will delete all the companies accounts, branches, users and their
accounts\n\nAre you sure you wish to delete this company[\\s\\S]$"));
}
else {
selenium.click("//input[#value='Companies Admin Home']");
selenium.waitForPageToLoad("5000");
selenium.click("//input[#value='New Company']");
selenium.waitForPageToLoad("5000");
selenium.type("name=companyname", "Fictitious Test Company");
selenium.type("name=postcode", "SW17 8DY");
selenium.type("name=expirepasswordsindays", "1000");
selenium.click("css=input[name=\"submitbutton\"]");
selenium.waitForPageToLoad("5000");
SV.verifyTrue(selenium.isTextPresent("Fictitious Test Company"));
}
NewObject.Logout(selenium);
}
The compiler is correct. The verifyTrue method indeed doesn't exist in your class. Your class should extend SeleneseTestCase, where that method is defined.
Java is telling you that verifyTrue stands on it's own, it doesn't return a value so it doesn't need an if statement wrapped around it.
If the argument is false, the test will just fail and the test will stop right there.
I think what you want in that case is to leave out the "verifyTrue" part and just have the stuff inside it passed to the if.
You already created SeleneseTestBase instance "SV".
You should call "SV.verifyTrue". or, extend SeleneseTestBase.
*You already used this way.(else statements last line.)
SV.verifyTrue(selenium.isTextPresent("Fictitious Test Company"));
*at Selenium 2.0, SeleneseTestCase is deprecated class.
http://selenium.googlecode.com/svn/trunk/docs/api/java/com/thoughtworks/selenium/package-summary.html

Categories

Resources