webdriverjs
Advanced tools
Comparing version 1.5.1 to 1.6.0
# CHANGELOG | ||
## v1.6.0 (2014-04-04) | ||
* allow parenthesized xpath expressions (thanks to @zauberpony) | ||
* enhanced README.md | ||
* implemented browser side eventhandling as "experimental" feature | ||
## v1.5.1 (2014-03-18) | ||
* re-add code removed by a refactor | ||
## v1.5.0 (2014-03-18) | ||
* downgrade chainit version because of performance leaks of queue v2.0 | ||
## v1.4.0 (2014-03-17) | ||
@@ -4,0 +15,0 @@ * implemented event handling in WebdriverJS - register events on 'init','command','end','error' or register own costum events |
@@ -34,7 +34,7 @@ var vows = require('vows'), | ||
'height is 30px': function(err,result) { | ||
'height is 32px': function(err,result) { | ||
assert(result.height === 32); | ||
}, | ||
'width is 94px': function(err,result) { | ||
'width is 89px': function(err,result) { | ||
assert(result.width === 89); | ||
@@ -91,2 +91,2 @@ } | ||
}).run(); // Run it | ||
}).run(); // Run it |
@@ -13,2 +13,3 @@ module.exports = function addValue (cssSelector, value, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -15,0 +16,0 @@ |
@@ -11,2 +11,3 @@ module.exports = function chooseFile(selector, localPath, cb) { | ||
client.uploadFile(localPath, function(err, res) { | ||
/* istanbul ignore next */ | ||
if (err) { | ||
@@ -13,0 +14,0 @@ return cb(err); |
@@ -13,2 +13,3 @@ module.exports = function clearElement (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,result); | ||
@@ -15,0 +16,0 @@ |
@@ -21,3 +21,6 @@ var clickHelper = require('../helpers/click'); | ||
} else { | ||
/* istanbul ignore next */ | ||
callback(err,result); | ||
} | ||
@@ -28,2 +31,3 @@ }); | ||
/* istanbul ignore next */ | ||
callback(err,result); | ||
@@ -30,0 +34,0 @@ |
@@ -29,2 +29,3 @@ module.exports = function close (newTabID, callback) { | ||
/* istanbul ignore next */ | ||
callback(err); | ||
@@ -31,0 +32,0 @@ |
@@ -14,2 +14,3 @@ module.exports = function doubleClick (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -16,0 +17,0 @@ |
@@ -44,2 +44,3 @@ module.exports = function swipe (selector, startX, startY, endX, endY, touchCount, duration, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -53,2 +54,3 @@ | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -69,2 +71,3 @@ | ||
/* istanbul ignore next */ | ||
callback(err, res); | ||
@@ -71,0 +74,0 @@ |
@@ -28,2 +28,3 @@ module.exports = function dragAndDrop (cssSelectorItem, cssSelectorDropDestination, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -37,2 +38,3 @@ | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -39,0 +41,0 @@ |
module.exports = function end (callback) { | ||
this.session("delete",callback); | ||
}; |
@@ -12,9 +12,9 @@ module.exports = function endAll (callback) { | ||
self.call(callback); | ||
} | ||
else { | ||
callback(err, result); | ||
} | ||
} else { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
} | ||
@@ -21,0 +21,0 @@ }); |
@@ -44,2 +44,3 @@ module.exports = function flick (selector, startX, startY, endX, endY, touchCount, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -53,2 +54,3 @@ | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -69,2 +71,3 @@ | ||
/* istanbul ignore next */ | ||
callback(err, res); | ||
@@ -71,0 +74,0 @@ |
@@ -15,2 +15,3 @@ module.exports = function getAttribute (cssSelector, attributeName, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -17,0 +18,0 @@ |
@@ -29,2 +29,3 @@ module.exports = function getCookie (name, callback) { | ||
if(typeof callback === 'function') { | ||
/* istanbul ignore next */ | ||
callback(err,result); | ||
@@ -31,0 +32,0 @@ } |
@@ -15,2 +15,3 @@ module.exports = function getCssProperty (cssSelector, cssProperty, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -17,0 +18,0 @@ |
@@ -15,2 +15,3 @@ module.exports = function getElementSize (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -17,0 +18,0 @@ |
@@ -22,2 +22,3 @@ module.exports = function getLocation (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -24,0 +25,0 @@ |
@@ -18,2 +18,3 @@ module.exports = function getLocationInView (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -20,0 +21,0 @@ |
@@ -11,2 +11,3 @@ module.exports = function getSource (callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -13,0 +14,0 @@ |
@@ -15,2 +15,3 @@ module.exports = function getTagName (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -17,0 +18,0 @@ |
@@ -15,2 +15,3 @@ module.exports = function getText (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -17,0 +18,0 @@ |
@@ -10,2 +10,3 @@ module.exports = function getTitle (callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -12,0 +13,0 @@ |
@@ -18,2 +18,3 @@ module.exports = function getValue (cssSelector, callback) { | ||
if(typeof callback === 'function') { | ||
/* istanbul ignore next */ | ||
callback(err, result.value); | ||
@@ -20,0 +21,0 @@ } |
@@ -17,2 +17,3 @@ module.exports = function hold (selector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -19,0 +20,0 @@ |
@@ -15,2 +15,3 @@ module.exports = function isSelected (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -17,0 +18,0 @@ |
@@ -15,2 +15,3 @@ module.exports = function isVisible (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -17,0 +18,0 @@ |
@@ -22,2 +22,3 @@ module.exports = function moveToObject (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -33,2 +34,3 @@ | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -35,0 +37,0 @@ |
@@ -17,2 +17,3 @@ module.exports = function release (selector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -19,0 +20,0 @@ |
@@ -13,2 +13,3 @@ module.exports = function saveScreenshot (fileName, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -15,0 +16,0 @@ |
@@ -41,2 +41,3 @@ module.exports = function scroll (selector, xoffset, yoffset, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -69,2 +70,3 @@ | ||
// scroll within native app - not supported yet | ||
/* istanbul ignore next */ | ||
return typeof callback === 'function' ? callback(new Error('Scrolling to specified x and y position isn\'t supported yet')) : false; | ||
@@ -71,0 +73,0 @@ |
@@ -24,2 +24,3 @@ module.exports = function setValue (cssSelector, value, callback) { | ||
} else { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -33,2 +34,3 @@ } | ||
if (typeof callback === 'function') { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -35,0 +37,0 @@ } |
@@ -13,2 +13,3 @@ module.exports = function submitForm (cssSelector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err, result); | ||
@@ -15,0 +16,0 @@ |
@@ -45,2 +45,3 @@ module.exports = function tap (selector, x, y, tapCount, touchCount, duration, callback) { | ||
if(typeof callback === 'function') { | ||
/* istanbul ignore next */ | ||
callback([errLocation,errSize]); | ||
@@ -63,2 +64,3 @@ } | ||
if(typeof callback === 'function') { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -65,0 +67,0 @@ } |
@@ -17,2 +17,3 @@ module.exports = function touch (selector, callback) { | ||
/* istanbul ignore next */ | ||
callback(err,res); | ||
@@ -19,0 +20,0 @@ |
@@ -24,2 +24,3 @@ module.exports = function uploadFile(localPath, cb) { | ||
.finalize(function(err) { | ||
/* istanbul ignore next */ | ||
if (err) { | ||
@@ -26,0 +27,0 @@ cb(err); |
@@ -16,2 +16,3 @@ /** | ||
/* istanbul ignore next */ | ||
module.exports = function(cssSelector) { | ||
@@ -18,0 +19,0 @@ return (function(cssSelector) { |
@@ -20,4 +20,4 @@ module.exports = function findStrategy(args) { | ||
// use xPath startegy if value startes with // | ||
} else if(value.indexOf('//') === 0) { | ||
// use xPath strategy if value starts with // | ||
} else if(value.indexOf('//') === 0 || value.indexOf('(//') === 0) { | ||
using = 'xpath'; | ||
@@ -24,0 +24,0 @@ |
@@ -34,2 +34,3 @@ // call must be scoped to the webdriverjs client | ||
/* istanbul ignore next */ | ||
callback(err,result); | ||
@@ -36,0 +37,0 @@ |
@@ -19,2 +19,44 @@ module.exports = function init (desiredCapabilities, callback) { | ||
/** | ||
* build chrome extension if experimental mode is enabled | ||
*/ | ||
if(this.options.experimental && this.desiredCapabilities.browserName === 'chrome') { | ||
var that = this, | ||
fs = require('fs'), | ||
join = require('path').join, | ||
ChromeExtension = require('crx'), | ||
crx = new ChromeExtension({ | ||
privateKey: fs.readFileSync(join(__dirname, '../../extension/key.pem')), | ||
rootDirectory: join(__dirname, '../../extension/chrome') | ||
}); | ||
crx.load(function(err) { | ||
if (err) return callback(err); | ||
this.pack(function(err, data){ | ||
if (err) return callback(err); | ||
/** | ||
* add extension | ||
*/ | ||
that.desiredCapabilities.chromeOptions = { | ||
extensions: [data.toString('base64')] | ||
} | ||
that.requestHandler.create( | ||
commandOptions, | ||
{desiredCapabilities: that.desiredCapabilities}, | ||
callback | ||
); | ||
/** | ||
* remove created build | ||
*/ | ||
this.destroy(); | ||
}); | ||
}); | ||
return; | ||
} | ||
this.requestHandler.create( | ||
@@ -21,0 +63,0 @@ commandOptions, |
@@ -56,2 +56,10 @@ module.exports = function session (doWhat, sessionId, callback) { | ||
/** | ||
* close socket connection if experimental mode is enabled | ||
*/ | ||
if(this.options.experimental && this.desiredCapabilities.browserName === 'chrome') { | ||
this.eventHandler.socket.disconnect('unauthorized'); | ||
this.eventHandler.app.close(); | ||
} | ||
} else { | ||
@@ -58,0 +66,0 @@ if (typeof callback === 'function') { |
@@ -15,4 +15,16 @@ 'use strict'; | ||
this.instance = instance; | ||
this.browserEvents = {}; | ||
this.supportedEvents = ['on','once','removeListener','removeAllListeners','emit']; | ||
/** | ||
* if experimental mode is enabled, start socket connection to communicate | ||
* with the browser to register browser side eventlisteners | ||
*/ | ||
if(this.instance.options.experimental) { | ||
this.startSocketServer(); | ||
this.supportedEvents.push('addEventListener'); | ||
this.supportedEvents.push('removeEventListener'); | ||
} | ||
/** | ||
* expose EventEmitter function to WebdriverJS instance | ||
@@ -22,3 +34,3 @@ * it's a bit hacky solution but the only way to pass functions within methods which | ||
*/ | ||
['on','once','removeListener','removeAllListeners','emit'].forEach(function(funcName) { | ||
this.supportedEvents.forEach(function(funcName) { | ||
@@ -67,6 +79,87 @@ if(typeof self[funcName] !== 'function') { | ||
}); | ||
} | ||
}; | ||
// inherit functionality from evenst.EventEmitter | ||
util.inherits(EventHandler, events.EventEmitter); | ||
/** | ||
* start socket connection | ||
*/ | ||
/* istanbul ignore next */ | ||
EventHandler.prototype.startSocketServer = function startSocketServer() { | ||
var that = this, | ||
socketio = require('socket.io'); | ||
this.app = require('http').createServer(); | ||
this.io = socketio.listen(this.app, { log: false }); | ||
this.app.listen(5555); | ||
this.io.sockets.on('connection', function (socket) { | ||
that.socket = socket; | ||
}); | ||
}; | ||
/* istanbul ignore next */ | ||
EventHandler.prototype.addEventListener = function(eventName,elem,callback,useCapture) { | ||
if(!this.socket) { | ||
// try again after 100ms | ||
return setTimeout(this.addEventListener.bind(this,eventName,elem,callback,useCapture), 100); | ||
} | ||
// store registered event to be able to remove listener | ||
if(!this.browserEvents[eventName + '-' + elem]) { | ||
this.browserEvents[eventName + '-' + elem] = []; | ||
// register event on client side | ||
this.socket.emit('addEventListener', { | ||
eventName: eventName, | ||
elem: elem, | ||
useCapture: useCapture || false | ||
}); | ||
} | ||
this.browserEvents[eventName + '-' + elem].push(callback.toString()); | ||
// register event on server side | ||
this.socket.on(eventName + '-' + elem,callback); | ||
}; | ||
/* istanbul ignore next */ | ||
EventHandler.prototype.removeEventListener = function(eventName,elem,callback,useCapture) { | ||
if(!this.socket) { | ||
// try again after 100ms | ||
return setTimeout(this.removeEventListener.bind(this,eventName,elem,callback,useCapture), 100); | ||
} else if(!this.browserEvents[eventName + '-' + elem] || !this.browserEvents[eventName + '-' + elem].length) { | ||
return this; | ||
} | ||
var that = this; | ||
// get stored event listener | ||
this.browserEvents[eventName + '-' + elem].forEach(function(listener, i) { | ||
if(listener === callback.toString()) { | ||
// remove listener in event list | ||
that.browserEvents[eventName + '-' + elem].splice(i,1); | ||
// remove listener on server side | ||
that.socket.removeListener(eventName + '-' + elem,callback); | ||
// break loop | ||
return false; | ||
} | ||
}); | ||
// remove event listener on client side if there is no listener anymore | ||
if(this.browserEvents[eventName + '-' + elem].length === 0) { | ||
this.socket.emit('removeEventListener', { | ||
eventName: eventName, | ||
elem: elem, | ||
useCapture: useCapture || false | ||
}); | ||
} | ||
}; | ||
module.exports = EventHandler; |
@@ -210,29 +210,2 @@ /** | ||
/** | ||
* logs command tree | ||
* @param {QueueItem} rootItem root item of tree | ||
*/ | ||
Logger.prototype.executionOrder = function(rootItem) { | ||
this.printChildren(rootItem,0); | ||
}; | ||
/** | ||
* logs current queue item and ist children | ||
* @param {QueueItem} item current queue item | ||
* @param {Number} depth count of nested element | ||
*/ | ||
Logger.prototype.printChildren = function(item,depth) { | ||
var pre = ''; | ||
for(var j = 0; j < depth; ++j) { | ||
pre += ' '; | ||
} | ||
pre += '|--'; | ||
console.log(pre,item.commandName); | ||
for(var i = 0; i < item.children.length; ++i) { | ||
this.printChildren(item.children[i],depth+1); | ||
} | ||
}; | ||
/** | ||
* helper method to check size ob object | ||
@@ -239,0 +212,0 @@ * @param {Object} obj object you like to check |
module.exports = makeError; | ||
function makeError(obj) { | ||
/* istanbul ignore next */ | ||
if (!obj) { | ||
@@ -5,0 +6,0 @@ return null |
@@ -58,2 +58,3 @@ 'use strict'; | ||
// check if we got a session id | ||
/* istanbul ignore next */ | ||
if(!this.sessionID) { | ||
@@ -72,3 +73,2 @@ this.instance.eventHandler.emit('error', { | ||
this.instance.eventHandler.emit('init', { | ||
@@ -75,0 +75,0 @@ sessionID: this.sessionID, |
@@ -22,3 +22,4 @@ var buildPrototype = require('./utils/buildPrototype.js'), | ||
host: '127.0.0.1', | ||
port: 4444 | ||
port: 4444, | ||
experimental: false | ||
}, options || {}); | ||
@@ -25,0 +26,0 @@ |
{ | ||
"name": "webdriverjs", | ||
"description": "A nodejs bindings implementation for selenium 2.0/webdriver", | ||
"version": "1.5.1", | ||
"version": "1.6.0", | ||
"homepage": "https://github.com/camme/webdriverjs", | ||
@@ -40,3 +40,2 @@ "author": "camilo tapia <camilo.tapia@gmail.com>", | ||
"glob": "~3.2.7", | ||
"bower": "~1.3.1", | ||
"nock": "~0.27.1", | ||
@@ -76,4 +75,6 @@ "coveralls": "~2.8.0", | ||
"request": "~2.34.0", | ||
"deepmerge": "~0.2.7" | ||
"deepmerge": "~0.2.7", | ||
"crx": "~0.4.1", | ||
"socket.io": "~0.9.16" | ||
} | ||
} |
@@ -120,3 +120,85 @@ Webdriver/selenium 2.0 javascript bindings for nodejs [![Build Status](https://travis-ci.org/camme/webdriverjs.png?branch=master)](https://travis-ci.org/camme/webdriverjs) [![Coverage Status](https://coveralls.io/repos/camme/webdriverjs/badge.png?branch=master&)](https://coveralls.io/r/camme/webdriverjs?branch=master) | ||
## Eventhandling | ||
WebdriverJS inherits several function from the NodeJS [EventEmitter](http://nodejs.org/api/events.html) object. | ||
Additionally it provides an experimental way to register events on browser side (like click, | ||
focus, keypress etc.). | ||
#### Eventhandling in NodeJS environment | ||
The following functions are supported: `on`,`once`,`emit`,`removeListener`,`removeAllListeners`. | ||
They behave exactly as described in the official NodeJS [docs](http://nodejs.org/api/events.html). | ||
There are some predefined events (`error`,`init`,`end`, `command`) which cover important | ||
WebdriverJS events. | ||
**Example:** | ||
```js | ||
client.on('error', function(e) { | ||
// will be executed everytime an error occured | ||
// e.g. when element couldn't be found | ||
console.log(e.body.value.class); // -> "org.openqa.selenium.NoSuchElementException" | ||
console.log(e.body.value.message); // -> "no such element ..." | ||
}) | ||
``` | ||
All commands are chainable, so you can use them while chaining your commands | ||
```js | ||
var cnt; | ||
client | ||
.init() | ||
.once('countme', function(e) { | ||
console.log(e.elements.length, 'elements were found'); | ||
}) | ||
.elements('.myElem', function(err,res) { | ||
cnt = res.value; | ||
}) | ||
.emit('countme', cnt) | ||
.end(); | ||
``` | ||
#### Eventhandling on browser side | ||
This is an experimental feature that helps you to listen on events within the browser. It | ||
is currently **only** supported in Chrome browser (other browser will eventually follow). | ||
To register an event call the `addEventListener` command. If an event gets invoked it returns | ||
almost the complete event object that got caught within the browser. Only the `Window` will | ||
be removed to avoid circular references. All objects from type `HTMLElement` will be | ||
replaced by their xPath. This will help you to query and identify this element with WebdriverJS. | ||
Before you are able to use browser side eventhandling you need set the `experimental` flag | ||
on client initialization: | ||
```js | ||
var client = WebdriverJS.remote({ | ||
logLevel: 'verbose', | ||
experimental: true, // <-- enables browser side eventhandling | ||
desiredCapabilities: { | ||
browserName: 'chrome' | ||
} | ||
}); | ||
``` | ||
After that you can use `addEventListener` to register events on one or multiple elements | ||
and `removeEventListener` to remove them. | ||
**Example** | ||
```js | ||
client | ||
.url('http://google.com') | ||
.addEventListener('dblclick','#hplogo', function(e) { | ||
console.log(e.target); // -> 'id("hplogo")' | ||
console.log(e.type); // -> 'dblclick' | ||
console.log(e.clientX, e.clientY); // -> 239 524 | ||
}) | ||
.doubleClick('#hplogo') // triggers event | ||
.end(); | ||
``` | ||
**Again:** this is still an experimental feature. Some events like `hover` will not be | ||
recorded by the browser. But `click` and custom events are working flawlessly. | ||
## Adding custom commands | ||
@@ -205,3 +287,3 @@ | ||
- **getAttribute(`String` selector, `String` attribute name, `Function` callback)**<br>Get an attribute from an dom obj based on the selector and attribute name | ||
- **getCookie(`String` name, `Function` callback)**<br>Gets the cookie for current page. | ||
- **getCookie(`String` name, `Function` callback)**<br>Get cookie for the current page. If no cookie name is specified the command will return all cookies. | ||
- **getCssProperty(`String` selector, `String` css property name, `Function` callback)**<br>Gets a css property from a dom object selected with a selector | ||
@@ -208,0 +290,0 @@ - **getCurrentTabId(`Function` callback)**<br>Retrieve the current window handle. |
@@ -108,2 +108,15 @@ describe('test different selector strategies', function () { | ||
it('should find an element using "xpath" method for ParenthesizedExpressions', function(done) { | ||
this.client | ||
.isVisible('(//div)[7]/span',function(err,isVisible) { | ||
assert.equal(null, err); | ||
assert.equal(isVisible,true); | ||
}) | ||
.getAttribute('(//div)[7]/span', 'data-foundBy', function(err,attr) { | ||
assert.equal(null, err); | ||
assert.equal(attr,'xpath'); | ||
}) | ||
.call(done); | ||
}); | ||
// check if it is still backwards compatible for obsolete command | ||
@@ -110,0 +123,0 @@ it('should still work with obsolete command',function(done) { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
929995
8
214
8538
401
7
22
1
+ Addedcrx@~0.4.1
+ Addedsocket.io@~0.9.16
+ Addedactive-x-obfuscator@0.0.1(transitive)
+ Addedarchiver@0.8.1(transitive)
+ Addedbase64id@0.1.0(transitive)
+ Addedbuffer-crc32@0.2.13(transitive)
+ Addedcommander@12.1.02.1.0(transitive)
+ Addedcrc32-stream@0.2.0(transitive)
+ Addedcrx@0.4.4(transitive)
+ Addeddebug@1.0.5(transitive)
+ Addeddeflate-crc32-stream@0.1.2(transitive)
+ Addedms@2.0.0(transitive)
+ Addednan@1.0.0(transitive)
+ Addedoptions@0.0.6(transitive)
+ Addedpolicyfile@0.0.4(transitive)
+ Addedredis@0.7.3(transitive)
+ Addedsocket.io@0.9.19(transitive)
+ Addedsocket.io-client@0.9.16(transitive)
+ Addedtinycolor@0.0.1(transitive)
+ Addeduglify-js@1.2.5(transitive)
+ Addedwrench@1.5.9(transitive)
+ Addedws@0.4.32(transitive)
+ Addedxmlhttprequest@1.4.2(transitive)
+ Addedzeparser@0.0.5(transitive)
+ Addedzip-stream@0.3.7(transitive)