commit 9bee8ed5128d5c9aa429b4df4d59e2ec883ba844 Author: John Bintz Date: Mon Jun 8 18:49:53 2015 -0400 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c577f7f --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Persistent Selenium in JavaScript + +I'm moving to a more JavaScript-heavy environment but still wanted to preserve +my [development mode integration testing setup](https://github.com/johnbintz/bintz-integration_testing_setup). +Since I have no Capybara, I made this. It wraps [selenium-standalone](https://github.com/vvo/selenium-standalone) +with an Express proxy that intercepts calls to create and destroy sessions, +and ensures there's only ever one session that is never destroyed. Works +great with [Testium](https://github.com/groupon/testium/) and allows me +to recreate my RSpec/Cucumber + Capybara setup purely in JavaScript! + +## Using + +`npm install -g persistent_selenium`, then `persistent_selenium`. Point +your Selenium client to `http://localhost:4443`. Test away! diff --git a/bin/persistent_selenium b/bin/persistent_selenium new file mode 100755 index 0000000..c387c31 --- /dev/null +++ b/bin/persistent_selenium @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../index.js'); diff --git a/index.js b/index.js new file mode 100644 index 0000000..2b9a83d --- /dev/null +++ b/index.js @@ -0,0 +1,81 @@ +var selenium = require('selenium-standalone'); +var proxy = require('express-http-proxy'); +var Request = require('request'); + +var app = require('express')(); +var currentSession = null; +var currentSessionObj = null; +var seleniumPort = 4444; + +var initBrowser = function(cb) { + Request({ + method: 'post', + url: 'http://localhost:' + seleniumPort + '/wd/hub/session/' + currentSession + '/url', + json: { url: "data:text/html;charset=utf-8;base64,PGh0bWw+PGhlYWQ+PHRpdGxlPm5vZGUtcGVyc2lzdGVudF9zZWxlbml1bTwvdGl0bGU+PGhlYWQ+PGJvZHk+PGgxPm5vZGUtcGVyc2lzdGVudF9zZWxlbml1bSBzdGFydGluZy4uLjwvaDE+PC9ib2R5PjwvaHRtbD4=" } + }, function(err, response, body) { + cb(); + }); +}; + +app.use(proxy('localhost', { + filter: function(req, res) { + if (currentSession) { + if (req.path === '/wd/hub/session/' + currentSession && + req.method.toLowerCase() === 'delete') { + req._wasDelete = true; + } + + if (req.path === '/wd/hub/session' && + req.method.toLowerCase() === 'post') { + req._wasCreate = true; + } + } + + return true; + }, + decorateRequest: function(req) { + req.port = seleniumPort; + + if (currentSession) { + if (req.path === '/wd/hub/session/' + currentSession && + req.method.toLowerCase() === 'delete') { + req.method = 'GET'; + req.path = '/wd/hub/sessions'; + } + + if (req.path === '/wd/hub/session' && + req.method.toLowerCase() === 'post') { + req.method = 'GET'; + req.path = '/wd/hub/sessions'; + } + } + + return req; + }, + intercept: function(origRes, data, req, res, callback) { + if (!currentSession && req.url === '/wd/hub/session' && + req.method.toLowerCase() === 'post') { + + currentSessionObj = JSON.parse(data.toString('utf-8')); + currentSession = currentSessionObj.sessionId; + initBrowser(function() { callback(null, data); }); + } else { + if (req._wasCreate) { + data = JSON.stringify(currentSessionObj); + initBrowser(function() { callback(null, data); }); + } else { + if (req._wasDelete) { + callback(null, JSON.stringify('{}')); + } else { + callback(null, data); + } + } + } + } +})); + +selenium.start({ spawnOptions: {}}, function() { + console.log("Persistent selenium listening on port 4443"); + app.listen(4443); +}); + diff --git a/package.json b/package.json new file mode 100644 index 0000000..01b51eb --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "persistent_selenium", + "version": "0.0.1", + "description": "Keep your Selenium browser windows open while running tests in development.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "John Bintz (http://johnbintz.com/)", + "license": "ISC", + "dependencies": { + "express": "^4.12.4", + "express-http-proxy": "^0.6.0", + "request": "^2.57.0", + "selenium-standalone": "^4.4.2" + }, + "homepage": "https://github.com/johnbintz/node-persistent_selenium", + "bin": { + "persistent_selenium": "./index.js" + }, + "repository": "johnbintz/node-persistent_selenium", + "preferGlobal": true +}