Is there a way to globally and automatically modify a message before emitting it? Something along the lines of jQuery ajax's beforeSend.
Right now, I'm manually adding a timestamp to the payload for each emit and it would be much less error-prone to have that done automatically.
Thanks!
You can either override the .emit() method (saving the original so you can call it) or if you control all the code that calls .emit(), then just make your own method that adds the timestamp to the payload and then calls .emit().
To patch the original .emit(), you could do this:
(function() {
var origEmit = Socket.prototype.emit;
Socket.prototype.emit = function(msg, data) {
if (typeof data === "object") {
data.timeStamp = Date.now();
}
return origEmit.apply(this, arguments);
}
})();
To create your own emit method that all your code could use, you could do this:
Socket.prototype.emitT = function(msg, data) {
if (typeof data === "object") {
data.timeStamp = Date.now();
}
return this.emit.apply(this, arguments);
}
Related
The site http://project-gc.com/Statistics/TopFavWilson views data depending on a set filter via ajax.
I can see this data as bargraphs.(I'm logged in and authenticated)
But I would like to save this data for import into e.g. a spreadsheet program.
I need the Fav%Wilson points (also in the ajaxresponde), I can't get them in a different way.
I thought about using a greasemonkey script to fetch the responddata from the after the ajaxcall.
Maybe with "waitForKeyElements"?
Can anybody suggest a sollution or give me a hint how to solve the problem?
If you only want to monitor the responses without any interaction, you can replace the XHR constructor with a wrapper function and add an event listener to each newly created instance.
// ==UserScript==
// #name ajaxobserver
// #namespace http://example.com
// #description observes ajax responses
// #include http://project-gc.com/Statistics/TopFavWilson
// #include http://project-gc.com/Statistics/TopFavWilson/*
// #version 1
// #grant none
// #run-at document-start
// ==/UserScript==
// scope encapsulation in newer GM versions not necessary, nevertheless...
(function()
{
// save constructor
let XMLHttpRequest = window.XMLHttpRequest;
// replace constructor function
window.XMLHttpRequest = function()
{
// new instance
let obj = new XMLHttpRequest();
// register a listener
obj.addEventListener('load', function (event)
{
console.log('EVENT LISTENER: ajax load: responseText =', event.target.responseText);
});
//return the created instance instead of `this`
return obj;
};
})();
If you also want to manipulate results, you will need a proxy or you have rebuild the entire XHR Object by hand as a wrapper. This is a proxy example:
// ==UserScript==
// #name ajaxmanipulator
// #namespace http://example.com
// #description observes & manipulate ajax responses
// #include http://project-gc.com/Statistics/TopFavWilson
// #include http://project-gc.com/Statistics/TopFavWilson/*
// #version 1
// #grant none
// #run-at document-start
// ==/UserScript==
(function()
{
let
// a function call handler for onevent functions
applyEventHandler =
{
apply: function(targetFunc, thisArg, [event])
{
if
(
'readystatechange' === event.type && 4 === event.target.readyState && 200 === event.target.status
||
'load' === event.type
)
console.log('EVENT', event.type + ':', event.target.responseText);
return targetFunc.call(thisArg, event);
}
},
// a function call handler for onevent functions
applyOpenHandler =
{ // destructuring arguments array into individual named arguments
apply: function(targetFunc, thisArg, [method, url, async, user, password])
{
console.log('open handler:', 'target =', targetFunc, ', thisArg =', thisArg );
console.log
( 'XMLHttpRequest.open\n',
'method:' , method,
'url:' , url,
'async:' , async,
'user:' , user,
'password:', password
);
// let's manipulate some argument
url += '?get-parameter-added-by-proxy';
// finally call the trapped function in context of thisArg passing our manipulated arguments
return targetFunc.call(thisArg, method, url, async, user, password);
}
},
// a property handler for XMLHttpRequest instances
xmlHttpReq_PropertiesHandler =
{
// target : the proxied object (native XMLHttpRequest instance)
// property: name of the property
// value : the new value to assign to the property (only in setter trap)
// receiver: the Proxy instance
get:
function (target, property /*, receiver*/)
{
console.log('%cget handler: ', 'color:green', property);
switch (property)
{
case 'responseText':
// let's return a manipulated string when the property `responseText` is read
return '<div style="color:red;border:1px solid red">response manipulated by proxy'
+ target.responseText + '</div>';
case 'open':
// All we can detect here is a get access to the *property*, which
// usually returns a function object. The apply trap does not work at this
// point. Only a *proxied function* can be trapped by the apply trap.
// Thus we return a proxy of the open function using the apply trap.
// (A simple wrapper function would do the trick as well, but could be easier
// detected by the site's script.)
// We use bind to set the this-context to the native `XMLHttpRequest` instance.
// It will be passed as `thisArg` to the trap handler.
return new Proxy(target.open, applyOpenHandler).bind(target);
default:
return 'function' === typeof target[property]
// function returned by proxy must be executed in slave context (target)
? target[property].bind(target)
// non-function properties are just returned
: target[property]
;
}
},
set:
function (target, property, value, receiver)
{
try
{
console.log('%cset handler: ', 'color:orange', property, '=', value);
switch (property)
{
// Event handlers assigned to the proxy must be stored into the proxied object (slave),
// so that its prototype can access them (in slave context). Such an access is not trapped by
// the proxy's get trap. We need to store proxied functions to get ready to observe invokations.
// Old ajax style was checking the readystate,
// newer scripts use the onload event handler. Both can still be found.
case 'onreadystatechange':
case 'onload':
// only create proxy if `value` is a function
target[property] = 'function' === typeof value
? new Proxy(value, applyEventHandler).bind(receiver)
: value
;
break;
default:
target[property] = value;
}
return true; // success
}
catch (e)
{
console.error(e);
return false; // indicate setter error
}
}
},
oldXMLHttpRequest = window.XMLHttpRequest
; // end of local variable declaration
window.XMLHttpRequest = function(...argv)
{
return new Proxy(new oldXMLHttpRequest(...argv), xmlHttpReq_PropertiesHandler);
}
})();
Be aware that this direct acces only works as long as you do not grant any privileged GM_functions. When you get enclosed into sandbox, you will have to inject the function as sting into the site's scope, e.g. via setTimeout.
When spying on a method, we can either callThrough (use original implementation) or callFake (use a custom implementation).
What I want is a behaviour similar to callThrough but inspect/modify its return value before returning it to the caller.
So I can do something like this:
spyOn(foo, "fetch").and.afterCall(function(result) {
expect(result).toBeDefined();
result.bar = "baz";
return result;
});
Right now the simplest way is doing something like this:
var original = foo.fetch;
foo.fetch = function() {
var result = original.apply(this, arguments);
expect(result).toBeDefined();
result.bar = "baz";
return result;
}
Which is somewhat annoying because now I have to manually restore the spy instead of having the framework automatically does it for me.
Does Jasmine have an after-advice spy?
Generally: no.
You could extend the SpyStrategy object with such a function though:
this.callThroughAndModify = function(resultModifier) {
var result;
plan = function() {
result = originalFn.apply(this, arguments);
return resultModifier(result);
};
return getSpy();
};
You've to clone the above SpyStrategy file and insert that method.
Usage:
var obj = {
fn: function(a) { return a * 2; }
};
spyOn(obj, "fn").and.callThroughAndModify(function(result) {
console.log("Original result: ", result);
return 1;
});
expect(obj.fn(2)).toBe(1);
Drawbacks:
You've to replace the whole SpyStrategy.js
You've to load that script before Jasmine initializes the original SpyStrategy at boot
I am using Selenium WebDriver for crawling a web site(only for example, I will be crawling other web sites too!) which has infinite scroll.
Problem statement:
Scroll down the infinite scroll page till the content stops loading using Selenium web driver.
My Approach:
Currently I am doing this-
Step 1: Scroll to the page bottom
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("javascript:window.onload=toBottom();"+
"function toBottom(){" +
"window.scrollTo(0,Math.max(document.documentElement.scrollHeight," +
"document.body.scrollHeight,document.documentElement.clientHeight));" +
"}");
Then I wait for some time to let the Ajax Request complete like this-
Step 2: Explicitly wait for Ajax request to be over
Thread.sleep(1000);
Then I give another java script to check if the page is scrollable
Step 3:Check if the page is scrollable
//Alternative to document.height is to be used which is document.body.clientHeight
//refer to https://developer.mozilla.org/en-US/docs/DOM/document.height
if((Long)js.executeScript("return " +
"(document.body.clientHeight-(window.pageYOffset + window.innerHeight))")>0)
If the above condition is true then I repeat the from Step 1 - 3, till condition in Step 3 is false.
The Problem:
I do not want to give the Thread.sleep(1000); in step 2, rather I would like to check using Java Script if the background Ajax request is over and then scroll down further if the condition in Step 3 is true .
PS: I am not the developer of the page so I do not have access to the code running the page, I can just inject java scripts(as in Step 1 and 3) in the web page. And, I have to write a generic logic for any web site with Ajax requests during infinite scroll.
I will be grateful to some one could spare some time here!
EDIT : Ok, after struggling for 2 days, I have figured out that the pages which I am crawling through the Selenium WebDriver can have any of these JavaScript libraries and I will have to pool according to the different Library, for example, In case of the web application using jQuery api, I may be waiting for
(Long)((JavascriptExecutor)driver).executeScript("return jQuery.active")
to return a zero.
Likewise if the web application is using the Prototype JavaScript library I will have to wait for
(Long)((JavascriptExecutor)driver).executeScript("return Ajax.activeRequestCount")
to return a zero.
Now, the problem is how do I write a generic code which could handle most the JavaScript libraries available?
Problem I am facing in implementing this-
1. How do I find which JavaScript Library is being used in the Web Application(using Selenium WebDriver in Java), such that I can then write the corresponding wait methods?
Currently, I am using this
Code
2. This way I will have to write as many as 77 methods for separate JavaScript library so, I need a better way to handle this scenario as well.
In short, I need to figure out if the browser is making any call(Ajax or simple) with or without any JavaScript library through Selenium Web Driver's java implementation
PS: there are Add ons for Chorme's JavaScript Lib detector and Firefox's JavaScript Library detector which detect the JavaScript library being used.
For web pages with Ajax Response during the infinite scroll and using jQuery API(or other actions), before starting to opening the web page.
//Inject the pooling status variable
js.executeScript("window.status = 'fail';");
//Attach the Ajax call back method
js.executeScript( "$(document).ajaxComplete(function() {" +
"status = 'success';});");
Step 1: will remain the same as in the original question
Step 2 Pooling the following script(This is the one which removes the need of Thread.Sleep() and makes the logic more dynamic)
String aStatus = (String)js.executeScript("return status;");
if(aStatus!=null && aStatus.equalsIgnoreCase("success")){
js.executeScript("status = 'fail';");
break poolingLoop;
}
Step 3: No need now!
Conclusion: No need to give blunt Thread.sleep(); again and again while using Selenium WebDriver!!
This approach works good only if there's jQuery api being used in the web application.
EDIT:
As per the the link given by #jayati i injected the javascript-
Javascript one:
//XMLHttpRequest instrumentation/wrapping
var startTracing = function (onnew) {
var OldXHR = window.XMLHttpRequest;
// create a wrapper object that has the same interfaces as a regular XMLHttpRequest object
// see http://www.xulplanet.com/references/objref/XMLHttpRequest.html for reference on XHR object
var NewXHR = function() {
var self = this;
var actualXHR = new OldXHR();
// private callbacks (for UI):
// onopen, onsend, onsetrequestheader, onupdate, ...
this.requestHeaders = "";
this.requestBody = "";
// emulate methods from regular XMLHttpRequest object
this.open = function(a, b, c, d, e) {
self.openMethod = a.toUpperCase();
self.openURL = b;
ajaxRequestStarted = 'open';
if (self.onopen != null && typeof(self.onopen) == "function") {
self.onopen(a,b,c,d,e); }
return actualXHR.open(a,b,c,d,e);
}
this.send = function(a) {
ajaxRequestStarted = 'send';
if (self.onsend != null && typeof(this.onsend) == "function") {
self.onsend(a); }
self.requestBody += a;
return actualXHR.send(a);
}
this.setRequestHeader = function(a, b) {
if (self.onsetrequestheader != null && typeof(self.onsetrequestheader) == "function") { self.onsetrequestheader(a, b); }
self.requestHeaders += a + ":" + b + "\r\n";
return actualXHR.setRequestHeader(a, b);
}
this.getRequestHeader = function() {
return actualXHR.getRequestHeader();
}
this.getResponseHeader = function(a) { return actualXHR.getResponseHeader(a); }
this.getAllResponseHeaders = function() { return actualXHR.getAllResponseHeaders(); }
this.abort = function() { return actualXHR.abort(); }
this.addEventListener = function(a, b, c) { return actualXHR.addEventListener(a, b, c); }
this.dispatchEvent = function(e) { return actualXHR.dispatchEvent(e); }
this.openRequest = function(a, b, c, d, e) { return actualXHR.openRequest(a, b, c, d, e); }
this.overrideMimeType = function(e) { return actualXHR.overrideMimeType(e); }
this.removeEventListener = function(a, b, c) { return actualXHR.removeEventListener(a, b, c); }
// copy the values from actualXHR back onto self
function copyState() {
// copy properties back from the actual XHR to the wrapper
try {
self.readyState = actualXHR.readyState;
} catch (e) {}
try {
self.status = actualXHR.status;
} catch (e) {}
try {
self.responseText = actualXHR.responseText;
} catch (e) {}
try {
self.statusText = actualXHR.statusText;
} catch (e) {}
try {
self.responseXML = actualXHR.responseXML;
} catch (e) {}
}
// emulate callbacks from regular XMLHttpRequest object
actualXHR.onreadystatechange = function() {
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
// onreadystatechange callback
if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") { return self.onreadystatechange(); }
}
actualXHR.onerror = function(e) {
ajaxRequestComplete = 'err';
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onerror != null && typeof(self.onerror) == "function") {
return self.onerror(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
actualXHR.onload = function(e) {
ajaxRequestComplete = 'loaded';
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onload != null && typeof(self.onload) == "function") {
return self.onload(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
actualXHR.onprogress = function(e) {
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onprogress != null && typeof(self.onprogress) == "function") {
return self.onprogress(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
if (onnew && typeof(onnew) == "function") { onnew(this); }
}
window.XMLHttpRequest = NewXHR;
}
window.ajaxRequestComplete = 'no';//Make as a global javascript variable
window.ajaxRequestStarted = 'no';
startTracing();
Or Javascript Two:
var startTracing = function (onnew) {
window.ajaxRequestComplete = 'no';//Make as a global javascript variable
window.ajaxRequestStarted = 'no';
XMLHttpRequest.prototype.uniqueID = function() {
if (!this.uniqueIDMemo) {
this.uniqueIDMemo = Math.floor(Math.random() * 1000);
}
return this.uniqueIDMemo;
}
XMLHttpRequest.prototype.oldOpen = XMLHttpRequest.prototype.open;
var newOpen = function(method, url, async, user, password) {
ajaxRequestStarted = 'open';
/*alert(ajaxRequestStarted);*/
this.oldOpen(method, url, async, user, password);
}
XMLHttpRequest.prototype.open = newOpen;
XMLHttpRequest.prototype.oldSend = XMLHttpRequest.prototype.send;
var newSend = function(a) {
var xhr = this;
var onload = function() {
ajaxRequestComplete = 'loaded';
/*alert(ajaxRequestComplete);*/
};
var onerror = function( ) {
ajaxRequestComplete = 'Err';
/*alert(ajaxRequestComplete);*/
};
xhr.addEventListener("load", onload, false);
xhr.addEventListener("error", onerror, false);
xhr.oldSend(a);
}
XMLHttpRequest.prototype.send = newSend;
}
startTracing();
And checking the status of the status vars ajaxRequestStarted, ajaxRequestComplete in the java code, one can determine if the ajax was started or completed.
Now I have a way to wait till an Ajax is complete, I can also find if the Ajax was triggered on some action
Approach 1:
Your approach is good, just a few changes would do the trick:
Step 1: Improve this step to call the toBottom function at regular interval using window.setInterval. At (c >= totalcount) call window.clearInterval
Setp 2: Instead of checking the page is yet scrollable, check if (c >= totalcount). And this condition every 200ms until (c >= totalcount) returns true.
FYI: If the Step 1 doesn't work in all the browsers then probably, you can refer to line 5210 of Tata-Nano-Reviews-925076578.js and call this with cvariable checking.
Approach 2:
Go to jQuery API and type "ajax". You can find some callback handlers which could be used for ajax requests.
Probably, set a variable before the request is been sent and after it is been received appropriately.
And in between use your original method of scrolling to bottom at regular interval, unless you can no more scroll. At this point clear the interval variable.
Now, regularly check if that interval variable is null or not. Null would mean that you have reached the bottom.
We had to solve the same problem, and managed using a long Javascript function. Just need to add checks to see which library is not undefined.
PS Thanks for giving me an easy answer for how to check for in progress Prototype requests!
eg. Handle JQuery and XHR/Prototype
var jsExecutor = /*Get your WebDriverInstance*/ as IJavaScriptExecutor;
while(/*your required timeout here*/)
{
var ajaxComplete =
jsExecutor.ExecuteScript("return ((typeof Ajax === 'undefined') ||
Ajax.activeRequestCount == 0) && ((typeof jQuery === 'undefined') || $.active == 0)");
if (ajaxIsComplete)
return
}
I am using an observer on "http-on-modify-request" to analyze HTTP requests (and responses with the corresponding other observers).
Is it possible to determine whether the HTTP request / response is the main frame loading (the actual page DOM)? As opposed to another resource (image, css, sub_frame, etc.).
The docs have most of the answer you're looking for here and I've modified it below for use with the addon-sdk.
You can watch for an IFRAME by comparing the location with the top.document location.
I don't think there's an easy way to detect loading of images, etc so you'll probably want to just watch for the first hit that's not an IFRAME and regard everything else as css/image/script content loading.
var chrome = require("chrome");
var httpmods = {
observe : function(aSubject, aTopic, aData) {
console.log("observer", aSubject, aTopic, aData);
aSubject.QueryInterface(chrome.Ci.nsIHttpChannel);
var url = aSubject.URI.spec;
var dom = this.getBrowserFromChannel(aSubject);
if (dom) {
if (dom.top.document && dom.location === dom.top.document.location) {
console.log("ISN'T IFRAME");
} else {
console.log("IS IFRAME");
}
}
},
getBrowserFromChannel: function (aChannel) {
try {
var notificationCallbacks =
aChannel.notificationCallbacks ? aChannel.notificationCallbacks : aChannel.loadGroup.notificationCallbacks;
if (!notificationCallbacks)
return null;
var domWin = notificationCallbacks.getInterface(chrome.Ci.nsIDOMWindow);
return domWin;
}
catch (e) {
dump(e + "\n");
return null;
}
}
}
require("observer-service").add("http-on-modify-request", httpmods.observe, httpmods);
In backbone.js documentation it says:
To make a handy event dispatcher that can coordinate events among different areas of your application: var dispatcher = _.clone(Backbone.Events)
Can anyone explain how to implement the dispatcher to communicate from one view to another? Where do I have to place the code in my app?
Here is a good article about using an event aggregator.
Can anyone explain how to implement the dispatcher to communicate from one view to another? Where do I have to place the code in my app?
You will probably have some kind of App Controller object, which will control the flow of the app, creating views, models, etc. This is also a good place for the event aggregator.
From my point of view, I think that article explains it pretty well.
Recently I needed an EventDispatcher to handle a large amount of events without loosing track of their names and their behave.
Perhaps it helps you too.
Here a simple example View:
define(['backbone', 'underscore', 'eventDispatcher'],
function(Backbone, _, dispatcher){
new (Backbone.View.extend(_.extend({
el: $('#anyViewOrWhatever'),
initialize: function () {
window.addEventListener('resize', function () {
// trigger event
dispatcher.global.windowResize.trigger();
});
// create listener
dispatcher.server.connect(this, this.doSomething);
// listen only once
dispatcher.server.connect.once(this, this.doSomething);
// remove listener:
dispatcher.server.connect.off(this, this.doSomething);
// remove all listener dispatcher.server.connect from this:
dispatcher.server.connect.off(null, this);
// remove all listener dispatcher.server.connect with this method:
dispatcher.server.connect.off(this.doSomething);
// remove all listener dispatcher.server.connect no matter what and where:
dispatcher.server.connect.off();
// do the same with a whole category
dispatcher.server.off(/* ... */);
// listen to all server events
dispatcher.server.all(this, this.eventWatcher);
},
doSomething: function(){
},
eventWatcher: function(eventName){
}
})
))();
});
Here the EventDispatcher with some example events. The events itself are predefined in the template Object. Your IDE should recognize them and lead you through the list.
As you can see, the Dispatcher run on its own. Only your View or whatever needs underlying Event methods from Backbone.
// module eventDispatcher
define(['backbone', 'underscore'], function (Backbone, _) {
var instance;
function getInstance () {
if ( !instance ) {
instance = createInstance();
}
return instance;
}
return getInstance();
function createInstance () {
// dummy function for your ide, will be overwritten
function e (eventContext, callback) {}
var eventHandler = {},
// feel free to put the template in another module
// or even more split them in one for each area
template = {
server: {
connect: e,
disconnect: e,
login: e,
logout: e
},
global: {
windowResize: e,
gameStart: e
},
someOtherArea: {
hideAll: e
}
};
// Create Events
_.each(template, function (events, category) {
var handler = eventHandler[category] = _.extend({}, Backbone.Events);
var categoryEvents = {
// turn off listener from <category>.<**all events**> with given _this or callback or both:
// off() complete purge of category and all its events.
// off(callback) turn off all with given callback, no matter what this is
// off(null, this) turn off all with given this, no matter what callback is
// off(callback, this) turn off all with given callback and this
off: function (callback, _this) {
if(!callback && _this){
handler.off();
}else{
_.each(template[category], function(v, k){
k != 'off' && template[category][k].off(callback, _this);
});
}
}
};
events.all = e;
_.each(events, function (value, event) {
// create new Listener <event> in <category>
// e.g.: template.global.onSomething(this, fn);
categoryEvents[event] = function (_this, callback) {
_this.listenTo(handler, event, callback);
};
// create new Listener <event> in <category> for only one trigger
// e.g.: template.global.onSomething(this, fn);
categoryEvents[event].once = function (_this, callback) {
_this.listenToOnce(handler, event, callback);
};
// trigger listener
// e.g.: template.global.onSomething.trigger();
categoryEvents[event].trigger = function (debugData) {
console.log('**Event** ' + category + '.' + event, debugData ? debugData : '');
handler.trigger(event);
};
// turn off listener from <category>.<event> with given _this or callback or both:
// off() complete purge of category.event
// off(callback) turn off all with given callback, no matter what this is
// off(null, this) turn off all with given this, no matter what callback is
// off(callback, this) turn off all with given callback and this
// e.g.: template.global.onSomething.off(fn, this);
categoryEvents[event].off = function (callback, _this) {
handler.off(event, callback, _this);
}
});
template[category] = categoryEvents;
});
return template;
}
});
The behavior of Backbones Event-system is not affected in any way and can be used as normal.