Angular Project Blackjack: 3 – Unit Testing

(This post is part of my “from scratch” AngularJS project. If you are feeling lost, the first post is here.)

Now that we have our application running and our first controller done, the next thing we want to get setup is our testing framework. Having a testing framework ready to go is always beneficial, no matter what kind of development style you choose. I haven’t been able to get on board with TDD, but that is just my personal preference. I do like to have unit tests that cover my code, but I find it easier to write the tests after the code rather than before.

We are going to use the karma test runner suite to run our jasmine tests. Karma is a tool developed by the AngularJS team to run unit tests against a browser. It has the option to watch files for changes and re-run tests as soon as it detects them. It also reports passes/failures of the tests. Jasmine is the tool that we will write our tests in. We will test each part of the code, expecting certain things to happen, causing the tests to pass or fail.

Let’s get our environment setup to do some testing. Since this is first time we’ll be using npm to install something we want to save to the project, let’s first create a package.json file in the projects root directory:

{
  "name": "angular-blackjack",
  "version": "0.0.1" 
}

Now we are able to install packages with npm and save them to our package.json file so that they can be installed on any other machine that we take the project to.

npm install karma --save-dev
npm install karma-phantomjs-launcher --save-dev
npm install jasmine-core --save-dev
npm install karma-jasmine --save-dev
bower install angular-mocks --save-dev
karma init karma.config.js

This will initialize our karma test runner file karma.config.js. When it asks for which browser you would like to test on, enter ‘PhantomJS’. This is our “headless” browser that runs nicely on the command line. The most important part right now is to make sure karma is loading all of our source files properly like so:

files: [
'./src/bower_components/angular/angular.min.js',
'./src/bower_components/angular-mocks/angular-mocks.js',
'./src/app/blackjack.module.js',
'./src/app/**/*.module.js',
'./src/app/**/*.js',
//Test Specs
'./src/app/**/*.spec.js'
] 

We are telling karma to load all of our javascript files in the src directory, but we want to specifically tell it to load the ‘.spec.js’ files. These will be our tests.

In order to execute tests, inject angular code and core services, we also install angular-mocks. From the documentation, angular-mocks (or ngMocks) “provides support to inject and mock Angular services into unit tests”. This means we do things like “inject”, “dump”, and “module”. Things that are necessary to test our code.

Following the style guide, we want to keep our tests along side of our source code and name the tests as close to the files they are testing as possible. Our first tests will be on our game.controller.js file, so we will put it in the same directory and call it game.controller.spec.js. Let’s go through our test:

describe('GameController Unit Tests', function () {
    var gameController;
    beforeEach(function () {
        module('blackjack.game');
        inject(function ($controller) {
            gameController = $controller('GameController');
        });
    });

    it('should be true', function () {
       expect(true).toBe(true);
    });

    it('should have a start and end function', function () {
        expect(gameController.start).toBeDefined();
        expect(typeof gameController.start).toBe('function');
        expect(gameController.end).toBeDefined();
        expect(typeof gameController.end).toBe('function');
    });
});

First, our describe() function, well, describes the tests that are run in the second parameter. Everything within beforeEach() function will be executed, I hate to say this, before each test is run. Notice a pattern here? The Jasmine framework makes very readable code. Next, we’ll load our blackjack.game module with the module() function. The inject() function is where things get a bit different. Since we will be creating a controller to test, we will use the $controller service. We’ll create our ‘GameController’ within the inject function, so we have access to the $controller service we just injected. If we were to need the $controller service outside of the inject function, there is another method we could use, but that is (yet another) blog post!

Now that our gameController variable has been defined, we can run some actual tests on it. The first test:

expect(true).toBe(true);

is a good way to reveal any setup issues you may have. If the tests fail, you know you’ve done something wrong. For the next test, we will actually verify that our controller has the ‘start’ and ‘end’ functions available:

it('should have a start and end function', function () {
    expect(gameController.start).toBeDefined();
    expect(typeof gameController.start).toBe('function');
    expect(gameController.end).toBeDefined();
    expect(typeof gameController.end).toBe('function');
});

These ‘toBeDefined’ functions verify that, yes, these functions are defined on the controller. But, if there was a property called ‘start’, this would validate as true also. That is why we have the ‘typeof’ validation as well.

These tests can be run on the command line with

karma start karma.conf.js

We now have our unit testing framework setup and running a test against our first controller that we wrote. Not a bad start, especially without using any sort of generator or starter template!

One final note. I switched over to WebStorm a few months ago and I couldn’t be happier with the IDE. Coming from a Visual Studio and an XCode background, this IDE makes me feel like home. Here is WebStorm’s visualization of the tests we just wrote, pretty great right!?!

Here’s the results of our work!

Screenshot 2015-02-11 22.23.42

Angular Project Blackjack: Our First Controller

This post is part two of my “from scratch” AngularJS project. If you are feeling lost, the first post is here.

In our last post, we got our project directory setup, loading angular via bower and serving our files locally with http-server. Before we do anything else, let’s make it look somewhat decent via bootstrap. We’ll download it via bower. Then we’ll link the files in our index.html

bower install bootstrap --save

We’ll update the shell.html with with the bootstrap base template taken straight from the docs.
https://github.com/adamweeks/angular-blackjack/blob/blog-post-2/src/app/layout/shell.html

Now that we’re looking half-way decent, we’ll start by putting our game on the page. In AngularJS, our controllers are the ‘C’ to the MVC. They also can be the ‘VM’ in MVVM, depending on how you look at it. I’m a big MVC guy and since the C in MVC stands for ‘Controller’, so I’m just going to go with that. Let’s create our controller for the game, called GameController. As we go along, this will eventually contain the entire game. Since we are just getting started though, the only things our game controller will do right now is to start and end a game. Here is the meat to our controller:

function GameController(){
    var game = this;

    game.init = function () {
        game.started = false;
    };

    game.start = function () {
        game.started = true;
    };

    game.end = function () {
        game.started = false;
    };

    game.init();
}

I’m setting up this controller to always be used in a ‘controllerAs’ situation. This eliminates the need to use $scope in your controllers, and it is highly suggested by most Angular professionals. I also almost always use an init function in my controllers. I’ve found that it makes testing a bit easier when you want to see how your controller behaves with different variables. It is also good to have all your initialization code easy to find and manage. I’ve seen some controllers with variables being init-ed all over the place and it is tough to follow. Our start and end functions will be called on buttons in the view.

Let’s implement this controller on the view side.

<div ng-controller="GameController as game">
    <div ng-if="!game.started">
        <button class="btn btn-primary" ng-click="game.start()">Start Game</button>
    </div>
    <div ng-if="game.started">
        Game In Progress
        <button class="btn btn-danger" ng-click="game.end()">End Game</button>
    </div>
</div>

Our view now has two states, game started and game stopped. The ‘ng-if’ displays the proper button for each state. You’ll see we’ve wired up the buttons with ‘ng-click’ to call those functions we defined on the controller.

We’ve got our game controller being displayed and the buttons are functioning properly, so we will leave it here. Take a look at the resulting code here.

One thing to note, I would normally put this game controller into a directive and just throw the directive into shell.html, but since we haven’t discussed directives yet, we’ll leave that for another post!

AngularJS Blackjack Intro – Project Setup

About a year ago, I switched from being a full time iOS developer back to a web develox0ml8per specializing in AngularJS. Luckily, my company took a chance on me and let me learn it on the job. I have been absorbing as much Angular information as possible, trying to make sure I was at the top of my game. I found myself becoming quite skilled and even making a few small demo projects. Until, one day, I realized I didn’t really know how a lot of this worked. There was too much “magic” in the process. Sure, I could use yeoman and get an angular project building and releasing within a few hours, but I had no idea what the back end was actually doing. I felt a lot like our friend over here, not knowing some of the basics of the code. That’s why I decided to start this series of posts on creating an AngularJS project from scratch.

Most of my posts on AngularJS have been some pretty high level looks into specific topics (especially unit testing). In this series of posts, I’m going to be building a small, single-page, blackjack game in AngularJS. This will all be open sourced. We’ll be following some ground rules:

TL;DR: By the end of this post our code base should look like this: https://github.com/adamweeks/angular-blackjack/releases/tag/blog-post-1

First, let’s get the project folder going:

mkdir blackjack
cd blackjack
bower init
mkdir src src/app

Since we will be using bower, let’s configure it to install the components into our src folder so that they will be accessible from our index.html file.

.bowerrc

{
    &amp;quot;directory&amp;quot;: &amp;quot;/src/bower_components&amp;quot;
}

Next, let’s install angular:

bower install angular --save

We’ll setup our files like so:
index.html
https://github.com/adamweeks/angular-blackjack/blob/blog-post-1/src/index.html
app/blackjack.module.js
https://github.com/adamweeks/angular-blackjack/blob/blog-post-1/src/app/blackjack.module.js
app/layout/shell.html
https://github.com/adamweeks/angular-blackjack/blob/blog-post-1/src/app/layout/shell.html

As you can see, we’re already starting to use John Papa’s style guide suggestions with the blackjack.module.js filename and the layout folder. Also, the .editorconfig, .jshintrc.gitignore files are all from https://github.com/johnpapa/ng-demos/tree/master/modular

We now have our application and angular loading, so let’s load it in a browser! Oh, yea, about that. We’d really like a grunt/gulp serve solution with auto-refreshing fanciness like we get when we use yeoman to generate a project, but that’s for another blog post! We can serve from our src using a nifty node app called http-server

npm install http-server -g
cd src
http-server

And so, we’ve hit our commit. We’ve got an angular app serving text. This seems like a good stopping point. Stay tuned for more progress on our game!

AngularJS: Testing a Directive’s Controller with Isolate Scope Expressions

When writing unit tests for an AngularJS directive, there’s not a breadth of information online past the ‘basics’. This fact came to me rather quickly when I tried to write a simple unit test titled: “it(‘should call the passed function’…”. I had created a directive which accepted an isolate scope expression passed from the parent controller. Side-note: a good recap on isolate scope is found here. I finally figured it out with a little ‘controllerAs’ magic.

To follow along, open this jsfiddle!

“How did this work and what was I testing?”

This is the entire directive’s controller. My function in the directive’s controller (‘doSomething’) calls the passed expression (‘passedExpression’) from the parent controller. What I was trying to do in my test was verify that when a method in the directive’s controller was called, it was actually calling the function on the parent controller.

The Directive

So, our directive accepts the passed expression and it gets assigned to the directive’s isolate scope as  “$scope.passedExpression”. My initial thought was to simply test the MyDirectiveController without actually compiling the directive, but that doesn’t give us a full test (and would be way too easy to do!).

“Show Us the Test!”

The first test verifies that our parent scope’s variable was passed to the directive properly. The next one is what caught me. I could not figure out how to call the “doSomething()” function on the element’s controller. I tried using the ‘$controller’ injection to get to it, but the instance it created was not the same as the element’s controller. Once I started debugging, I started looking at the results of the function “element.isolateScope()“. There was a property on that scope object that was returned “myDirectiveCtrl” that I immediately found out was the directive’s controller instance! After that I could call whatever I wanted on it. With jasmine, I’m spying on my parent scope’s function to make sure it is being called.

I did see that there was an “element.controller()” function, but it never worked properly for me. If it works for you, please let me know!

“Now what?”
Go write some better unit tests! Also, write as many directives as you can! I’ve found that moving code out of my templates and into directives has really helped modularize my projects. Being able to reuse a directive is such a time (and code) saver!

Once again, this example lives on jsfiddle.

A Spaces Update (Mission Control)

I had previously blogged about how I use Mission Control Spaces in my workflow. Since my role at work has changed quite a bit (more web/less iOS) my layouts have changed a bit. It has been almost a year since I started using a ‘role based space’ setup and I’m still happy with the change.

Here’s my current setup:

  • Space 1 (Primary Monitor): Empty Space for Secondary Monitor (info)
  • Space 2 (Primary Monitor): Chrome (Gmail, General Browsing), Safari (Outlook web for work, JIRA, Stash), Spotify [GENERAL PURPOSE SPACE]
  • Space 3 (Primary Monitor): Chrome (Web Development, Karma Tests), iTerm2, WebStorm, Sublime Text [WEB DEV SPACE]
  • Space 4 (Primary Monitor): Source Tree [GIT SPACE]
  • Space 5 (Primary Monitor): XCode, iOS Simulator [iOS SPACE]
  • Space 6 (Secondary): Messages, Twitter, HipChat, Slack [COMMUNICATION SPACE]

As you can see, I’ve moved my iOS development space to the end since it so rarely gets used these days (sadface.gif) but I keep my web development space closer to the bottom of the stack. In the next few weeks, space 4 and 5 will probably get merged to keep things a bit more simple.

Maple Bourbon Bacon Almond Brittle

Maple Bourbon Bacon Brittle

Maple Bourbon Bacon Brittle

This weekend I decided to try to make an item I’d seen across instagram and pinterest, Bourbon Bacon Brittle. Now, I wouldn’t say I was a brittle expert, but I’ve probably made more batches of brittle for gifts than I’ve made any other food product (besides boxed mac and cheese!). I’d never put anything besides different kinds of nuts in the brittle though, so I wanted to give it a shot.

Let’s start with what I did and then I’ll tell you what I’m going to do next time.

Maple Bourbon Bacon process

Maple Bourbon Bacon process

Stage 1: Maple Bourbon Glaze
Ingredients:

  • 1/2 Cup Whiskey/Bourbon (I used Jack Daniels because I didn’t want to use the good stuff for the first attempt)
  • 1 Cup of Brown Sugar
  • 1/2 Maple Syrup

Steps:

  • Bring whiskey to a boil and reduce heat to a simmer
  • Simmer for around 10-15 minutes to boil alcohol off
  • Add brown sugar and syrup and mix
  • Bring mixture to a boil stirring frequently
  • Reduce to a simmer and test every 5-10 minutes for consistency
  • Once it reaches a syrup like consistency, it is ready
  • Leave it on very low heat to make it easier to brush on
GLAZED BACON!

GLAZED BACON!

Stage 2: BACON!

Ingredients:

  • All the bacon. 1 pound of it should use that amount of glaze (I used thick cut, but won’t next time)

Steps:

  • Preheat oven to 400 degrees F
  • Line a cookie sheet with foil
  • Place baking rack on cookie sheet
  • Spray pan and rack with cooking spray
  • Put as much bacon on the rack as you can get
  • Brush top of bacon with glaze from stage 1
  • Bake for 13 minutes in middle/top of oven to keep from burning
  • Take the tray out and flip bacon on the rack. Brush bacon with glaze again.
  • Bake for additional 13 minutes
  • Inspect bacon for done-ness. It will crisp up some after you take it out.
  • (At this point I re-glazed and re-baked both sides for another 2 mins because the thick cut bacon wasn’t quite done. Plus, bonus, more bourbon glaze!)
  • Remove from oven and let it cool (it will cool quicker on a different rack if you have a spare

Final Stage (3): Brittle!

Brittle cooling

Brittle cooling (Definitely not puke)

Ingredients:

  • 1 cup white sugar
  • 1/2 cup corn syrup
  • 1/8 tsp salt
  • 1 cup almonds
  • 2 tbsp butter
  • 1 tsp baking soda
  • 2 tsp vanilla
  • 2-3 slices of bacon chopped up
  • Candy Thermometer

Steps:

  • Get everything measured and prepared. Once the temp hits the sweet spot, you’ll be running around like crazy otherwise.
  • Spray a cookie sheet with cooking spray (or, if you’re like me, just use a silicone mat. That thing is truly magical!)
  • Mix sugar & corn syrup in pot and cook over medium heat.
  • Constantly stir mixture until it starts boiling then don’t touch it until it reaches 310 degrees.
  • Once it reaches 310, stir in almonds and bacon and cook 2 more minutes.
  • Mix vanilla, butter, salt, and baking soda in and stir quickly. (It will get all foamy due to the soda, but that is expected)
  • Once mixed, spread quickly onto pan and let cool.
  • Once completely cooled, break into pieces and store in a cool area (if you can manage to not eat the entire batch)

For Next Time:

Like I said above, I won’t get the thick cut bacon next time. It took longer to cook and the pieces were a bit chewy in the brittle. It was still delicious but I think having it be crunchy will make it even better.

I also put the bacon in the brittle with the almonds. I believe this basically wiped out a lot of my glaze that was on the bacon. Next time, I’ll wait until the very end (after the vanilla, butter and baking soda addition) so that the bacon retains as much glaze as possible.

AngularJS Directive’s ‘Restrict’ Real World Guide

While trying to wrangle custom directives in AngularJS, I’ve found the restrict property a bit tough to understand even after reading the guide:

The restrict option is typically set to:

  • 'A' – only matches attribute name
  • 'E' – only matches element name
  • 'C' – only matches class name

These restrictions can all be combined as needed:

  • 'AEC' – matches either attribute or element or class name

Here’s a real world example of each one in use. For these examples, we’ll define our directive as:

directive('exampleDirective', function(){
    return {
        restrict: 'A',
        template: 'This is an example directive',
    }
});

Also notice that even though our directive is named ‘exampleDirective’, Angular converts it to ‘example-directive’ when compiling the html.