Is there a way (preferably Firefox or Chrome) to log all the DOM methods invoked/properties modified by a Web app?
I need this to understand some of the working of web apps whose code I don't have in non-minified version.
I understand that this won't give me the complete picture, but I am more interested in the web app's interaction with the browser for my purpose.
You can log all method calls for specific class of objects by wrapping all of its methods with a custom logging function:
var originalMethod = SomeObject.prototype.someMethod;
SomeObject.prototype.someMethod = function() {
//log this call
originalMethod.apply(this, arguments);
}
I've created a function that hooks up such wrappers to all (non-inherited) methods of given class and logs all calls to the console:
function logMethodCalls(className) {
function wrapMethod(className, methodName, prototype) {
var orgMethod = prototype[methodName];
return function() {
window.console.debug('%c'+className+'::%c'+methodName, 'color: #FBB117; font-weight: bold', 'color: #6F4E37', {
details: {
scope: this,
arguments: arguments
}
});
return orgMethod.apply(this, arguments);
};
}
if(!window[className] || typeof window[className] !== 'function') {
window.console.error('Invalid class name.');
return;
}
var prototype = window[className].prototype;
for(var i in prototype) {
if(prototype.hasOwnProperty(i)) {
if(typeof prototype[i] === "function") {
prototype[i] = wrapMethod(className, i, prototype);
}
}
}
}
I'm running it like this:
["Document", "DocumentFragment", "Element", "Event", "HTMLElement", "HTMLDocument", "Node", "NodeList", "Window"].forEach(function(i){
logMethodCalls(i);
});
You can customise the array above to track only classes that you are interested in.
The output looks like this:
To be perfectly honest there is so much output that I don't think this type of debugging may be usable. You can try extending this solution even more by observing all properties (e.g. by defining getters and setters or proxies for all objects), but this will get even more messy.
Great idea! Tracking DOM changes may be useful when trying to understand how website/app works, but also while searching for performance bottlenecks (DOM access is expensive).
I haven't found extension that does exactly what you are asking for, so I've created one. You can install DOMListener from Chrome Web Store.
DOMListener extension uses MutationObserver to catch all DOM changes and outputs friendly messages to the DevTools console. Note that I'm using console.debug() so you can easily filter these messages out:
Code is available on GitHub. If you prefer to avoid installing the extension or you want to get a similar output in Firefox, simply grab the DOMListener.js file and run it in the console.
Related
Propose the following situation:
function functionExists(functionName) {
if (typeof window[functionName] == 'function') console.log("It's a function");
}
What would be an equivalent function in nodejs for functionExists where there is no global window variable?
CONCRETE SITUATION:
My concrete situation uses webpack instead of nodejs, but basically the problem is the same. I could use window here, but it would be too complicated to implement everything cleanly, and it isn't advised by webpack to mitigate things out to the window global variable.
Basically, I have a PHP backend, which generates a html <form> adding some options to it via a data attribute. When the page is loaded, my javascript initializes this <form> and gives it a bunch of functionalities (like validation for example). Another thing javascript does with this form, is that it parses the data attribute of it, and instead of the normal page reload submit, it changes the form so it is being submited over an ajax request to the server.
When this submit happens, it is set up, that the button and the whole form gets disabled, until my Ajax script sends back a response. How this is done, is that I have a Project_Form class, which when it is initialized, attaches itself to the jQuery submit event, stops the basic submit event, and runs an inner function which sends an ajax request to an api method. The ajax request is set up, that when a response is received, the same instantiated class will receive this response, so I can continue working with it.
When the form receives the response, it must do something with it. In the most basic situation, it must show a success message to the user, but there are some more complex situation, where for example, it has to make a page redirect (for example a login form). Right now, it is set up, that as a default, it will show a message, but when I define this form in PHP, I have the option to "hijack" this default behaviour, and instead of it, send the ajax response to a custom function, which will resolve the situation specifically.
When I am rendering the form in PHP, I already know where the form should send a success response (to which javascript function), but I can only provide this information to javascript, via a string. So my Project_Form class, should fetch this string, and should try to fetch a function from it which it will use. This is where my problem is coming from.
Unless you specifically KNOW that this is a global function (which is almost never the case in nodejs), functions by default in nodejs are scoped to the module and there is NO way to look them up by string name like you did with the window object in the browser, just like there is no way to look up local variables by name inside a function in Javascript.
In general, don't pass functions by string name. Or, if you have to, then you need to create a lookup table that you can check the function name against.
I'd suggest you explain the real problem you're trying to solve here because passing the function by string name is not how you would generally want to do things.
There is a bit of a hack using eval() that can see if a string represents a function name that is in scope:
// Warning, you must know that the argument f (if it is a string) does not
// contain harmful Javascript code because it will be used with eval()
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
Note: This tests to see if the function is in the scope of the isFunction() function. If you want to test if it's in your current scope, then you need to do the:
eval(`typeof ${f} === "function"`)
inline in your current scope so it runs in the scope you want to do the lookup from.
To ever consider using this, you will HAVE to know that the source of your string is safe and cannot contain harmful code. But, as I said earlier, it's better to design your program differently so you aren't referring to functions by their string name.
And, here's a runnable snippet that shows it in action (also works in a node.js module):
function test() {
console.log("in test");
}
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
console.log(isFunction("test")); // true
console.log(isFunction(test)); // true
console.log(isFunction("notAFunction")); // false
More added after question edit
If you only have the function name as a string and the function that it points to is not a property of some known object, then the only way I know of to turn that string into a function reference is with eval().
You could directly execute it with eval() such as eval(functionName + "()") or you could get a reference to the function with eval("let fn = " + functionName) and then use the newly defined fn variable to call the function.
If you control the various functions that could be referenced (because they're your Javascript), then you can make all those functions be a property of a known object in your Javsacript:
const functionDispatcher = {
function1,
function2,
function3,
function4
}
Then, instead of using eval(), you can reference them off the functionDispatcher object like you would have referenced before with window (except this isn't a global) as in:
functionDispatcher[someFunctionName]();
This would be a preferred option over using eval() since there is less risk of insertion of random code via an unsafe string.
In node.js you can achieve this like:
function functionExists(functionName) {
if(functionName && typeof functionName === "function")
console.log("It is a function");
}
Hope this works for you.
A methodological question:
I'm implementing an API interface to some services, using node.js, mongodb and express.js.
On many (almost all) sites I see code like this:
method(function(err, data) {
assert.equal(null, err);
});
The question is: should I keep assert statements in my code at production time (at least for 'low significance' errors)? Or, are these just for testing code, and I should better handle all errors each time?
You definitively should not keep them in the production environment.
If you google a bit, there are a plethora of alternative approaches to strip out them.
Personally, I'd use the null object pattern by implementing two wrappers in a separate file: the former maps its method directly to the one exported by the module assert, the latter offers empty functions and nothing more.
Thus, at runtime, you can plug in the right one by relying on some global variable previously correctly set, like process.env.mode. Within your files, you'll have only to import the above mentioned module and use it instead of using directly assert.
This way, all around your code you'll never see error-prone stuff like myAssert && myAssert(cond), instead you'll have ever a cleaner and safer myAssert(cond) statement.
It follows a brief example:
// myassert.js
var assert = require('assert');
if('production' === process.env.mode) {
var nil = function() { };
module.exports = {
equal = nil;
notEqual = nil;
// all the other functions
};
} else {
// a wrapper like that one helps in not polluting the exported object
module.exports = {
equal = function(actual, expected, message) {
assert.equal(actual, expected, message);
},
notEqual = function(actual, expected, message) {
assert.notEqual(actual, expected, message);
},
// all the other functions
}
}
// another_file.js
var assert = require('path_to_myassert/myassert');
// ... your code
assert(true, false);
// ... go on
Yes! asserts are good in production code.
Asserts allow a developer to document assumptions that the code makes, making code easier to read and maintain.
It is better for an assert to fail in production than allow the undefined behaviour that the assert was protecting. When an assert fails you can more easily see the problem and fix it.
Knowing your code is working within assumptions is far more valuable than a small performance gain.
I know opinions differ here. I have offered a 'Yes' answer because I am interested to see how people vote.
probably no
ref: When should assertions stay in production code?
Mostly in my code i put error handling function in a separate file , and use same error method everywhere, it mostly depends on logic anyways
like ppl generally forget this
process.on('uncaughtException', function (err) {
console.log(err);
})
and err==null doesn't hurts , it checks both null and undefined
Preparation
Hi i am using CasperJS in combination with grunt-casper (github.com/iamchrismiller/grunt-casper) for running automated functional and regression tests in our GUI Development process for verification.
We use it like this, casper runner in gruntfile.js:
casper: {
componentTests: {
options: {
args: ['--ssl-protocol=any', '--ignore-ssl-errors=true', '--web-security=no'],
test: true,
includes: ['tests/testutils/testutils.js']
},
files: {
'tests/testruns/logfiles/<%= grunt.template.today("yyyy-mm-dd-hhMMss") %>/componenttests/concat-testresults.xml': [
'tests/functionaltests/componenttests/componentTestController.js']
}
},
so as it can be seen here we just normally run casper tests with SSL params and calling only ONE Controllerclass here instead of listing the single tests (this is one of the roots of my problem). grunt-casper delivers the object which is in charge for testing and inside every single Controllerclass the tests are included and concatenated....
...now the componentTestController.js looks like the following:
var config = require('../../../testconfiguration');
var urls = config.test_styleguide_components.urls;
var viewportSizes = config.test_styleguide_components.viewportSizes;
var testfiles = config.test_styleguide_components.testfiles;
var tempCaptureFolder = 'tests/testruns/temprun/';
var testutils = new testutils();
var x = require('casper').selectXPath;
casper.test.begin('COMPONENT TEST CONTROLLER', function(test) {
casper.start();
/* Run tests for all given URLs */
casper.each(urls, function(self, url, i) {
casper.thenOpen(url, function() {
/* Test different viewport resolutions for every URL */
casper.each(viewportSizes, function(self, actViewport, j) {
/* Reset the viewport */
casper.then(function() {
casper.viewport(actViewport[0], actViewport[1]);
});
/* Run the respective tests */
casper.then(function() {
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
});
});
});
});
casper.run(function() {
test.done();
});
});
Here you can see that we running a 3 level loop for testing
ALL URLs given in a JSON config file which are contained in an ARRAY of String ["url1.com","url2.com"....."urln.com"]
ALL VIEWPORT SIZES so that every URL is tested in our desired Viewport resolutions to test the correct Responsibility behaviour of the components
ALL TESTFILES, all testfiles only include a TEST STUB what means, no start, begin or something else, its all in a large Testsourrounding.
MAYBE this is already mocky and can be done in a bette way, so if this is the case i would glad if someone has proposals here, but don't forget that grunt-casper is involved as runner.
Question
So far, so good, the tool in general works fine and the construction we built works as we desired. But the problem is, because all testfiles are ran in a large single context, one failing component fails the whole suite.
In normal cases this is a behaviour i would support, but in our circumstances i do not see any proper solution than log the error / fail the single testcomponent and run on.
Example:
I run a test, which is setUp like described above and in this part:
/* Single tests for every resolution and link */
casper.each(testfiles, function(self, actTest, k) {
casper.then(function() {
require('.'+actTest);
});
});
we include 2 testfiles looking like the following:
Included testfile1.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Atoms']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
casper.click(x("//a[normalize-space(text())='Atoms']"));
},
function fail() {
casper.test.assertExists(x("//a[normalize-space(text())='Atoms']"));
});
});
Included testfile2.js
casper.then(function () {
casper.waitForSelector(x("//a[normalize-space(text())='Buttons']"),
function success() {
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
casper.click(x("//a[normalize-space(text())='Buttons']"));
},
function fail() {
testutils.createErrorScreenshot('#menu > li.active > ul > li:nth-child(7)', tempCaptureFolder, casper, 'BUTTONGROUPS#2-buttons-menu-does-not-exist.png');
casper.test.assertExists(x("//a[normalize-space(text())='Buttons']"));
});
});
So if the assert in testfile1.js fails, everthing failes. So how can i move on to testfile2.js, even if the first fails? Is this possible to configure? Can it be encapsulated somehow?
FYI, this did not work:
https://groups.google.com/d/msg/casperjs/3jlBIx96Tb8/RRPA9X8v6w4J
Almost similar problems
My problem is almost the same like this here:
https://stackoverflow.com/a/27755205/4353553
And this guy here has almost another approach i tried but got his problems too because multiple testsuites ran in a loop occuring problems:
groups.google.com/forum/#!topic/casperjs/VrtkdGQl3FA
MUCH THANKS IN ADVICE
Hopefully I understood what you ware asking - is there a way to suppress the failed assertion's exception throwing behavior?
The Tester's assert method actually allows for overriding the default behavior of throwing an exception on a failed assertion:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
test.assert(false, message, { doThrow: false });
Not all assert helpers have this option though and the only other solution I can think of is catching the exception:
var message = "This test will always fail, but never throw an exception and fail the whole suite.";
try {
test.assertEquals(true, false, message);
} catch (e) { /* Ignore thrown exception. */ }
Both of these approaches are far from ideal since the requirement in our cases is to not throw for all assertions.
Another short term solution that requires overriding the Tester instance's core assert method is (but is still quite hacky):
// Override the default assert method. Hopefully the test
// casper property doesn't change between running suites.
casper.test.assert =
casper.test.assertTrue = (function () {
// Save original assert.
var __assert = casper.test.assert;
return function (subject, message, context) {
casper.log('Custom assert called!', 'debug');
try {
return __assert.apply(casper.test, arguments);
}
catch (error) {
casper.test.processAssertionResult(error.result);
return false;
}
};
})();
That said, I'm currently looking for a non-intrusive solution to this "issue" (not being able to set a default value for doThrow) as well. The above is relative to Casper JS 1.1-beta3 which I'm currently using.
I follow a tutorial with Meteor I try to create a collection, both for client and server. Here is my code:
var lists = new Meteor.Collection("Lists");
if (Meteor.isClient) {
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
As tutorial I have read, when run on server, if I open chrome console and type lists I will receive Meteor.Collection. But when I tried on my machine, I received error:
Reference error. lists is not define
Have I done something wrong? Please tell me.
Thanks :)
Also you can put all your collections inside the /lib/collection.js route (for better practices).
So with that we ensure that meteor loads first the collections, and they will be available on both client/server.
you should remove Autopublish/insecure package, to avoid meteor sends all the collections when load and to control who can or not insert/remove/update on the collections.
meteor remove autopublish
meteor remove insecure.
So a simple collection will look like this.
//lib/collection.js
Example = new Mongo.Collection("Example") //we create collection global
if(Meteor.isClient) {
Meteor.subscribe('Example') //we subscribe both after meteor loads client and server folders
}
now on /server/collections.js
Meteor.publish('Example', function(){
return Example.find(); //here you can control whatever you want to send to the client, you can change the return to just return Example.find({}, {fields: {stuff: 1}});
});
// Here we control the security of the collections.
Example.allow({
insert: function(userId, doc) {
if(Meteor.userId()){
return true; //if the user is connected he can insert
} else{
return false// not connected no insert
}
},
update: function(userId, doc, fields, modifier) { //other validation },
remove: function(userId, doc) { //other validation },
});
Just to try to explain a little more deep the Collection here on meteor, hope it help you GL
I think you have autopulish/autosubscribe turned off. Try
if (Meteor.isClient) {
Meteor.subscribe('lists');
}
if (Meteor.isServer){
Meteor.publish('lists',function(){
return Lists.find();
});
}
For your naming, I'd also recommend you reverse the way you're capitalizing your collections. So instead it would be
var Lists = new Meteor.Collection("lists");
And finally, look at https://github.com/matteodem/meteor-boilerplate for your directory structure so you don't have to do the if meteor.is stuff anymore.
Edit
Full code should look like:
var Lists = new Meteor.Collection("lists");
if (Meteor.isClient) {
Meteor.subscribe('lists');
}
if (Meteor.isServer){
Meteor.publish('lists',function(){
return Lists.find();
});
}
All of your script source files are wrapped in a function closure as part of the build process. In order for your collection to be visible outside of that file (or in your case - attached to the window object) you will need to declare it as a global variable:
Lists = new Meteor.Collection('lists');
Note the lack of var. As #thatgibbyguy pointed out, the accepted pattern is to capitalize collection variables, and camelcase collection names.
Rather than copy and pasting my code onto here, I have uploaded it to github. The RequireJS module does have a dependency on jquery.signalr and in tern has a dependency on jquery but also have a dependency on the javascript held in /signalr/hubs. There is a bit of config to do with Require.Config.
Basically what is happening is on the first time you load the page the connection is made to the hubs within signalr and the "server side" code is executed and does the desired thing. When you refresh the page it does not. All client side code is called, so for example:
var myViewModel = new MyViewMode();
myViewModel.init();
and within your init method you have
var connection = $.connection.myHub;
this.init = function() {
connection.server.myMethod();
}
this would then go off to
public MyHub : Hub
{
public void MyMethod()
{
Client.Request.populateSomeInformation() // I think it's request but I'm doing this from memory!
}
}
and then call
connection.client.populateSomeInformation = function () { .. )
but doesn't call this :(
It looks like a connection has been made (using the good old console.log() to see what it outputs) and indeed debugging the project it executes the code within the hub but there is no response made back to the javascript.
So wonderful people of the internet, where am I going wrong? Do I need to check the state of $.connection.hub.start(); before attempting to start it again?
Time for beer :)
I believe it should be
connection.client.populateSomeInformation = function () { .. )
(not connection.server)
http://www.asp.net/signalr/overview/hubs-api/hubs-api-guide-javascript-client#callclient
(observations on the code you have on github right now)
var isLoaded = false;
// ... some code that doesn't change isLoaded ...
if (isLoaded == false) {
scrollIntervalId = window.setInterval(function () {
signalRLoaded();
}, 30);
}
I think isLoaded will always be false at this point. Not sure what you intended this to accomplish.
var connection = $.connection.hub.start();
I don't think you're supposed to open the connection before defining any client functions. I don't see any client functions being defined here, so maybe you're doing that somewhere else? I don't know if it really matters other than if the server attempts to call a client function that hasn't yet been defined...
function SignalRReady(callback) {
if (isLoaded) {
callback(connection);
} else {
readyCalls = callback;
}
return SignalRReady;
}
SignalRReady.version = "1.0.0";
SignalRReady.load = function(name, request, onLoad, config) {
if (config.isBuild) {
onLoad();
} else {
SignalRReady(onLoad);
}
};
return SignalRReady;
I'm confused by this bit of code, probably because I don't see how it's being used. Is this an attempt at a kind of singleton? I see that SignalRReady is the "class" being returned for the module. You're not really returning an object, you're returning a constructor which implies that you're instantiating it in other places, something like
define(['SignalRReady'], function(sigR)
{
var srr = new sigR();
});
But then you have that load function defined that calls the constructor and makes this look all weird. How are you using this?
Anyways, I'm thinking you might be hitting some kind of race condition where the client function may not always be available at the time the server is trying to call it.
(additional comments/code 2013-09-06)
Your connection object is actually a jQuery promise ( http://api.jquery.com/category/deferred-object/ ).
If you're unfamiliar with promises, think of them generically as a queue of callbacks to be executed later. In this case, when connected, all the callbacks will be executed (in the order they were added). If a callback is added after being connected, it will get executed immediately. This is how your code is working now. You add the callback to the .done queue after the connection is made and is executed immediately.
If you insist on creating the connection object yourself, then you do not need to use the stateChanged event. You just add the callback to the .done queue:
define(function()
{
function signalRReady(callback)
{
if (window.connection == undefined) {
window.connection = $.connection.hub.start();
}
window.connection.done(callback);
}
signalRReady.version = "1.0.0";
return signalRReady;
});
However, I believe it's not a good idea to initiate the connection yourself. Because your module isn't a complete wrapper around SignalR such that people would only use your module to do SignalR stuff, you are not guaranteed (and cannot expect) other code will not initiate the connection. Especially if someone is adding your module to an existing codebase.
Your module is simply adding a new event, so keep it simple. Take the callback and execute it yourself when appropriate:
define(function()
{
function signalRReady(callback)
{
$.connection.hub.stateChanged(function (state)
{
if(state.newState === $.signalR.connectionState.connected)
{
callback();
}
});
}
signalRReady.version = "1.0.0";
return signalRReady;
});
Nowadays, promises are pretty popular. You might want to implement a promise-based module like:
define(function()
{
var deferred = $.Deferred();
$.connection.hub.stateChanged(function (state)
{
if(state.newState === $.signalR.connectionState.connected)
{
// executes all callbacks attached by the "ready" function below
deferred.resolve();
}
});
return {
ready: function(callback)
{
deferred.done(callback);
},
version: "1.0.0"
};
});
If callbacks are attached after the connection has been made, they are executed immediately.
Also, notice this example module's init function returns an object instead of a function. Since RequireJS will pass the same instance around to any module that requires it, state is maintained - we can use local variables instead of global.