Handle alerts in selenium webdriver for nodejs - node.js

I am running a simple webserver in nodejs. On the server side i want to check if the user was successful in getting an alert box in the UI. Could be (confirm , prompt etc) . The payload is in the URL. To check this i create a URL and pass it to selenium to check if it creates an alert box. However, all my attempts to handle the alert are failing with an exception. Heres my code
/* global */
const webdriver = require('selenium-webdriver')
const chrome = require('selenium-webdriver/chrome')
var options = new chrome.Options();
options.addArguments('headless');
var path = require('chromedriver').path;
let driver = new webdriver.Builder().
withCapabilities({'browserName': 'chrome', 'alertBehavior': 'IGNORE'}).
setChromeOptions(options).
build();
/* do bunch of stuff */
function checkXSS(payload) {
console.log('checking payload')
var url = 'http://<url>?payload=' + payload
driver.get(url). //exception thrown here itself.
driver.switchTo().alert().then(function() {
driver.switchTo().alert().accept();},
function(){});
}
And i get the below exception
UnexpectedAlertOpenError: unexpected alert open: {Alert text : XSS}
I tried other ways too that were suggested on stackoverflow. Such as using driver.get.then(_, =>), alert.dismiss() etc however all of them still throw the same exception. What am i missing here?

Related

Why chromium doesn't open in headless Mode?

I have the following NodeJS code to open Chromium in headless mode and record a web page to a video :
const { launch, getStream } = require("puppeteer-stream");
const fs = require("fs");
const { exec } = require("child_process");
async function test() {
const browser = await launch({headless: true});
const page = await browser.newPage();
await page.goto("https://www.someurl.com");
const stream = await getStream(page, { audio: true, video: true});
// record the web page to mp4 video
const ffmpeg = exec('ffmpeg -y -i - output.mp4');
stream.pipe(ffmpeg.stdin);
setTimeout(async () => {
await stream.destroy();
stream.on("end", () => {});
}, 1000 * 60);
}
The following code works properly but doesn't open chromium in headless mode. No matter what I do, the browser is still opened and visible when browsing the page. No error is thrown.
Does anyone know why it's not opened in headless mode please ?
Thanks
It says in the documentation for puppeteer-stream:
Notice: This will only work in headful mode
This is due to a limitation of Chromium where the Tab Capture API for the extension doesn't work in headless mode. (There are a couple bug reports about this, but I can't find the links at the moment.)
I had the same issue that headless doesn't work with some Websites and Elements (showing blank page content, not finding an element etc.).
But there is another method to "simulate" the headless mode by minimizing and moving the window to a location that can not be seen by the user.
This doesn't hide the chrome task from the taskbar, but the Chrome tab itself will still be hidden for the User.
Just use the following arguments:
var chromeOptions = new ChromeOptions();
chromeOptions.AddArguments(new List<string>() { "--window-size=1,1", "window-position=-2000,0" }); // This hides the chrome window
var chromeDriverService = ChromeDriverService.CreateDefaultService();
chromeDriverService.HideCommandPromptWindow = true; // This is to hid the console.
ChromeDriver driver = new ChromeDriver(chromeDriverService, chromeOptions);
driver.Navigate().GoToUrl("https://google.com");
in short the important part:
chromeOptions.AddArguments(new List<string>() { "--window-size=1,1", "window-position=-2000,0" });
chromeDriverService.HideCommandPromptWindow = true;
//driver.Manage().Window.Minimize(); //use this if the code above does not work

How to download a CSV file with selenium while bypassing the file dialog

I have been trying to access a url with a CSV file to download it in a specific directory, using the Selenium Webdriver for Firefox(geckodriver), in a NodeJS enviroment on Linux-Mint.
This is my code:
const {Builder} = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');
const path = require('path');
const options = new firefox.Options();
options.setPreference('browser.download.dir', path.resolve(__dirname));
options.setPreference('browser.download.folderList', 2);
options.setPreference('browser.helperApps.neverAsk.saveToDisk', 'application/x-csv');
function example(){
let driver = new Builder().forBrowser('firefox').setFirefoxOptions(options).build();
driver.get('http://insight.dev.schoolwires.com/HelpAssets/C2Assets/C2Files/C2ImportCalEventSample.csv');
}
example();
As you can see, I am correctly setting the browser option to browser.helperApps.neverAsk.saveToDisk, so as to be able to bypass the dialog. However, I am still getting the dialog no matter what I do. I haven't tried this code on Windows, but for my purposes it needs to work on Linux.
Am I missing something? Some preference that needs to be added or changed? Or does this not work on my current enviroment?
Thank you in advance for any help provided.
If you are just downloading a file from link why do you need selenium?
A much simple approach will be just to get the file by http and save to file.
const http = require('http');
const fs = require('fs');
const file = fs.createWriteStream("C2ImportCalEventSample.csv");
const request = http.get("http://insight.dev.schoolwires.com/HelpAssets/C2Assets/C2Files/C2ImportCalEventSample.csv", function(response) {
response.pipe(file);
});
If you have to use selenium let me know in the comments and i will try to find a solution for your problem using selenium.

Websocket closes on client message [JavaScript/Node.js]

I'm creating a simple Node.js WebSocket server, but I am running into a problem after the initial handshake.
In the beginning, I was only using chrome and the command line to monitor back and forth between a HTML5 Websocket and the Node.js server. It took a bit to implement the protocol, but I had just finished a very basic version of the server-side message decoding. I was having a hard time, however, because whenever I would call ws.send('some kind of message'), the websocket would close on the client side. Looking into the network tab of the DevTools, it looks like the message would send from the client, and get an immediate error response of (Opcode -1), and would log this error in the console:
WebSocket connection to 'ws://localhost:4000/' failed: A server must not mask any frames that it sends to the client.
I've looked into what it all means, and I can't figure out why my code would throw it. I had tried rebuilding it, and also making a test message send after the confirmation, which worked. The only thing I had not tried was using a different browser, so I tried it today. And it worked as expected.
Below is all my relevant code.
Libraries, constants, and listens:
const hostname = 'localhost';
const webport = 8080;
const socketport = 4000;
const http = require('http');
const net = require('net');
const mysql = require('mysql');
const rlm = require('readline');
const crypt = require('crypto');
...
server.listen(webport,hostname);
socketServer.listen(socketport,hostname);
HTTP Server:
const server = http.createServer(
function(req,res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write("
<html>
<head>
<title>Test Title</title>
</head>
<body>
<h1>Here's the thing</h1>
<p>im baby</p>
</body>
<script>
const ws = new WebSocket('ws://"+hostname+":"+socketport+"');
ws.addEventListener('message',function(data){
console.log(data.data)
});
</script>
</html>
"); // Reformatted for better reading
res.end();
});
Net Server:
var sockets = new Map();
var socketInfo = {};
const socketDelimiters = {
'Accept-Encoding':',',
'Accept-Language':';',
'Sec-WebSocket-Extensions':'; '
}
const socketServer = net.Server(function(s) {
s.on('data',function(e) {
/*
* If the socket is not registered, read first message as
* the beginning to a handshake
*/
if(sockets.get(s)==null) {
var str = ""+e;
var tempobj = str.split("\r\n");
var newObj = {};
for(var i in tempobj) {
if(tempobj[i].length>0) {
var tempProperty = tempobj[i].split(': ');
if(tempProperty.length>1) {
if(socketDelimiters[tempProperty[0]]!=null){
tempProperty[1] = tempProperty[1].split(
socketDelimiters[tempProperty[0]]);
}
newObj[tempProperty[0]] = tempProperty[1];
} else {
newObj.header = tempProperty;
}
}
}
var protocolReturn = "
HTTP/1.1 101 Switching Protocols\r\n
Upgrade: websocket\r\n
Connection: Upgrade\r\n
Sec-Websocket-Accept: "+createAcceptKey(newObj['Sec-WebSocket-Key'])
+"\r\n\r\n"; //Reformatted for better reading
s.write(protocolReturn);
s.pipe(s);
sockets.set(s,newObj['Sec-WebSocket-Key']);
socketInfo[newObj['Sec-WebSocket-Key']] = {
socket:s,
isReading:false,
message:null,
mask:null,
handshake: newObj
};
s.write(Buffer.from([0x81,0x04,0x74,0x65,0x73,0x74])); // 'test'
s.pipe(s);
} else {
/*
* If the socket is found and registered, decode the incoming message
*/
var firstBytes = e.readUInt16BE(0);
console.log(firstBytes);
var length=((firstBytes & 0x007F)/0x0001);
var FIN = ((firstBytes & 0x8000))!=0;
var opcode = (firstBytes & 0x0F00)/0x0100;
var mask = ((firstBytes & 0x0080)!=0);
if(opcode!=8) {
console.log("end: "+FIN);
console.log("mask: "+mask);
console.log("op code: "+opcode);
console.log("length: "+length);
var mask = [];
for(var i=0; i<4; i++) {
var b = e.readUInt8(2+i);
mask.push(b);
}
var val=[];
for(var i=0; i<length; i++) {
var b = e.readUInt8(6+i) ^ mask[i%4];
val.push(b);
}
var newVal = new Buffer.from(val);
console.log(newVal.toString('utf8'));
}
}
})
// Handles error
s.on('error',function(err) {
console.log(err);
})
// Takes socket out of the socket list on close
s.on('close',function(hasError) {
if(hasError) {console.log("Please see error")}
delete socketInfo[sockets.get(s)];
sockets.delete(s);
});
});
// Generates accept key from given key
function createAcceptKey(key) {
var inKeyHash = crypt.createHash('sha1');
inKeyHash.update(key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
return (inKeyHash.digest('base64'));
}
What all this should do ('<' means server to client, '>' means client to server)
> [handshake initiation]
< [handshake confirmation]
< test
> [anything the client sends through the console]
/*
*All I do for the client to server bit at the end is go into the console,
* and plug in something like this
*/
ws.send('blah blah blah')
This works perfectly fine in Firefox, but as explained above, in chrome, it throws an error, claiming that the server had sent a masked frame at the same instant the client sends a message to the server.
Is there a reason that chrome reads a masked frame and firefox does not?
UPDATE:
I have now tried to use this in a different browser (the OBS browser to be exact) and it throws the same error on the server's side that connecting with Chrome does (I've added an event listener to send a message on socket open on the client side). Would anyone know why it only works in Firefox?
Solved this two days ago, didn't realize I could post my own answer (still new to posting here, sorry!)
A lot of my understanding of Node.js sockets came from the net documentation. In this, there is an example of a server and client interaction. The pipe() command is used after writing on the server side, so I assumed that it was necessary in writing to a socket client.
It is not required, and in fact should not be used. The example is an echo server, so every message the client sends to the server will be relayed back to the client. This post is the one that helped me with this, but I am a bit mad, because I tried following that advice before, and it stopped working when I removed the pipe commands. If the definition of insanity is "Trying something again and expecting different results," then throw me in the loony bin.
TL,DR;
Writing to the socket was easier than I thought:
// Expected:
socket.write('blah blah blah');
socket.pipe(socket);
// Reality
socket.write('blah blah blah');

Navigating to another URL during webdriver task

I am trying to log into a website as an admin and then navigate to another page (a portal) which requires this admin login beforehand to display data. I don't think I can access the cookies because of an issue accessing https cookies issue I read up on earlier (correct me if I'm wrong).
So my current solution is to enter the url as soon as the login process is complete and then continue with other tasks. Could you please advise on the methods/functions I can use to do this? If there are better ways to do this, I'd also be happy to hear about those!
var webdriver = require("selenium-webdriver");
var By = require("selenium-webdriver").By;
var until = require("selenium-webdriver").until;
var assert = require("chai").assert;
var filename = "img";
var fs = require('fs');
var err = "error caught!";
var testName = "get_login_cookies";
var driver = new webdriver.Builder()
.forBrowser('chrome')
.build();
describe('email register', function () {
this.timeout(25000);
before(function(done) {
driver.navigate().to('https://www.perlego.com/#');
driver.manage().deleteAllCookies;
driver.manage().window().maximize()
.then(() => done())
});
it('logs in with admin user and gets cookies', (done) => {
driver.findElement(By.name('email')).sendKeys("user#example.com");
driver.findElement(By.css('#password')).sendKeys("examplePassword");
driver.findElement(By.css('.login-button')).click();
// some code here to navigate to other page via url
// runs remainder of tests
});
after(function(done) {
driver.quit()
.then(() => done())
});
});
So I found that it was as simple as running the driver.navigate() method where I wanted to go to a new page:
driver.navigate().to('https://www.somesite.com/#');
Because of the cookie settings on the site, I was unable to access them with the webdriver, so I had to enter the password each time.
I was tripped up by waiting for ajax calls on the page when trying to select elements, this method helped:
driver.manage().timeouts().implicitlyWait(3000);
Hope this helps someone out there!

Chrome Extension with webSocket

I want to create extension that use Pusher service(http://pusher.com/) to send messages to the client, and I am getting the following error message:
Port error: Could not establish connection. Receiving end does not exist.
When I try the same code on simple html page it works.
Pusher.log = function(message) {
if (window.console && window.console.log) window.console.log(message);
};
// Flash fallback logging - don't include this in production
WEB_SOCKET_DEBUG = true;
var pusher = new Pusher('key');
var channel = pusher.subscribe('channel');
channel.bind('event', function(data) {
alert("test");
});
Do I need to change anything in order to make it run?
thx.

Resources