Error using getWindowHandles in Selenium WebDriverJS - javascript

There is a question very similar to this asking how to do what I want to do, but the answer is not working for me. I do not have enough reputation to comment or ask for clarification on that yet.
I am using JavaScript and WebDriverJS with NodeJS
I am trying to switch to a new window that just opened up with a target=_blank link.
I seem to have boiled the problem down to driver.getWindowHandles() giving me an error.
Trimmed down Node js file:
var webdriver = require("selenium-webdriver");
var driver = new webdriver.Builder().usingServer().withCapabilities({'browserName': 'chrome' }).build();
driver.get('https://www.google.com');
driver.getTitle().then(function (title) {
console.log(title);
var handles = driver.getWindowHandles();
});
driver.getTitle().then(function (title) {
console.log(title);
});
This is what my command line looks like:
C:\selenium>node test2.js
Google
C:\selenium\node_modules\selenium-webdriver\lib\goog\async\nexttick.js:39
goog.global.setTimeout(function() { throw exception; }, 0);
^
TypeError: undefined is not a function
at C:\selenium\test2.js:8:23
at promise.ControlFlow.runInFrame_ (C:\selenium\node_modules\selenium-webdri
ver\lib\webdriver\promise.js:1877:20)
at promise.Callback_.goog.defineClass.notify (C:\selenium\node_modules\selen
ium-webdriver\lib\webdriver\promise.js:2464:25)
at promise.Promise.notify_ (C:\selenium\node_modules\selenium-webdriver\lib\
webdriver\promise.js:563:12)
at Array.forEach (native)
at Object.goog.array.forEach (C:\selenium\node_modules\selenium-webdriver\li
b\goog\array\array.js:203:43)
at promise.Promise.notifyAll_ (C:\selenium\node_modules\selenium-webdriver\l
ib\webdriver\promise.js:552:16)
at goog.async.run.processWorkQueue (C:\selenium\node_modules\selenium-webdri
ver\lib\goog\async\run.js:125:21)
at runMicrotasksCallback (node.js:337:7)
at process._tickCallback (node.js:355:11)
If I comment out the var handles... line then the script finishes with no error and prints the text "google" twice to the command prompt.

I figured it out!
1) The call is getAllWindowHandles in javascript. It drives me batty how each language api seems to have differently named methods for the same thing.
Reference for the webdriverJS webdriver class:
http://selenium.googlecode.com/git/docs/api/javascript/class_webdriver_WebDriver.html
2) The return is a promise, not the actual array I wanted, so it is easier to handle in a .then statement.
new code that prints out:
Google
[array of open window names]
Google
var webdriver = require("selenium-webdriver");
var driver = new webdriver.Builder().usingServer().withCapabilities({'browserName': 'chrome' }).build();
driver.get('https://www.google.com');
driver.getTitle().then(function (title) {
console.log(title);
driver.getAllWindowHandles().then(function (allhandles) {
console.log(allhandles);
});
});
driver.getTitle().then(function (title) {
console.log(title);
});

Related

TypeError: Assignment to constant variable ,After Changing it to let/var

Im trying to set the binary path of a binary of chrome with selenium, in javascript language.
unfortunately, my knowledge in javascript is limited, and Im getting an error while trying to do so, in which I cannot solve, despite my efforts.
so without further ado, I will now share my problem, with the hope that someone with a better knowledge in javascript then me, will help me
some background:
Im triggering a function in the firebase could functions,
inside this function , I'm trying to create a selenium webdriver.
in order to do so:
I need to do those things:
chromedriver --> that work on a linux system(located inside the functions project folder)✅
chrome browser binary that is located on this machine ✅
3.then, I need to create a a chrome Options object.
a. adding an Argument so it will be headless.✅
b. setting it with a path to the chrome binary.❌
and at last, create a chrome driver with options, that I have created
currently, I'm at stage 3.b
the error that rise coming from my poor knowledge in javascript
this is the error :
TypeError: Assignment to constant variable.
here what's lead to this error
this is my code :
exports.initializedChromeDriver = functions.https.onRequest((request, response) => {
async function start_chrome_driver() {
try {
functions.logger.info('Hello logs!', {structuredData: true});
console.log("did enter the function")
const google_site = "https://www.gooogle.com";
const { WebDriver } = require('selenium-webdriver');
const {Builder, By} = require('selenium-webdriver');
console.log("will try to initialzed chrome");
let chrome = require('selenium-webdriver/chrome');
console.log("did initialzed chrome");
var chrome_options = new chrome.Options()
console.log("will try to set the chrome binary Path");
functions.logger.info('new chrome.Options()', {structuredData: true});
chrome_options = chrome_options.setChromeBinaryPath(path="/usr/bin/google-chrome");// <------- THIS IS THE LINE THAT RISE THE ERROR!
console.log("did setChromeBinaryPath");
chrome_options.addArguments("--headless");
let buillder = new Builder().forBrowser('chrome');
functions.logger.info(' did new Builder().forBrowser(chrome)', {structuredData: true});
const google_site = 'https://wwww.google.com'
await driver.get(google_site);
functions.logger.info('driver did open google site', {structuredData: true});
return "succ loading google"
}
catch (err) {
console.log('did catch')
console.error(err);
return "error loading google";
}
}
const p = start_chrome_driver().then((value,reject) => {
const dic = {};
dic['status'] = 200;
dic['data'] = {"message": value};
response.send(dic);
});
and here's the error that follows this code in the firebase functions logs:
I tried to change the chrome_options object into var/let, and looking for answers in the web , but after deploying again, and again, and again.. I feel like its time to get another perspective, any help will do.
You have an unnecessary assignment here (path=...)
chrome_options = chrome_options.setChromeBinaryPath(path="/usr/bin/google-chrome");
Just remove the assignment to path
chrome_options = chrome_options.setChromeBinaryPath("/usr/bin/google-chrome");

How to get element by resource id?

I have spent some hours trying to search an element by id using appium javascript client with no luck. Have found some other posts here in stack overflow stating it works, but it doesn not work for me. It seems that I could use something like:
var buttonEl = await driver.findElement(By.id("resourceid"));
but I always get an error saying:
InvalidSelectorError: Locator Strategy 'css selector' is not supported for this session
Here the source code:
"use strict";
var wd = require("selenium-webdriver"),
By = wd.By,
until = wd.until;
// Setting Desired Capabilities.
var desiredCaps = {
platformName: "Android",
deviceName: "a3ae1c63",
appPackage: "com.mypackage",
appActivity: ".Main",
browserName: '',
noReset: true,
newCommandTimeout: 1000000
};
async function test() {
//Initiating the Driver
let driver = await new wd.Builder().usingServer("http://localhost:4723/wd/hub").withCapabilities(desiredCaps).build();
var buttonEl = await driver.findElement(By.id("id/contact_selector"));
buttonEl.click();
}
test();
I'm pretty confused now. I understand that it seems that I can't use the find element by id in an android session but on the other hand I have read about people using it successfully.
Any help would be greatly appreciated.
I think you are using selenium arguments for the locator strategy. Please readedocumentation of appium selector here http://appium.io/docs/en/commands/element/find-elements/index.html#selector-strategies.
try this
var buttonEl = await driver.element("id", "resource-id");
Finally I was able to fix my problem. The main problem was that I wasn't using the needed web driver. I switched to webdriverio and everything is working now.
Better place to start is to check examples in appium github. They have some examples for every driver. Code is a bit outdated though.

Ghostdriver 1.2.1 + PhantomJS 2.0 + latest Selenium Can't find variable error in Java

[ERROR - 2016-01-16T02:22:00.898Z] Session [e6651a90-bbf7-11e5-9061-cff578894101] - page.onError - msg: ReferenceError: Can't find variable: data
:262 in error
[ERROR - 2016-01-16T02:22:00.898Z] Session [e6651a90-bbf7-11e5-9061-cff578894101] - page.onError - stack:
(anonymous function) (http://www.example.com/ns/common/jquery/jquery.cartActions.js?cd=0:205)
o (http://www.example.com/images/common/jquery/jquery.latest.js:2)
fireWith (http://www.example.com/images/common/jquery/jquery.latest.js:2)
w (http://www.example.com/images/common/jquery/jquery.latest.js:4)
d (http://www.example.com/images/common/jquery/jquery.latest.js:4)
openUrl (:0)
open (:280)
(anonymous function) (:/ghostdriver/request_handlers/session_request_handler.js:495)
_execFuncAndWaitForLoadDecorator (:/ghostdriver/session.js:212)
_postUrlCommand (:/ghostdriver/request_handlers/session_request_handler.js:494)
_handle (:/ghostdriver/request_handlers/session_request_handler.js:91)
_reroute (:/ghostdriver/request_handlers/request_handler.js:61)
_handle (:/ghostdriver/request_handlers/router_request_handler.js:78)
:262 in error
^Domain edited out on purpose.
According to Can't find variable - PhantomJS this error has to do with not having proper jailed execution of Javascript. I don't understand what this means in the context of my Java program.
My Selenium program has only one kind of Javascript call, and it works like this:
((JavascriptExecutor) driver).executeScript("arguments[0].click();", buttonToClick);
The line above doesn't seem to be the issue because from my tests I can see that multiple lines like the above execute without error before coming to the above error.
Also, Session.NegotiatedCapabilities has "acceptSslCerts":false, which I have not been able to solve with this code block as the PhantomJS driver initializer:
String[] cli_args = new String[]{"--debug=false", "--web-security=false", "--ssl-protocol=any", "--ignore-ssl-errors=true"};
DesiredCapabilities caps = DesiredCapabilities.phantomjs();
caps.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cli_args);
caps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, "/Users/richard/Downloads/phantomjs-2.0.0-macosx/bin/phantomjs");
driver = new PhantomJSDriver(caps);
I can see that the arguments ARE being passed in on the Console...
Jan 16, 2016 6:23:40 AM org.openqa.selenium.phantomjs.PhantomJSDriverService <init>
INFO: arguments: [--web-security=no, --ignore-ssl-errors=yes, --webdriver=33238, --webdriver-logfile=/Users/richard/YeezyBot/phantomjsdriver.log]
Finally, everything works with Firefox WebDriver.
Injecting JavaScript to the web page or any other element is poor practice. You can find the Element using Selenium code and click on it without the use of any injection.
Wait for the page to be loaded
Find the button by CSS or Xpath expression
Wait for the element to by clickable
click on it using Selenium code only
WebDriverWait wait = new WebDriverWait(driver, timeToWait);
this.by = by;
try {
webElement lastFoundElement =
wait.until(ExpectedConditions.visibilityOfElementLocated(by));
wait.until(ExpectedConditions.elementToBeClickable(lastFoundElement ));
new Actions(browser).moveToElement(element, offsetX, offsetY).click().build().perform();
}
catch (Exception ex)
{
}

Setting service_args for phantomjs in selenium-webdriver for node

I need to be able to run phantomjs with the following arg:
--ignore-ssl-errors=true
The page I'm testing uses a self-signed cert so I need the arg to open the page. I'm trying to pass the arg in webdriver using the snippet below:
capabilities = webdriver.Capabilities.phantomjs();
capabilities.set('service_args', '--ignore-ssl-errors=true');
driver = new webdriver.Builder().
withCapabilities(capabilities).
build();
Is the correct way to pass the service_args? I actually hope not since I can't load my test page. I can open the page by running:
phantomjs --ignore-ssl-errors=true myTest.js
Here is the code in myTest.js
var page = new WebPage();
page.open('https://my.somefaketestpage.com/', function (status) {
just_wait();
});
function just_wait() {
setTimeout(function() {
page.render('screenshot.png');
phantom.exit();
}, 2000);
}
The correct answer is:
caps = new DesiredCapabilities();
caps.setJavascriptEnabled(true);
caps.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, new String[] {"--web-security=no", "--ignore-ssl-errors=yes"});
driver = new PhantomJSDriver(caps);
documented here: https://github.com/detro/ghostdriver/issues/233
In case someone will need it for facebook/php-webdriver CLI arguments can be passed to PhantomJS in a following manner:
$driver = RemoteWebDriver::create('http://localhost:4444/wd/hub', [
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
'phantomjs.cli.args' => ['--ignore-ssl-errors=true']
]);
Reading this I got really confused, as the accepted answer is in Java, and the GhostDriver constants and stuff aren't present. For those who are also confused, this worked for me:
var webdriver = require('selenium-webdriver'),
Capabilities = webdriver.Capabilities;
var capability = Capabilities
.phantomjs()
.set('phantomjs.cli.args', '--ignore-ssl-errors=true');
var driver = new webdriver
.Builder()
.withCapabilities(capability)
.build();

Selenium Webdriver (node.js) take screenshot and save test results

I started developing tests for a website application and I have some problems.
I'm using Node.js, webdriver, chromedriver and selenium rc.
The questions are:
1. How do I make a screenshot and save it in the same folder as the script.
2. Is there a way to save the test logs for a test case? For example, if check for an element on the page and don't find it, how do I output that?
For saving the test logs you typically use a test runner. When you check if an element is on the page and you can't find it then you raise an exception (typically an assertion error) and the test runner will record this and mark it as a failed test. In the documentation they suggest you use Mocha.
As for saving a screenshot to disk, the the api looks like this
driver.takeScreenshot().then(
function(image, err) {
require('fs').writeFile('out.png', image, 'base64', function(err) {
console.log(err);
});
}
);
Adapting aychedee's answer into a complete promise that will resolve after the file is written and reject on write failure:
const fsp = require('fs').promises
function takeScreenshot(driver, file){
return driver.takeScreenshot()
.then(image => fsp.writeFile(file, image, 'base64'))
}
Or in an ESM async function
import { writeFile } from 'node:fs/promises'
async function takeScreenshot(driver, file){
let image = await driver.takeScreenshot()
await writeFile(file, image, 'base64')
}
Just for the record, this is how you take a screenshot with WebdriverJS:
var webdriverjs = require('webdriverjs'),
client = webdriverjs.remote({
desiredCapabilities: {
browserName: 'chrome'
}
});
client
.init()
.url('http://google.com')
.saveScreenshot(__dirname + '/googleScreenshot.png')
.end();
You can also use WebdriverCSS to take screenshots. It is a plugin for WebdriverJS to do CSS regression tests. It is pretty much the same like PhantomCSS.

Categories