B4J Library Selenium Library - Pnd_Selenium

Selenium automates browsers. That's it!
What you do with that power is entirely up to you.
Primarily it is for automating web applications for testing purposes, but is certainly not limited to just that.
Boring web-based administration tasks can (and should) also be automated as well.

Wrapper is based on Selenium Java v4.27.0 (November 25, 2024) from HERE.


Versions:

v0.70

  • Removed ActionSendNonTextKey, as it not needed anymore
  • Now you can send multiple special keys at once, for example CTRL+A (select all)
  • Selenium is no longer connected to the version of Chrome browser installed on your computer
  • New KeyCodes class for special keys
  • New example app
  • Selenium upgrade to v4.27.0

v0.80
  • New Cookies class
  • New example app

v0.81
  • New functions like: WebElementIsSelected, WebElementIsDisplayed, etc. for direct interaction with WebElement objects
  • Support for Alerts - modal dialogs
  • Better documentation
  • New example app

v0.85
  • Return List As Objects of WebElement, to be able to interact with WebElement inside List
  • New option: ExecuteAsyncScript
  • New timeout options: ImplicitlyWait, PageLoadTimeout and ScriptTimeout for ExecuteAsyncScript
  • ExecuteAsyncScript and ExecuteScript (synchronous) return String as value if return or callback statement exists
  • New example app

v0.90
  • New class LogLevel
  • Removed one old class
  • Now is possible to use nested WebElements
  • Every FindBy function as first argument can use WebElement object
  • New example apps


Examples:

Selenium1.zip

  • How to setup Chrome for Testing and Chrome Driver
  • Where to find and how to setup Argument for Chrome
  • Cookies: get, get all, add, edit, delete, delete all
  • ExecuteScript, ExecuteAsyncScript
  • Fill form and submit form
  • General library usage examples

Selenium2.zip
  • How to get all links from the page with FindByTagNameList
  • How to get all links from the page with FindByXPathList
  • How to filter links
  • How to get all TD text from all TABLES from all pages
  • How to navigate from page to page without revisiting already visited links

Download library from: https://www.dropbox.com/scl/fi/yqdu...ey=91dfe0o19u45xqsebd2j26yth&st=jheflmt1&dl=0

When you download Chrome For Testing as well as the Chrome Driver, make sure to extract everything into one folder.
chrome.exe and chromedriver.exe should be in same folder.
For Windows use:
Chrome For Testing: https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.204/win64/chrome-win64.zip
Chrome Driver: https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.204/win64/chromedriver-win64.zip

If you are using other OS download Chrome For Testing and Chrome Driver from: https://googlechromelabs.github.io/chrome-for-testing/
Latest library version is tested with Chrome For Testing and Chrome Driver v131.0.6778.204
 

Attachments

  • Selenium1.zip
    4.6 KB · Views: 3
  • Selenium2.zip
    2.9 KB · Views: 1
Last edited:

Pip

Member
Hi Pendrush,

first of all, thanks a lot for this Selenium library !

I only despair at the moment with Chrome's automation, after pressing a button opens a new tab and thus the CurrentUrl is no longer correct.

Thus the question: "How can I set the focus on the new TAB and thus continue to work in it?"

Thanks in advance !

With kind regards
Pip
 

Pendrush

Well-Known Member
Licensed User
Longtime User
Library updated to v0.6, to switch tab use code:
B4X:
Dim TabName As String
For Each name As String In Selenium.AllTabs
    TabName = name
Next
Selenium.SwitchToTab(TabName)
 

Pip

Member
Hi Pendrush,

the change to the new TAB works only conditionally. The CurrentURL changes apparently, but certain elements on this TAB are unfortunately still not findable.

As an example:
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method": "css selector", "selector": "body#body>header>form>div>div>button"}

it doesn't matter if I search with CSS selector or XPath, the element remains untraceable.

Even if I close the old TAB before executing the For Each loop, this has no effect.

I try to address a textbox and next a button. Despite the correct linking I get "No Search element" displayed. It seems to me that the website blocks such controls.

Try:
By simulating the Tab key, I navigate to the textbox and would now only need a routine to pass a text, unfortunately I am missing the element here and pure keyboard input cannot be sent, also CTRL+V fails unfortunately.

Would you still have an idea for me ?
 

Pip

Member
Sorry for double post,

is there a way to disable the message "Chrome is being controlled by automated test software" and suggest to the web server that there is no underlying automation? I have not been able to solve it via startup parameters.

As an example:
I try to log in to the UPS website, automated by Chromedriver I get an "Access Denied" message.

So I would have to make it so that the web server does not notice that it is an automation software. Is there a solution for this problem?

Thanks a lot in advance !
 
Last edited:

Anser

Well-Known Member
Licensed User
Longtime User
Maybe the elements that you are trying to access are inside a Frame.
Switch to that particular frame first using the SwitchToFrame() and then try to access those elements
 

Pip

Member
Maybe the elements that you are trying to access are inside a Frame.
Switch to that particular frame first using the SwitchToFrame() and then try to access those elements
SwitchToFrame() was a good hint ! Thank you, I could then access the element via XPath !

Ok, so this works now, but how do I solve the problem that the UPS website (completely different website) recognizes that it is an automation ? Do you have a tip for me ?

Thank you
 

Pendrush

Well-Known Member
Licensed User
Longtime User
Maybe you can try to change user agent, for example:
B4X:
Selenium.AddArgument("--user-agent=Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
You can also try some other user agent from different browsers.
 

Pip

Member
Hello Pendrush,

I had
B4X:
Selenium.AddArgument("--user-agent=Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
tested once via https://botcheck.luminati.io/ with the following result:
Navigate type
FAIL user-agent: missing user-agent header

Other test with
B4X:
Selenium.AddArgument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
gave the following:


Both attempts ended in "Access Denied" so far. I will test more user agents.
 

Pendrush

Well-Known Member
Licensed User
Longtime User
Maybe:
B4X:
Selenium.AddArgument("-–disable-blink-features=AutomationControlled")
 

kostefar

Active Member
Licensed User
Longtime User
I hope this thread is not too old to add a bit to it. If so, please let me know, and I´ll start a new one.

I´ve installed Selenium, but fail to get the demo working. I´m using the latest chromedriver, which is 111.0.5563.65, whereas the chromedriver is for 111.0.5563.64, so not sure if that´s what´s causing the below:


B4X:
WARNING: package com.sun.javafx.embed.swing.oldimpl not in javafx.swing
Waiting for debugger to connect...
Program started.
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Starting ChromeDriver 111.0.5563.64 (c710e93d5b63b7095afe8c2c17df34408078439d-refs/branch-heads/5563@{#995}) on port 14376
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.
mar. 15, 2023 3:13:57 PM org.openqa.selenium.remote.http.WebSocket$Listener onError
WARNING: Invalid Status code=403 text=Forbidden
java.io.IOException: Invalid Status code=403 text=Forbidden
    at org.asynchttpclient.netty.handler.WebSocketHandler.abort(WebSocketHandler.java:92)
    at org.asynchttpclient.netty.handler.WebSocketHandler.handleRead(WebSocketHandler.java:118)
    at org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelRead(AsyncHttpClientHandler.java:78)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:336)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:444)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:280)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:832)
Error occurred on line: 24 (Main)
org.openqa.selenium.remote.http.ConnectionFailedException: Unable to establish websocket connection to http://localhost:53946/devtools/browser/372efec7-19e0-4f6b-9c7f-ede143289bf0
Build info: version: '4.7.2', revision: '4d4020c3b7'
System info: os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '14.0.1'
Driver info: driver.version: ChromeDriver
    at org.openqa.selenium.remote.http.netty.NettyWebSocket.<init>(NettyWebSocket.java:102)
    at org.openqa.selenium.remote.http.netty.NettyWebSocket.lambda$create$3(NettyWebSocket.java:128)
    at org.openqa.selenium.remote.http.netty.NettyClient.openSocket(NettyClient.java:107)
    at org.openqa.selenium.devtools.Connection.<init>(Connection.java:78)
    at org.openqa.selenium.chromium.ChromiumDriver.lambda$new$2(ChromiumDriver.java:116)
    at java.base/java.util.Optional.map(Optional.java:258)
    at org.openqa.selenium.chromium.ChromiumDriver.<init>(ChromiumDriver.java:114)
    at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:82)
    at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:71)
    at com.pendrush.selenium.kotlin.SeleniumLib.initialize(SeleniumLib.kt:32)
    at com.pendrush.selenium.Wrapper.initialize2(Wrapper.java:39)
    at com.pendrush.selenium.Wrapper.Initialize(Wrapper.java:35)
    at b4j.example.main._appstart(main.java:78)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
    at b4j.example.main.start(main.java:38)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:832)

Thanks in advance!
 

Pip

Member

Hey kostefar,

Try this before Selenium.initialize:
B4X:
Selenium.addArgument("--remote-allow-origins=*")

It works fine for me !

Kind regards
Pip
 

kostefar

Active Member
Licensed User
Longtime User
Hey kostefar,

Try this before Selenium.initialize:
B4X:
Selenium.addArgument("--remote-allow-origins=*")

It works fine for me !

Kind regards
Pip
Thank you SO much Pip, now I´m one step further! How did you find out about that?
 

Pip

Member

Pip

Member
@Pendrush

Is there a possibility to set the "navigator.webdriver" flag to false ?

The Chromedriver starts with navigator.webdriver = true, so the website already knows about it. This flag would be false if the website is driven by a human.

Is it possible to make the chrome dev options accessible before the chrome browser starts and thus set the flag to false ?

If this already works with the current library, I wouldn't know exactly how to do it.

Thanks in advance !
 

syerif

Active Member
Licensed User
Longtime User


Hi,
it is possible with your library to scrolling browser like this..

Thank you
 

kostefar

Active Member
Licensed User
Longtime User
Would someone be able to get me started on something that looks like this in terms of filling in email address + password and clicking "Sign in"?

B4X:
<div class="form-group username">
            <label class="control-label" for="Email">Email</label>
            <input class="form-control" placeholder="Email Address" autocomplete="off" tabindex="1" spellcheck="false" type="text" data-val="true" data-val-required="The Email field is required." id="Email" name="Email" value="" />
            <span class="text-danger" id="unError" style="display:none;">Please enter a valid email address</span>
        </div>
            <div class="form-group password">
                <label class="control-label" for="Password">Password</label>
                <input type="password" class="form-control" placeholder="Password" autofocus="autofocus" autocomplete="off" tabindex="2" id="Password" name="Password" />
            </div>

        <div class="form-group">
            <label class="chk-label" for="RememberLogin">
                <input tabindex="4" type="checkbox" checked="checked" data-val="true" data-val-required="The Remember Login field is required." id="RememberLogin" name="RememberLogin" value="true" />
                Remember Login
            </label>
        </div>

        <div class="form-group">
            <button type="submit" id="SubmitLogin" tabindex="3">
                Sign in
            </button>
        </div>

Thanks in advance!

PS: I did already try different things using the example attached to the initial post as a template, but with no luck so far.
 
Last edited:

behnam_tr

Active Member
Licensed User
Longtime User
@Pendrush
thanks for great library

please can you add method for execute java script code ??
i need to Modify innerHTML
like this :
B4X:
<span class="locked-step"></span>

to

<span class="showStepsButton"></span>

 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…