The AngularJS team created Karma, but Karma isn’t tied to AngularJS. As a test runner, I can use Karma to run tests against any JavaScript code using a variety of testing frameworks in a variety of browsers. All I need is Node.js.
Pretend I am writing code to represent a point in two dimensional space. I might create a file point.js.
var Point = function(x,y) { this.x = x; this.y = y; }
I’ll test the code using specifications in a file named pointSpecs.js.
describe("a point", function() { it("initializes with x and y", function() { var p1 = new Point(3,5); expect(p1.x).toBe(3); expect(p1.y).toBe(5); }); });
What Karma can do is:
- Provide web browsers with all of the HTML and JavaScript required to run the tests I’ve written.
- Automate web browsers to execute all the tests
- Tell me if the tests are passing or failing
- Monitor the file system to re-execute tests whenever a file changes.
The first step is using npm to install the Karma command line interface globally, so I can run Karma from anywhere.
npm install karma-cli –g
Then I can install Karma locally in the root of my project where the Point code resides.
npm install karma --save-dev
Karma requires a configuration file so it knows what browsers to automate, and which files I’ve authored that I need Karma to load into the browser. The easiest way to create a basic configuration file is to run karma init from the command line. The init command will walk you through a series of questions to create the karma.conf.js file. Here is a sample session.
>karma init Which testing framework do you want to use ? Press tab to list possible options. Enter to move to the next question. > jasmine Do you want to use Require.js ? This will add Require.js plugin. Press tab to list possible options. Enter to move to the next question. > no Do you want to capture any browsers automatically ? Press tab to list possible options. Enter empty string to move to the next question. > PhantomJS > Chrome > What is the location of your source and test files ? You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js". Enter empty string to move to the next question. > js/**/*.js > specs/**/*.js > Should any of the files included by the previous patterns be excluded ? You can use glob patterns, eg. "**/*.swp". Enter empty string to move to the next question. > Do you want Karma to watch all the files and run the tests on change ? Press tab to list possible options. > yes Config file generated at "C:\temp\testjs\karma.conf.js".
I can open the config file to tweak settings and maintain the configuration in the future. The code is simple.
module.exports = function(config) { config.set({ basePath: '', frameworks: ['jasmine'], files: [ 'js/**/*.js', 'specs/**/*.js' ], exclude: [ ], preprocessors: { }, reporters: ['progress'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['PhantomJS', 'Chrome'], singleRun: false }); };
Note that when I enter the location of the source and test files, I want to enter the location of the source files first. It’s helpful if you can organize source and test files into a directory structure so you can use globbing (**) patterns, but sometimes you need to explicitly name individual files to control the order of loading.
At this point I can start Karma, and the tests will execute in two browsers (Chrome, which I can see, and PhantomJS, which is headless). I’d probably tweak the config file to only use Phantom in the future.
Now, Karma will continuously run tests in the background while I work.
Easy!
A rest parameter allows a function to work with an unknown or variable number of arguments. A function’s rest parameter always appears at the end of the function’s argument list and uses a triple dot prefix (...), as shown below.
let doWork = function(name, ...numbers){ let result = 0; numbers.forEach(function(n){ result += n; }); return result; };
A caller invoking doWork can pass zero or more parameters at the rest parameter position. You can say the numbers argument will take “the rest” of the parameters a caller passes, and numbers will hold the parameter values in an array. In the following example, numbers will reference an array with the values 1, 2, 3.
let result = doWork("Scott", 1, 2, 3); expect(result).toBe(6);
In the case where a caller passes no parameters in the rest parameter position, the rest parameter will be an empty array.
let doWork = function(...numbers){ return numbers; }; let result = doWork(); expect(result.length).toBe(0);
Before ES6, we could allow callers to pass a variable number of arguments to a function by using the implicit arguments variable inside of the function. The arguments variable contains all the parameters to a function in an array-like object, but arguments is not an array, which creates confusion. It is also difficult to spot if a function is using arguments without reading through the code or documentation for the function.
ES6 rest parameters will avoid the confusion by always giving us a true array, and by using a dedicated syntax that makes rest parameters easy to spot when reading the function signature.
Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!
Primary constructors are a feature you’ll find in a few programming languages, including F#, Scala, and Kotlin. A primary constructor allows us to define a constructor for a type and capture the constructor parameters to use in initialization expressions throughout the rest of the type definition. Here’s one simple example:
public struct Money(string currency, decimal amount) { public string Currency { get; } = currency; public decimal Amount { get; } = amount; }
Notice how the primary constructor arguments appear inside parentheses just after the type name. The code can then use the arguments in field initializers and property initializers. Common questions about this new syntax revolve around parameter validation, and how primary constructors can work with other explicit constructors. Here’s another example.
public class AddUserCommand(User newUser, User creator) : Command { public AddUserCommand(User newUser) : this(newUser, creator: newUser) { } public User NewUser { get; protected set; } = newUser; public User Creator { get; protected set; } = Verify.NotNull("creator", creator); Guid _creatorId = creator.Id; }
Once you have a primary constructor, all other constructors must ultimately call into the primary ctor using this(), which makes sense since we always want the primary constructor arguments to be available for initialization (although a struct will still have a non-replaceable default constructor that will initialize all members to default values).
Validation is a bit trickier, but simple validation checks are possible in the initialization expressions.
I really like the primary constructor syntax for components that are managed by an IoC container. Typically these components have a single constructor to accept dependencies, and they need to store the dependencies in a field or property. Validation of the dependencies is not a concern as most containers will (or can) raise an error if a dependency cannot be found.
public class UserController(IUserStorage storage) : Controller { public ActionResult Index() { // ... } IUserStorage _storage = storage; }
The primary constructor syntax means there is a little less code to write for these types of components.
If a JavaScript function takes two parameters, we have always had the ability to invoke the function and pass two parameters, or one parameter, or no parameters, or three parameters if we wanted. In cases where we do not pass enough parameters, the author of a function might want to specify a default value instead of working with undefined.
Before ES6, developers applied default values to simple parameters using || expressions inside the function.
let doWork = function(name) { name = name || "Scott"; return name; };
With ES6, default parameters are explicit and appear in the argument list for a function.
let doWork = function(name = "Scott") { return name; }; expect(doWork()).toBe("Scott");
A function can even calculate a default using something more than just a literal expression.
let doWork = function(x = Math.random()) { return x; }
The default parameter syntax is a good example of how ES6 is providing a clean syntax for a common requirement. No longer will we have to scan through a function implementation or documentation to discover the defaults.
Of course, not all parameters are simple values. A common programming technique for operations involving complex configurations, like an HTTP call, is to accept a single object argument and use some sort of extend API to merge the incoming configuration with configuration defaults (jQuery.extend or angular.extend, as two examples). Default parameters are useful in this scenario, too, but we’ll have to learn about object destructuring in an upcoming post, first.
Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!
I’ve been a bit late to the Angular controller as syntax. I was skeptical of the feature at first, and with an Angular project already in flight, I felt it wasn’t the type of change to make with a significant amount of code already committed.
The controller as syntax allows me to alias a controller in markup.
<div ng-controller="MainController as main"> {{ main.title }} </div>
Then instead of injecting a $scope into the controller, model data and behavior is added to the controller instance itself.
app.controller("MainController", function(){ this.title = “Hello!”; });
Behind the scenes the controller as syntax adds the controller alias (main in the above example) to a scope object, because Angular still evaluates all binding expressions against a scope object.
Here’s what I think about controller as now.
- Using the controller alias in a view is a push into the pit of success. View code is more explicit and easier to maintain. Even when using $scope in a controller, I’ve come to view any reliance on prototypal inheritance in the scope chain with suspicion, as the inheritance is brittle, subtle, and often complicates both controller and test code. With a controller alias there is no reliance on scope inheritance hierarchies.
- Not having to inject a $scope makes test code slightly easier.
- Having no access to the $scope API inside a controller is a good thing. I’ve come to view any use of $scope.$watch, $scope.$emit, $scope.$on, and $scope.$* in general with suspicion, at least when inside the controller code for a view. Nearly all the functionality available through the $scope API is better used inside of directives or services that provide a better abstraction.
- Thinking of the controller as a true constructor function instead of a function that adds stuff to $scope is healthier. You can take advantage of the constructor function prototype property to organize code, and this will work well with ES6 class definitions (which presumably will work well with ng 2.0).
- Writing directive controllers is different than writing view controllers. With directive controllers the instance members are often used as an API for intra-controller coordination, and this API should be separate from the model for the view.
- Somewhat related to the above, I’m still not convinced that tangling the controller and view model together is a good idea. I think there is some value in having a dedicated factory for view models.
The good appears to outweigh the bad, so I’ll switch over to using controller as syntax moving forward. I don’t think controller as is a panacea for complicated$scope code, but it does push people in a better direction.
I also think controller as highlights the need for Angular 2.0 to make some huge, breaking changes. Once of Angular’s greatest strengths, for me, is that the framework provides enough flexibility to build a variety of apps both large and small. Routing is optional, for example, and most programming can be done with plain old JavaScript objects. However, the surface area of the framework is dangerously close to being a Mirkwood forest of programming techniques. A streamlined API with stronger opinions about how to tie components together would make the framework easier to use.
The ES6 const keyword will give you what the keyword name implies – a read-only variable. Like let, a variable declared with const will have block scoping, and you cannot re-declare a const.
const MAX_BUNNIES = 3;
There is no requirement for a constant variable to use capital letters, that’s just a convention I like to follow.
In a perfect world, all the JS runtimes would have a perfect implementation of const. Unfortunately, const is one of those keywords that has been around in some runtimes even before the keyword appeared in an official ECMAScript specification.
While most runtimes can agree that a const should be constant, existing implementations disagree on how to behave when code attempts to assign a new value to a constant. Should the assignment cause a runtime error? Should the assignment fail silently?
The ES6 specification says const should fail with a runtime error if a program tries to assign a new value to a constant, and constant declarations without an initializer should be a syntax error.
const MAX_SIZE = 10; MAX_SIZE = 12; //SyntaxError
I hope that it won’t take long for all the latest runtimes and browsers to straighten up and behave correctly. The current situation shouldn’t stop you from using const whenever possible because the keyword does have a few benefits.
1. const tells other programmers about the intended behavior of a variable, and this makes code easier to read.
2. const tells the runtime about the intended behavior of a variable, which can allow for small optimizations across time and space.
Coming up next: default parameters.
Want more? Watch JavaScript Fundamentals for ES6 on Pluralsight!
With a new release of the C# language approaching, it’s also time to look at new features for C#.
First up is the ability to use an initialization expression with an automatically implemented property.
Currently, a constructor is required if you want to create objects using an auto-property and initialize an auto-property to a non-default value.
In C# 6.0, the ability to use an initializer with the auto-property means no explicit constructor code is required.
public class User { public Guid Id { get; } = Guid.NewGuid(); // ... }
Another benefit of the syntax is how an initialized auto-property only requires a getter, the set method is optional. With no setter, immutability is easier to achieve.
The property initialization syntax also plays well with another new feature for C# 6, the primary constructor syntax. We’ll look at primary constructors in the next post for this series.