Skip to content

Instantly share code, notes, and snippets.

@formula1
Last active March 3, 2017 03:25
Show Gist options
  • Save formula1/53835c24330c0d77a9a1e73d233b4253 to your computer and use it in GitHub Desktop.
Save formula1/53835c24330c0d77a9a1e73d233b4253 to your computer and use it in GitHub Desktop.
selenium testing

Current Usage

To use

var reqrelSelenium = require("selenium-browser-runner/require-release.js");
var webdriver = require('selenium-webdriver');
var fileserverurl = "http://fileserver:80";
reqrel.require().then(function(){
  console.log("started");
  var driver = new webdriver.Builder()
    .forBrowser('chrome')
    .usingServer('http://localhost:4444/wd/hub')
    .build();
  return driver.get(fileserverurl).then(function(){
    console.log("loaded page");
    return runTests(driver, fileserverurl);
  }).then(function(){
    console.log("finshed tests");
    return reqrel.release();
  }, function(){
    console.log("errored tests");
    return reqrel.release();
  }).then(function(){
    console.log("finished release");
  });
});

Expectations

This expects that your tests will run on static html directories

Enhancements

  • Can utilize docker-compose network
    • require/release individual servers
    • specy how to start them, where the root is located and the expected name
  • Provide Example Tests
version: "3"
services:
fileserver:
image: kyma/docker-nginx
command: nginx
volumes:
- "./:/var/www"
ports:
- "8080:80"
hub:
image: selenium/hub
ports:
- "4444:4444"
depends_on:
- fileserver
firefox:
image: selenium/node-firefox
environment:
- HUB_PORT_4444_TCP_ADDR=hub
- HUB_PORT_4444_TCP_PORT=4444
depends_on:
- hub
chrome:
image: selenium/node-chrome
environment:
- HUB_PORT_4444_TCP_ADDR=hub
- HUB_PORT_4444_TCP_PORT=4444
depends_on:
- fileserver
- hub
{
"name": "selenium-browser-runner",
"version": "1.0.0",
"description": "Selenium Browser Runner",
"main": "require-release.js",
"author": "",
"license": "ISC",
"dependencies": {
"split": "^1.0.0",
"selenium-webdriver": "^3.1.0"
}
}
var child_process = require("child_process");
var path = require("path");
var split = require("split");
var REQUIRED_MESSAGES = [
/hub.*Selenium Grid hub is up and running$/,
/chrome.*The node is registered to the hub and ready to use$/,
/firefox.*The node is registered to the hub and ready to use$/
];
var __root = path.resolve(__dirname, "../..");
var stillRequiring = 0;
module.exports.require = function(){
return create(createBrowserContext).then(function(){
stillRequiring++;
})
};
module.exports.release = function(id){
if(stillRequiring === 0){
Promise.reject(new Error("relaeseing when no longer required"))
}
stillRequiring--;
if(stillRequiring.length > 0){
return Promise.resolve();
}
return destroy(destroyBrowserContext);
};
function createBrowserContext(){
return new Promise(function(res, rej){
var child = child_process.spawn(
"docker-compose",
["-f", path.join(__dirname, "docker-compose.yml"), "up", "--force-recreate"],
{ stdio: ["ignore", "pipe", "pipe"] }
);
var to;
var missing = REQUIRED_MESSAGES.slice(0);
var outsplitter = split();
var errsplitter = split();
child.stderr.pipe(errsplitter).on("data", function(buffer){
// var message = buffer.toString("utf-8");
// console.error("ERROR", message);
})
child.stdout.pipe(outsplitter).on("data", function(buffer){
var message = buffer.toString("utf-8");
// console.log(message);
for(var i = 0, l = missing.length; i < l; i++){
if(missing[i].test(message)){
break;
}
}
if(i < l){
missing.splice(i, 1);
if(missing.length === 0){
clearTimeout(to);
child.stdout.unpipe(outsplitter);
child.stdout.pipe(split()).on("data", function(buffer){
// var message = buffer.toString("utf-8");
// console.error(message);
});
res(child);
}
}
});
to = setTimeout(function(){
child.stdout.unpipe();
rej(new Error("timed out"));
}, 30*1000);
});
}
function destroyBrowserContext(context){
var child = context;
var timeoutlimit = 30 * 1000;
return new Promise(function(res, rej){
try{
child.on("exit", function(){
res();
})
setTimeout(function(){
rej("kill timed out");
}, timeoutlimit);
child.kill();
child.kill();
}catch(e){
rej(e);
}
});
}
var currentContext = false;
var isCreating = false;
var currentlyDestroying = false;
var destroyListeners = [];
var createListeners = [];
function create(fn){
return new Promise(function(res, rej){
if(!currentlyDestroying) return res();
destroyListeners.push([res, rej]);
}).then(function(){
return new Promise(function(res, rej){
if(currentContext !== false){
return res();
}
createListeners.push([res, rej]);
if(isCreating){
return;
}
isCreating = true;
fn().then(function(results){
currentContext = results;
isCreating = false;
var listeners = createListeners;
createListeners = []
listeners.forEach(function(resrej){
resrej[0]();
})
}, function(err){
isCreating = false;
var listeners = createListeners;
createListeners = []
listeners.forEach(function(resrej){
resrej[1](err);
})
})
})
})
}
function destroy(fn, timeoutlimit){
if(currentContext === false){
return Promise.resolve();
}
currentlyDestroying = true;
timeoutlimit = timeoutlimit || 1500;
return Promise.resolve(currentContext).then(fn).then(function(){
currentlyDestroying = false;
currentContext = false;
var listeners = destroyListeners
destroyListeners = [];
listeners.forEach(function(resrej){
resrej[0]();
})
}, function(err){
console.log("errored listeners", err);
currentlyDestroying = false;
var listeners = destroyListeners
destroyListeners = [];
listeners.forEach(function(resrej){
resrej[1](err);
})
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment