Wednesday, August 19, 2015

Creating Masked Input Directive with TDD–part2

In the previous post we started implementing the masked input directive. We’ve written tests and the implementation of the directive’s controller. Now it’s time to add the directive itself and of course we’ll start form the tests.

Testing the directive means testing it’s interaction with the UI. These are your integration tests. We’ll want to test the controller logic and the way it reflects in the UI.

First we’d like to test that the directive’s isolated scope has the provided “mask” and “skip” values (keep in mind that in a real application you would test the existence of all the DDO values):

image

Some key notes from this test:

1. In order to test a directive we must create a string that represents its DOM (an element which has the directive attribute i.e.).

2. $compile service parses the element’s DOM and executes the directive function with the provided scope. So the “element” variable is now the directive with all its properties and methods.

3. We can access the scope properties using the element’s “√≠solateScope” method.

Now let’s define the DDO:

image

Then we’d like to test that the element’s value will have the provided mask value after the DOM compiles.

image

And now with the link function:

image

In order to change the UI (the element’s value property) you have to call to $setViewValue that is a special angular method that is in charge of setting the value property of the directive element (<input type=”text” value=”this one”/>). $render is called for the UI changes to take place.

Now we add the directive to an html file and actually see all the stuff that we were testing. Add an index.html file, include angular and all the client folder except the spec files!

image

Run it:

clip_image002

That’s what I’m talking about!

All that’s left is connecting our tested (TDD baby) controller functionality to every time the user presses a key.

image

I’ve created a keydown event using the private createKeyDownEvent method and fired it.

The implementation:

image

We subscribe to the keydown event, get the new char, call editMask and if successful re-render the UI.

That’s it! You have a functional masked input element which is fully tested.

clip_image002[5]

As you can see, writing TDD with angular is extremely easy and straight forward. If you are not writing tests then you most definitely should! Just begin, it’s worth it.

Have fun TDDing,

Tuesday, August 18, 2015

Creating Masked Input Directive with TDD–Part 1

In the next two posts I’d like to show you three things:
1. What is a “masked input”.
2. How to create a masked input custom angular directive.
3. And the cherry on top – implement it applying TDD!
So what it is “masked input”?
It allows users to easily enter fixed length input where you would like them to enter the data in a certain format (dates, phone numbers, ids, credit card number and more).
Most of forms out there don’t supply the users any hints about the data’s format and make the users guess it (most of the time the input fields will be  blank textboxes). If there’s a format mismatch then the user will receive an error and will try again.
Using masks allowclip_image003 us to show the users the exact format and force them to enter it correctly.
Let’s implement it!
Remember that we’ll do it using TDD.
So first let’s define the desired API:
image
We want to create a custom attribute directive that will have three properties:
1. Mask – the mask that the user will see in the textbox. These values will be replaced by the user’s input as they type.
2. Skip – an array of chars that we want to be left along with the user’s input like ‘/’ in a date textbox – 01/06/1991
3. Ng-model – the associated model from some controller.
Great! Now after we know our goal we can start writing code.
1. Create ASP.NET Web API project
Add the following nuget packages:
- Angularjs.core
- jasmineTest – this is the jasmine.js testing framework for ASP.NET MVC
- angularjs.TypeScript.DefinitelyTyped
- jasmine.TypeScript.DefinitelyTyped
The last two packages include definition files used generally for TypeScript for the 3rd parties intellisense. However I found that even if you don’t write TypeScript there intellisense is pretty helpful.
clip_image002[6]
Now let’s add a Client directory, index.html file, app.module.js, app.controller.js and a InputMask directory (all the angular code is style accordingly the John’s Papa style guide).
clip_image004[6]
2. Enter TDD
Before we implement the controller we’ll add a spec file to test the controller, we will add a basic test, let it fail and only then implement the controller and the module.
Add a form.controller.spec.js file (this is a style guide naming convention, formControllerSpec.js is also fine). Now we’ll add a basic jasmine test for testing that our controller is defined.
image
Nothing special here: we inject the $controller service in order to get our controller, inject it with a new scope and assert that the controller is defined.
Now let’s add all the files into the SpecRunner.cshtml file:
image
I’ve added angular, angular.mocks, the module and the controller.
The test fails since there’s no module or a defined controller– let’s add them.
First the module:
image
I’m using IIFE to prevent my functions getting into the global scope and prevent the tests get to my private methods.
And the controller:
image
I’m using the $inject pattern in order to make sure that my controller parameters won’t get ruined after minifying the code.
Let’s run the test:
clip_image002
Now let’s add another test to validate that the scope works:
image
Notice that even in js tests I still use the AAA pattern. It makes the tests readable, especially when they get complex.
Run and pass:
clip_image002[5]
1. Adding the directive’s controller
The logic regarding the mask’s chars replacement will be inside the controller (the logic regarding the display will be inside the link function. We’ll get there later).
Add an InputMask directory and place the controller and its spec file in it:
clip_image004
And the first test:
image
I’m placing the specs files near the source files so that the specs will be immediately noticed when someone looks at the solution and so that it will be extremely easy to see that a file is lacking its tests.
Add the controller and the test will pass.
Now let’s start adding some functional tests.
Every time a user enters a letter a controller function must be called in order to edit the mask, it will check the current input length – it shouldn’t be longer than the defined mask and it should replace the mask characters while skipping the values provided in the “skip” array.
Let’s go:
image
And the implementation:
image
Replacing the mask as the user enters input:
image
Notice that the controller sets the ngModel with the mask value on its initialization. We’ll provide the mask value for the ngModel before calling for the editMask method from out test.
The implementation:
image
Now let’s add a test and its implementation for the “skip” characters functionality.
Test:
image
Implementation:
image
Pretty straight forward. Notice how the controller doesn’t do any UI logic– just the way it supposed to be.
In a real life application you should add as many test you can for your controllers in order to achieve maximum code and use cases coverage, in this post (which is already quiet long) we’ll stop here and move towards the next topic – testing the directive.

Friday, August 14, 2015

Crawling HTML with CsQuery

Recently I was asked to build a crawler for a webpage.


The crawler was supposed to get part of the main page values like the TV Show name, it’s season etc.

So how do you do it?

First you have to download the page’s html to your server:
using (var client = new WebClient())
 {
     htmlContent  =            client.DownloadString(link);
 }
Now you have the whole document as a string. In order to get the relevant values you have to identify the path to the element that has the desired value. You’ll want to find an element with an “Id” attribute so you can be sure that it is unique and set it as the root of your path. From that element you’ll have to travel the DOM until you get to the wanted element and its value.

For example: In order to get the TV show title in the above website I’ll Inspect the element from the browser:






















The TV Show name is the innerText of the “a” element. The first unique element with an “Id” attribute is the <div id=”main”> (there’s another element that doesn’t have an id attribute but still seems kind of unique – <div class=”subpage_title_block”> both can be used).
After we identified the root element we need to explicitly describe the whole path:

div (id=main) => div => div => div (notice that the former element has an “a” element as a first child) > h3 => a. The last element has the TV Show title as its innerText.

The fun part

So how can we create such a path while the DOM is represented as a single string?
There are several solutions for crawling an HTML string: the most common is the HTMLAgilityPack which allows to perform lync style operation on the DOM. It’s nice but not simple enough to use.

There is another crawling solution - CsQuery (“Install-Package CsQuery” from nuget). It’s API is so neat and straight forward - just the way you would want it:
CQ dom = "<div>Hello world! <b>I am feeling bold!</b> What about <b>you?</b></div>";

In order to create a new CQ instance all you have to do is just serve the html string.
The selection is really simple too:
var boldElements = dom["b"].Select(x => x.InnerText).ToList();

Here you select all the bold text from the DOM.
So how does CsQuery help us in our example?
var tvShowTitle = dom["div#"main > div > div > div> h3 > a].InnerText;

Yes! That simple!


Enjoy.