Wednesday, October 8, 2014

Selenium Webdriver in Nodejs + Javascript

Phewww getting back to blog after almost an year.
So, am back to discuss an interesting node module selenium-webdriver [Ref: Project Doc and npm registry]
Am assuming the reader has prior knowledge on what nodejs, npm and node modules are. And a little bit of selenium fun ;)
What is selenium?
As wiki says, Selenium is a portable software testing framework for web applications.
It is a prominently used tool for browser automation. For further details checkout SeleniumHQ.

What are we doing here?
Basically Selenium provides bindings in many languages like java, python, php and now even nodejs.
Here am planning to run through few code samples of using selenium webdriver in nodejs.

Where to start?
im@mylaptop$ npm install --save selenium-webdriver

A Simple Webdriver Example
// Import Selenium Dependency
var Webdriver = require('selenium-webdriver');

// Few Settings
var PAGE_LOAD_TIMEOUT_MS = 10000;
var SCRIPT_LOAD_TIMEOUT_MS = 1000;
var WINDOW_WIDTH_PX = 1024;
var WINDOW_HEIGHT_PX = 768;

// Initialize a webdriver with desired capabilites
var driver = new Webdriver.Builder().withCapabilities(Webdriver.Capabilities.firefox()).build();
// Manage timeouts of the webdriver instance
driver.manage().timeouts().pageLoadTimeout(PAGE_LOAD_TIMEOUT_MS);
driver.manage().timeouts().setScriptTimeout(SCRIPT_LOAD_TIMEOUT_MS);
// Manage window settings of the webdriver instance
driver.manage().window().setSize(WINDOW_WIDTH_PX, WINDOW_HEIGHT_PX);

// Request to render google.com
driver.get("http://google.com").then(function () {
		// On Success get the title of the rendered page
    driver.getTitle().then(function (title) {
    		// On Success log it out
        console.log(title);
    });
});

// Initialize a webdriver with desired capabilites
What are the default capabilities?
Checkout capabilities.js
It includes
1. BROWSER_NAME
2. SUPPORTS_JAVASCRIPT
3. SUPPORTS_CSS_SELECTORS
4. TAKES_SCREENSHOT

Webdriver.Capabilities.firefox()
Creates a new capabilities object by overriding the default BROWSER_NAME from 'browserName' to 'firefox'.

So, What are all other browser options?
Checkout Browsers Section

Do all the browsers work by default?
Not really. To initialize a webdriver, we need to make sure that executable of desired browser is present in the system PATH.
For Ex: To use firefox, the following should be checked. If this fails, then appropriate binaries should be installed.

iam@mylaptop$ which firefox
/usr/bin/firefox

Apart from this, few browsers use separate driver executables to abstract the communication via webdriver to actual browser. For Ex: Chrome needs chromedriver. Download and make sure it is available in the system PATH.
Internally chromedriver expects google-chrome to be available in the system PATH.

What if I wish to start chrome or firefox from webdriver with specific options?
var driver = new Webdriver.Builder().withCapabilities(Webdriver.Capabilities.firefox()).setFirefoxOptions({
	firefox_profile: "Name"
}).build();

How do I manage exceptions while loading [like pageload timesout]?
Selenium webdriver is full of promises. Almost every interaction with the webdriver [irrespective of whether it is sync or async] returns a promise.
As we can see in our code,
driver.get("http://google.com").then(function success() {
    console.log('Successful');
    i++;
}, function error(err) {
    console.log(err);
}).thenCatch(function (e) { 
    console.log("Any exceptions in success or err callbacks gets thrown here", e);
    // You need to decide the resolution value here
}).thenFinally(function () {
    console.log("We can tear down stuffs here");
    // You need to decide the resolution value here. If nothing specified undefined will be returned.
});

How do I handle actions that are dependent on some conditions [like may be after some ajax calls you need click some button]?
We can ask driver to wait implicitly on a timeout basis or explicitly on a condition basis.
driver.sleep(MY_SLEEPTIMER_MS).then(function () {
	console.log("I'll do my action");
});
driver.wait(function () {
	if (document.readyState === "complete") {
		return true;
	}
}, TIMEOUT_TO_WAIT).then(function () {
	console.log("I'll do my action here");
}, function () {
	console.log("Either the condn satisfied or the TIMEOUT_TO_WAIT happened; luck is yours");
});

How do I access dom?
It is pretty simple as we do in javascript.
driver.findElement(Webdriver.By.name('test')).then(function (element) {
		element.click();
});
// Other options
// Webdriver.By.tagName
// Webdriver.By.id
// Webdriver.By.css [all valid css selectors works]
// Webdriver.By.xpath
// Many more..
Check out full list here
You can use findElements to get a list of matched elements.

Can we do it on multiple attributes?
Yep we could do that too.
var webElement = driver.findElement({
	css: '#myselector',
	tagName: 'div'
});
// We can even detect elements within scope of another element
var img = webElement.findElement(Webdriver.By.tagName("img"));
The result of the findElement Query is chainable [it is of type WebElementPromise].
function getInputElement(driver) {
	return driver.findElement(Webdriver.By.css("input[type='search']")).then(null, function () {
		return driver.findElement(Webdriver.By.css("input[id*='search']"));
	}).then(null, function () {
		return driver.findElement(Webdriver.By.css("input[name*='search']"));
	});
}
// Fill input with value ABC
getInputElement(driver).then(function (element) {
	element.sendKeys("ABC");
});

Will we be able to execute a custom script of mine in the page's context?
Yes, Absolutely
var myscript = "return document.title";
driver.executeScript(myScript).then(function (value) {
	console.log("document title is ", value);
});
Check executeAsyncScript as well. It might interest you.

What else can we do?
webdriver.js is the best documented code I have seen so far.
It explains all the webdriver apis to dot. Check it out.

Points to remember:
1. Although driver.get returns promise, it is a completely synchronous task and it blocks the nodejs single thread. Beware of this :)
2. You need chromedriver to use Chrome as your Client Browser.
3. findElement returns a chainable promise cum webElement.
4. We can send non printable keys as well using sendKeys. Check list of keys supported.
5. Actions like submit and click will make the driver wait, when they result in redirection but actions like Webdriver.key.ENTER or RETURN won't.
6. Last but not the least these are the core webdriver files
7. You can use selenium standalone server to communicate to a remote webdriver too.
7. Do checkout webdriver.io

Friday, December 27, 2013

The Year 2K13 Was....

As we are at the verge of year 2K13, I asked a question to my inner self
How did it go?
From there on my mind started recalling events, that went past me in the journey.
The journey that made me an year older with handful of new experiences.
2K13 in my calendar is going to be one of the most unfogettable year in both the ways [Happiness & its counterpart].
January:
All the waves into both work and life because of relocation from mumbai to bangalore [Oct 2012] were slowly settling down.
Had Durga to fill the void left in my work as a companion. Someone to discuss and share. And forgot to say, now we are a team ;)
Realized that I got promoted from Web Dev to R&D Engg.
Gave good support to my Super DAD who was taking care of our dream home which was under construction.
Bottom Line: Realized that there is a lot more to do than work in life and Patience rewards

February:
Feb 22 - One of the important events in our family till then, was planned. Our House warming ceremony. My Dad's moment of pride.
Over all the odds, function ended with a note of happiness and pride. Had all my teachers who are the reason for who am now, friends and lots of relatives come home.
Gifted my father for the first time on his birthday after I started my earning. A nice TITAN wrist watch [Getting Goose Bumps even now].
First birthday of two of my nephews in the same month.
Hemanth Sagar Shifted to Bangalore from Mumbai. And now we are 3 heads up.
Bottom Line: Remembering people who had an impact in your growth in life is a respect you give back to them.

Housewarming Invite

March:
Joined Music and Metals [Body Fitness Center] on March 12th.
Can't even say how much value it does add to me now. Never ever thought this could be such a good thing happening to me back then.
Although I Initially joined to reimburse Health and Fitness component at office, Now I swear I stopped reimbursing them.
All credits to Jibin [Trainer & Best Pal] who changed the meaning of workouts to fun and brought people together as a family.
Bottom Line: Passion drives people [Dedicated to Jibin]

April:
April 26th - Marked 3rd anniversary and another year awaiting.
Home Construction was well in progress and heated up to reach the end.
And one of my roommates Deepan Chakravarthy got engaged. Best Surprising moment of the year ;)
Bottom Line: There is always a hidden random surprise awaits us [Dedicated to Deepan :D]

May:
Practised for my first 10K marathon with my companion Durga. Would wish to revisit this post.
Thanks to Dr. Manimozhi & AIFO for giving us such an awesome opportunity.
May 19th - Finished the marathon in 1 Hr and 2 min.
May 20th - My first intern Apurv joined the team.
May 22nd - My sister, classmate and bestest friend Yogi's engagement.
May 22nd - Deepan's marriage.
May 25th - Completed Year 2 @Media.net
Visited Chennai to attend the marriage. Met my partner [Chandru] after almost 3 months.
It was a really nice re-union with Nizha, Kanmani [My Sister] and Chandru at Buhari.
Kushagra Shifted to Bangalore from Mumbai. And we are 4 heads up.
Volunteered LokSatta Party on the election day in Bangalore with Vignesh.
Bottom Line: Determination defines you and what you can.

Team AIFO and M&M after marathon

June:
June 9th - Participated in Corporate relay 5K * 4 with Kushagra, Hemanth, Durga and our manager cum partner Chandru
It was good going with Apurv on his internship and as well at my work.
June 12-13 - Yogi's Marriage at Coimbatore. Couldn't even believe that a kutti friend [small] of mine was getting married. Ufffff.. 23 Yrs Gone..
Had a really nice long chat with Elempirai [Another School Friend of mine] on our way back to home. Almost we shared everything.
Bottom Line: Learning never stops

After Corporate Relay

July:
Visited my beloved partner's home town for the first time in 5 yrs [Sankaran Kovil]. One very memorable trip.
Bike ride to coutrallam in continuously drizzling weather and Fun in the falls was the best out of all.
More than everything else, we celebrated my partner's birthday at his hometown [Fullfilled his childhood dream of cutting cake at his home :P]
Helped my partner to meet his fiancee for the first time [with Venky and Ramesh].
2 days of complete enjoyment made it for the whole month.
Bottom Line: Making your close ones happy is one of the richest feeling :)

Coutrallam

August:
August 10th - First away trip at Music and Metals team to Chunchi Falls & Mekadatu. So, much fun it was. Took my partner with me. Made him visit Bangalore from Chennai.
Visited home town for a 4 days long weekend. Spent some good time off from home with my family.
Falls in the back drop

September:
September 9th - We entered our dream home. It was complete by then. All credits to my Dad. Almost 2yrs of his life was spent on it.
September 17th - Completed one year in bangalore :)
September 29th - After a complete year being in bangalore finally I met my closest buddy Selva only for the Second time :o
We watched a movie [Onaiyum Aatukutiyum] and did swimming at BAC
Bottom Line: True friends don't complaint. Coz they know you :D [Dedicated to Selva]

October:
Two mentees Vedant and Vivek joined hands with us in Bangalore for media.net.
We rocked the Directi Annual Bash :)
Got Promoted as Senior R&D Engg. Promotion Number 2 in 2 yrs :) Awesome place to work with. Recognition of good work at its best.
Bottom Line: Keep focused and Keep moving. There is lot more heights to reach :)

Directi Annual Party

November:
Nov 2nd - Diwali Diwali Diwali... First Diwali at our new home :)
Yogi visited our home with her hubby for the first time after marriage.
Nov 15th - My Cousin Sister gave birth to Shruthika :) Happy Moment.
My first dream come true. My Bike. I said MY BIKE. Got my Yamaha FZS delivered just a day before my birthday :)
Nov 17th - One of the best birthday celebration till date. 12 o'clock cake cut on road with Jibin Akash and Balaji. Long drive. And meeting with special friends ;)
Bottom Line: Full filling your own dreams adds more meaning to your life :)

MY BIKE
My B'day Celeb at M&M

December:
The month which will stay in my heart forever for two extremely opposite feelings.
Dec 5th - Left bangalore to Sankaran Kovil to attend my partner, friend, brother and gem of a person in my life's wedding.
Dec 6th - First ritual [Panthakaal Naduvathu] & Dress Purchase [Usshhhsabba]
Dec 11th - Engagement
Dec 12th - Marriage
Spent one full week with my beloved partner and witnessed one new relation joining hands with him in his life thereafter :)
Went back home. Spent sometime with my family. My Sister scored 8.8 in her 7th Semester [Way higher than me] and made me happier than ever.
The much need break of the year came to an end. Packed and back to bangalore.
Dec 18th - Flew to mumbai for two weeks trip in Mumbai DevCenter
Dec 19th - One of My uncles [He was almost my dad] passed away in an accident. So, flew back to bangalore on an emergency
Dec 20th - The uncle's aunt [She was almost my mother] decided to joins hands with uncle in heaven. Worst way to end an year.
Witnessed an awesome relation that existed in real continued to be so in heaven in just two days.
The best love story I had ever seen in real. Some claimed that it was a foolish act but it was truely an act of proving togetheredness.
They were so close to each other that one can't exist without the other. Hope their wishes will always be with me from heaven.
Only Two people in my life who never knew what selfishness and jealousy was. We lost them.
Two different events in subsequent weeks. Nothing to say but there's a lot to realize.
Bottom Line: This moment is not permanent. Loss is a part of life. Accept and go on.
Everybody needs some spl care at some point in life, just spot it and help them to come out with glory [Dedicated to my sister :)].

Partner's Marriage

Although the year 2013 went ahead in a very much positive note from the beginning with small small obstacles financially and relation wise.
In the end it left me with terrible and unmatchable loss of my second parents.
More & More responsibilities over me. Time to become a man :)
With their wishes let the forthcoming year be another milestone in my career and rejuvenate my family members from the loss.
The year 2K13 was not all about work or the other way round even. There was a perfect balance in everything. Should thank my team at work and my family who helped me make this happen. Special thanks to My Dad, Roomies, Chandru, Durga and Jibin.

Friday, June 28, 2013

GRUNT- The JavaScript Task Runner

Grunt helps developers automate the task of javascript deployment.
In our development cycle, every javascript deployment used to be
1. Code
2. Minify
3. Upload
We were missing out two important phases which ensures code quality and reliability
1. Lint
2. Testing
As our code became larger and larger, as anyother dev we also considered a refactor.
The refactor resulted in splitting our large code base to manageable modules.
Now, Deployment has to go through
1. Unit test independent modules
2. Merge Modules to a shippable target
3. Lint
4. Minify
5. Deploy
Ooops... Nice but how?
It's true that developers love things automated, and so we were. We arrived at a one stop solution GRUNT.

This blog post is a Let Them Know Types. As, I felt that the instructions on grunt setup is kind of scattered :)
To hav a better introduction with the hero, you should meet him at his place
Grunt has two parts:
1. Using it
2. Customizing it

How to start using it?
Installation:
Grunt 0.4.x requires Node.js version >= 0.8.0. Install it from here
Read a bit on npm [Node Pacakge Manager] in case you are not aware of here
$ npm install -g grunt-cli
What is grunt-cli?
grunt-cli is a utility, that makes sure that it runs the grunt version installed locally to the project.
This helps developers having different versions of grunt across projects.
Installing grunt-cli adds "grunt" command to your system path

$ mkdir firstGruntProject
$ cd !$
$ grunt
grunt-cli: The grunt command line interface. (v0.1.9)

Fatal error: Unable to find local grunt.

If you're seeing this message, either a Gruntfile wasn't found or grunt
hasn't been installed locally to your project.

What does this mean?
Basically to begin with a grunt task runner project, there are 3 important requirments.
1. Local grunt module
2. GruntConfig.js //Task runner's configuration
3. package.json

The above error states that we haven't got the local grunt module setup in our project home.
Before doing that, lets set up a very basic grunt project.

Is there any easy way to generate basic grunt config file?
Yes, check out Project Scaffolding
There is a very handy utility "grunt-init", which accepts a TEMPLATE to create a sample GruntConfig file or Grunt Plugin.
A Template is kind of config file for automation of config or plugin creation.

Sample Template for simple grunt project can be downloaded Grunt Git repo
Once setup of template is done, install grunt-init globally
$ git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile
$ npm install -g grunt-init
$ cd firstGruntProject
$ grunt-init ~/.grunt-init/gruntfile
You will get a list of Yes or No's. Answer them and you are almost done to set up a grunt project

Next?
We need a local grunt installation. It is as simple as that [npm install grunt@version]
$ npm install grunt
You can notice the absence of "-g" param for grunt install.
This gives you an option of having multiple grunt versions across your projects. grunt-cli is the util which makes this possible.

Lets try grunt now..
$ grunt
Loading "Gruntfile.js" tasks...ERROR
>> Error: Unable to read "package.json" file (Error code: ENOENT).
Ooops, Most of the gruntfile templates create a project specific package.json. But not in this sample template.
So, Lets create our own using npm init command
$ npm init


Ok, Is there a limitation on where the command should be run from?
You can run "grunt" command from anywhere inside your project.
"grunt" command is kind of nodejs require().
"grunt-cli" util takes care of locating the locally installed grunt module and load it with Gruntfile.js

Once all this is done. Executing grunt should be as smooth as a cake provided there are no errors in the tasks and their internal confs.

Now how to install some packages I need?
It is as simple as installing node packages
$npm install package@version --save-dev
**save-dev option rewrites package.json automagically.

How do I specify package specific configs?
Mostly all modules have their wiki on how should you pass configs.
Check this to get some more idea.

Grunt provides lots and lots of apis. Check them out here
I love grunt.option and grunt.file the most :)

This is one part of the best parts. Grunt makes it possible for people to write their own tasks or plugins. We'll handle that in a separate blog post :)