Yesterday we hosted the second React Meetup in Melbourne, what a great turn out! It was great to see such a big community for a new technology.
Here is a link to the talk Michael and I did:
https://github.com/choonkending
Yesterday we hosted the second React Meetup in Melbourne, what a great turn out! It was great to see such a big community for a new technology.
Here is a link to the talk Michael and I did:
We recently got the opportunity to attend cssconf in Melbourne, followed by Decompress (a day of lightning talks and hacking).
I found it to be a really rewarding experience. The material presented was really relevant to my work and I got to pick the brains of some of the speakers during break time :)
Here's a list of my top 3 takeaways from the CSS Conf AU by category:
After following all the speakers on Twitter, I happened upon a couple of good resources unbeknownst to me, and I’ve added them to my Easter break reading/review/code list of resources:
Front End Guidelines by Benjamin de Cock
https://github.com/bendc/frontend-guidelines
CSS Guidelines by Harry Roberts
http://cssguidelin.es/
Like what we do? Join us then.
Let’s face it. Front end testing, or in fact, any sort of testing that involves you (the developer/tester) manually going through each scenario can be a gruelling process. This post isn’t about the importance of front end testing, because it's 2015.
I’m going to write about testing the UI and simulating user actions in the browser using PhantomJS, CasperJS, Mocha and Chai.
Before I proceed any further, here is a brief introduction to what each framework/library does:
Mocha is a feature-rich JavaScript test framework running on node.js and the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.
Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.
PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.
CasperJS is an open source navigation scripting and testing utility written in Javascript for the PhantomJS WebKit headless browser and SlimerJS (Gecko). It eases the process of defining a full navigation scenario and provides useful high-level functions, methods and syntactic sugar.
CasperJS provides us with some really neat functions to work with. Particularly:
casper.start()
: Configures and starts Caspercasper.waitFor()
: Waits until a function returns true to process any next step.casper.waitUntilVisible()
: Waits until an element matching the provided selector expression is visible in the remote DOM to process a next step. Uses waitFor(). I find this particularly useful especially when we are interacting with DOM elements that have animation.casper.capture()
: Proxy method for PhantomJS’ WebPage#render. Adds a clipRect parameter for automatically setting page clipRect
settings and reverts it back once done.There are many more useful functions here.
CasperJS provides built in testing functionality as well, but we opted for the Mocha testing framework and Chai assertion library because we liked it better.
First get Mocha and Chai installed (if you opt to use Mocha and Chai instead of just using casper’s built in testing utility):
npm install mocha
npm install chai
Then install phantomJS: - npm install -g phantomjs
There are a couple of other ways to install phantomjs shown here.
Get casperjs running: - npm install -g casperjs
Finally get mocha-casperjs and casper-chai installed if you want to use Mocha and Chai with casperjs.
npm install -g mocha-casperjs
npm install -g casper-chai
Note from the future: I recommend installing the
npm
packages locally and specifying the test commands within
package.json
instead.
Alternatively, if you’re happy with just phantomjs and casperjs, using the Chrome extension tool here can help you get off to a good start. Resurrectio allows you to record a sequence of browser actions and produces the corresponding CasperJS script.
Ahem. Let’s really get started now.
Let’s write some code that does all of the following in sequence:
describe('Home page', function() {
before(function() {
casper.start('http://localhost:8000');
});
it('should have an element in DOM', function(){
casper.waitForSelector('#correctElement', function() {
'#correctElement'.should.be.inDOM;
});
});
it('should bring you to another page on click', function() {
casper.thenClick('#destroyEverything', function(){
this.echo('Clicked on Destory everything');
});
casper.waitFor(function check() {
return this.evaluate(function() {
return /urlthatwewant/.test(document.location.pathname);
});
}, function then() {
// Succeeded
this.echo('->Succeeded in loading the another page');
this.capture(anotherPage.png');
}, function timeout() {
this.echo('Failed to load page').exit();
});
});
});
Running the above is simple.
mocha-casperjs <filename>.js
Here are some things we learnt while setting up frontend tests for Kogan.com.
Many of the functions can be reused. Fortunately, PhantomJS allows you to import/require modules using the CommonJS syntax.
A very reusable module would be the login module (simplified version) (as shown below)
module.exports = function(email, password) {
describe('Logging in', function() {
it('Filling in form fields and clicking should log the user in', function() {
casper.then(function(){
this.fillSelectors('form.form-email', {
'input#email' : email,
'input#password' : password
});
this.echo('Filling in details');
});
casper.thenClick('#loginButton', function() {
this.capture('filledIn.png');
this.echo('->Clicked on Login');
});
});
});
};
Having a config file with all your valid/invalid data can also help with making things DRY-er.
/**
config file
**/
module.exports = {
URL: {
dev: ‘http://localhost:8000’
}
};
Putting them all together, we could make the code a lot cleaner, and easier to understand. Pretty sweet huh?
var config = require('./config');
var login = require('./functions/login);
var doSomething1 = require('./functions/doSomething1);
var doSomething2 = require('./functions/doSomething2);
describe('Yet Another Page', function() {
before(function() {
casper.start(config.URL.dev);
});
login();
doSomething1();
doSomething2(1);
});
Like the sound of how we work? Check out our Careers Page!