Mashup: web performance with raycasting

First, a confession: I always wanted to be a game developer.  My first programming failures were to try and make games in Turbo Pascal back in the late 80’s.  I was inspired again by Hunter Loftis’ post A first-person engine in 265 lines.  Using that as a foundation, I added maps and textures generated from Speedreport.  Without further ado, I give you Adventures In Web Performance!

Screenshot 2014-07-08 at 03.58.08 PM

The Speedreport script uses Apache Usergrid as a backend. There is a free public instance of Usergrid at http://apigee.com/appservices/, graciously hosted by my employer, Apigee.

To submit your site or app, just clone the Speedreport repo and follow the instructions to test your site.  Bug reports and pull requests are always welcome!

-ryan (@ryanbridges)

Testing web UI interaction response times with CasperJS

I’ve written a few utilities lately to measure how fast a page loads over the wire.  While watching Nicholas Zakas’ presentation at Velocity, I started wondering how I would measure the load times for popups, tabs, and other dynamic content loaded via user interaction.  CasperJS has already proven extremely handy for automating some pretty complex functional tests that had previously been done manually, so I pulled that out of the tool box to see if I could add some measurements.

Unfortunately, Nicholas’ demo was so fast and consistent that the numbers didn’t look believable :-) So, like most web developers, I turned to jQuery. And, as always, jQuery had exactly what I needed. The jQuery UI Tabs Example came complete with dynamically loaded, slow, and even broken tabs.  The Gist and output are below.

var colorizer = require('colorizer').create('Colorizer');
var casper = require('casper').create();
var totalTests=3;
casper.start('http://jqueryui.com/resources/demos/tabs/ajax.html', function(){
	casper.viewport(1024, 768);
	this.test.assertHttpStatus(200, "The page has loaded.");
	this.test.assertSelectorExists('#tabs', "We got tabs.");
	this.test.assertVisible('#tabs-1', "Content 1 is visible.");
	this.capture('ui-id-1.png');
});
testTabLoad('#ui-id-2', '#ui-tabs-1', "Tab 1", "tab1.png");
testTabLoad('#ui-id-3', '#ui-tabs-2', "Tab 2", "tab2.png");
testTabLoad('#ui-id-4', '#ui-tabs-3', "Tab 3 (slow)", "tab3.png");
testTabLoad('#ui-id-5', '#ui-tabs-4', "Tab 4 (broken)", "tab4.png");
casper.run(function() {
	this.test.done(totalTests);
	this.test.renderResults(true);
});
function testTabLoad(tab, content, name, capfilename){
	totalTests+=4;
	casper.then(function() {
		if(name)casper.echo(name, "COMMENT");
		var start=Date.now();
		this.test.assertSelectorExists(tab, "Tab selector exists.");
		this.test.assertSelectorExists(content, "Content selector exists.");
		this.test.assertDoesntExist(content+'>p', "Content is not already populated.");
		this.test.assertNotVisible(content, "Content selector is not currently visible.");
		this.click(tab);
		this.waitUntilVisible(content+'>p', function(){
			casper.echo("Content became visible in " + (Date.now()-start) + " ms", "INFO_BAR");
			if(capfilename)this.captureSelector(capfilename, content);
		});
	});	
}

Selection_012