A simple jQuery Qunit-based JavaScript Unit Test Project Template

UPDATE: I just updated the template. You can download it here.

Next week, I’m giving a talk on JavaScript Unit Testing at Codestock. I think this is my 5th year. Always a great show and am looking forward to seeing everyone in Knoxville, TN. The talk is going to be divided into 3 parts: 1 – recognizing and implementing testable JavaScript code, 2 – JavaScript Unit Testing fundamentals and 3 – Visual Studio integration. It is the 3rd part that I want to discuss right now. I’ve just uploaded a new JavaScript unit test project template to the Visual Studio Gallery.

js_testing_icon

There is a need for a simple unit test project that is devoted to JavaScript unit testing. For this template, I chose the jQuery QUnit project. To make full use of the template, you will also need the Chutzpah JavaScript Unit Test Runner installed. Chutzpah integrates your JavaScript Unit tests.

Once the extension is installed, the add-in will be available:

(Yes, I know the project type reads as Visual C#… When I created the template, I decided to start with a class library project – like any other unit test project. I could have hosted this in a Windows Store JavaScript project – but that would have left folks out that have not upgraded to Windows 8 yet. )

image0

To get up and running, I added a simple Hello World QUnit JavaScript unit test. The following example shows the template in action:

Consider the following solution structure:

image1

This solution has 3 projects: ASP.NET MVC, MVC Unit Test and a JavaScript Unit Test Project. To illustrate how to put your web project’s js code under test, I created a myFunctionTests.js file -  which corresponds to the myFunctions.js file in the UnitTesting.Web MVC Project. Here is the code for myFunction.js:

var myFunctions = (function () {
    var _functions = {};

    _functions.add = function (items) {
        var total = 0;
        for (var i in items)
        {
            total += items[i];
        }
        return total;
    };

    return _functions;
}());

A very simple function that takes an array of numbers and adds them together. Here’s the test in the JavaScript Unit Test Project:
(Take note of how to reference the js file that hosts the function under test.)

/// <reference path="../../../unittesting.web/scripts/myfunctions.js" />

test("My Function Add Test", function () {
    var result = myFunctions.add([1, 2, 3]);
    var expected = 6;

    ok(result == expected, "Result: " + result  + ", expected: " + expected);
});

In addition, there is also a standard unit test project which was added when the MVC project was created. The following figure shows the Visual Studio Test Explorer running all of our tests (in my Test Explorer settings, I’ve opted to organize the tests by project):

image2

If I was to alter the test by changing the expected value to 5 and saved the file, the affected tests will run again. The following figure shows our unit test in a failed state:

image3

 

Enjoy!!

Posted in Javascript, jQuery, QUnit, Unit Testing | Tagged , , , | Leave a comment

Pre-Process your images with promises

For this post, I’m using Windows 8 WinJS as the vehicle. However, this approach is applicable by any method that implements an XMLHttpRequest.

Here’s the scenario: you have an application with several images and those images are stored on a remote server. The sources of each image is something like http://someserver.com/myimage.png.

Looking at a Windows 8 store app as an example, the good news is that your page will display immediately. Your images may display immediately. Or more likely, they will begin to display after the page has loaded. You may see the images incrementally appearing. This does not make for a good user experience.

The good news is that WinJS implements the Promise Pattern and XMLHttpRequest via the WinJS.xhr object. This means we can pre-fetch images and resolve them to blob URL’s and then bind our UI to the blob URL instead of the raw image url.

Using a stock WinJS Navigation Project, the following code is placed in the app.addEventListener(“activated”, function (args) {} handler:

var promises = [];

//Load the blob for the default image in the event a specified image URL does not work.
WinJS.xhr({ url: "images/no-available-image.png", responseType: "blob" }).done(function 
(data) {
 var noImageBlob = URL.createObjectURL(data.response);
  //The imageResults.json file is a static result from the Bing Images API.
  WinJS.xhr({ url: "js/imageResults.json" }).done(function (data) {
     var results = JSON.parse(data.responseText);
     //Loop through the results to create the promise array.
     results.d.results[0].Image.forEach(function (element, index, array) {
     promises[index] = WinJS.xhr({ url: element.MediaUrl, responseType: "blob" })
        .then(function (e) {
           //When the promise executes, an imageBlob property is created
           //holding the image blob URL
           results.d.results[0].Image[index].imageBlob = URL.createObjectURL(e.response);
        }, function error(e) {
           //If an error occurs when trying to retrieve the image
           //the No Image BLob URL created on line 28 is used instead
           results.d.results[0].Image[index].imageBlob = noImageBlob;
        });
     });
     //The join method kicks off the promises handed to it.
     //The promises can run in any order and finish at any time. 
     //The done event for the join method fires after all of the promises
     //in the promise array have been fulfilled.
     WinJS.Promise.join(promises).done(function (e) {
        //Need to create a global namespace to hold a reference
        //to the images array. To facilitate data binding, 
        //the WinJS.BindingList method is invoked, passing the 
        //image array.
        WinJS.Namespace.define("ImageList",
           {
              Images: new WinJS.Binding.List(results.d.results[0].Image)
           });;
           //Now that all of the pre-processing has occurred, we can now
           //navigate to the home page that displays the images.
           if (app.sessionState.history) {
              nav.history = app.sessionState.history;
           }
           args.setPromise(WinJS.UI.processAll().then(function () {
              if (nav.location) {
                 nav.history.current.initialPlaceholder = true;
               return nav.navigate(nav.location, nav.state);
           }
           else {
                return nav.navigate(Application.navigator.home);
           }
        }));
     });
  });
);

JavasScript, being a dynamic language, we can simply augment the object from the parsed JSON. In this example, I used a static file from the Bing Image Search API. You will have to conform the object references to the specific API you are working with. In the previous code, we wait until all of the images have been fetch. In an async world, this can be a challenge. We don’t know what order the requests will be processed. In some cases, a server status 500 could result. This approach affords us an opportunity to handle that error with a place holder image. If on the other hand, you deal with the raw URL’s directly, you have no such opportunity to intercept errors.

On the HTML markup side, I have this code to bind an image tag’s src to the newly created imageBlob property. For this example, the raw URL that is returned in the response is MediaUrl.

<section aria-label="Main content" role="main">
   <div id="ImagesTemplate" data-win-control="WinJS.Binding.Template">
      <div style="width: 150px; height: 100px;">
          <img src="#" style="width: 60px; height: 60px;" 
              data-win-bind="alt: MediaUrl; src: imageBlob" />
      <div>
       <h4 data-win-bind="innerText: MediaUrl"></h4>
      </div>
   </div>
</section>
<div id="ImageListView" 
   data-win-control="WinJS.UI.ListView"  
   data-win-options="{itemDataSource : ImageList.Images.dataSource, 
                      itemTemplate: select('#ImagesTemplate')}">
</div>

In the markup, I have a WinJS ListView control that uses the ImageList.Images.dataSource as its datasource. The ListView also references a simple template to display the output.

Here is the result (looks a bit skewed due to this page’s dimensions):

images

When the page displays, because the images have already been pre-fetched, they will immediately display as well. This makes for a more pleasant user experience.

Looking at the first image, it has a raw URL of:

http://www.israbox.com/uploads/posts/2011-04/1303738133_john-coltrane.jpg

When pre-fetched, the blob URL is:

blob:354BAAC6-B8D8-4172-A283-4DF2F037FECD

Posted in Windows 8, WinJS | Tagged | Leave a comment

DongleGate: A Legal Perspective and some social commentary

Those of you that know me, know that I’m both a software developer and a lawyer. I’ve not commented on the #DongleGate issue – except to say that this issue has privacy, first amendment and civil litigation ramifications. Those of us witnessing this escapade have seen at least 1 guy lose his job and this just in, the complainant Adria Richards (http://butyoureagirl.com/) has lost her job as a developer evangelist for SendGrid. Here’s the blog post from her former employer: http://blog.sendgrid.com/a-difficult-situation/.

One thing we can agree on, there is a massive lack of maturity in this business. At one time or another, including yours truly, has been guilty of an off-color joke. Most of the times, at community gatherings like conferences; we are typically amongst friends and feel comfortable that we can be ourselves, letting our guard down. At the end of the day, we must rely on the fact that in this business, we have to have a thick skin and that we are adults. That in no way is meant to justify offensive comments and that somebody like Adria didn’t have a right to be offended. She did have a right to be offended. And to that, it’s not for anybody else to question it. It’s enough for anybody to say they were offended – and others should respect that. That said, does it mean the offended have an open ended license to exact whatever retribution they want on the offenders? No…. In these community gatherings, there is a level of privacy, within the community cocoon; we have a reasonable expectation to.

We see the t-shirt shirt = “Fork you”. We see on open source projects: “Fork me on GitHub”. Doesn’t take a rocket scientist to see the double entendre here. If one is to where that shirt in public, does that give anybody who is offended license to snap a picture, tweet it, and then hope that some misfortune befalls that person? I don’t think such license is granted.

Consider this YouTube video from Ms. Richard’s: http://www.youtube.com/watch?v=nMpJSKbsmgQ. There’s a saying in the law that in matters of equity, you have to have “Clean Hands.” Is it permissible for her to be offended as she was when she makes a video that could be taken as offensive by others? At about 3:03 into the video, she talks about an incident that was done to her – that could very well be taken as offensive, and she let it pass. In this case, she decided to not let something pass…something that WAS NOT said directly to her. If I was prosecuting this case, and I was going to depose Ms. Richards, this is a line of questioning I would surly explore to great details. What was her real motivation here?

This gets to my first question:

Was there a reasonable expectation of privacy by these two gentlemen?

I believe there was. They were having a private conversation, which Ms. Richards overheard. Yes, this was a public place. Did she have the right to express her indignation at those comments to these two gentlemen? Absolutely yes. In fact, that would have been the more impactful thing to do. That would be a proportional response. Reporting the incident to the PyCon staff is not appropriate. They are not there to police what people say. Note, these two guys didn’t say the comment to her. She thrust herself into their conversation. By the same token, the two guys allowed her to confront them. She didn’t. Instead, she took their picture and posted a tweet. And from there, SHE took what was a private thing and made it public. She made the situation worse. In that regard, she violated the privacy rights of these two men, notwithstanding their comments. Speaking of those comments, only her, the two guys and maybe one or two others know what the precise words were. The first result, at least one of the guys lost his job.

Next question..
Does the guy who got fired have a cause of action against Ms. Richards?

This is the part you want to pay attention to as you should think very carefully about the consequences of tweeting something that is private and further, identifying specific people where harm could come to them. First, did these two guys have a right to say what they said, no matter how stupid it was? Yes, they had a right. There is such a thing as a First Amendment last I checked. It’s also not illegal to be stupid. Did the guy who got fired, his employer, have a right to fire him? If he works in an employment at-will state, the answer is yes. Is he totally out of luck? No.. He can sue Ms. Richards for Tortious Interference with an Employment Relationship. She knew and intended a certain level of a negative outcome to these two gentlemen. That’s malice. While his employer may be on good ground to fire him, he can nevertheless sue Ms. Richards to recover damages. There may also be a cause of action on defamation grounds. These two guys are being labeled as sexists when all that may have happened was a joke, off color as it may have been, that offended this one person. That too may be the basis of a cause of action.

Next question..
Is there any other entity that could be liable?

As SendGrid has already admitted, Ms. Richard’s was there in her capacity as a representative as a SendGrid Employee. Ms. Richard’s did not do SendGrid any favors when she tweeted that she had SendGrid’s full support – a claim that SendGrid didn’t dispute. In the law, there is the legal doctrine of “Respondeat Superior.” It effectively means that the master is liable for the actions of his agent. Ms. Richards has a large Twitter following and that is due in least in part to her former job as a developer evangelist for SendGrid. There’s a strong argument to be made that SendGrid is liable, at least in part, for Ms. Richard’s actions – regardless of the fact that they terminated her services.

This whole episode illustrates again the importance of how we react emotionally and the legal consequences therein. If I’m the gentlemen who lost his job, I’m exploring my legal options – and there are legal options. Above all, this is a teachable moment. If you are offended at something somebody does, consider the context. 99.99% of the time, these matters are best handled privately. Takes more courage and is more impactful when you communicate your disdain to the offending party directly. If your goal is to change behavior that will more likely have the desired effect. Sure, you may be told to eff-off. That’s a risk…a risk worth taking.

How about conference organizers?

I understand that PyCon has modified their code of condut… Didn’t know that such a thing existed. I would always suggest to any conference organizer to NOT get into the business of policing their attendees. Rather, I’d rely on the venue staff for that. Obviously, if somebody is disruptive, boot their tails out. These guys didn’t appear to be disruptive at all for the record – not that it really matters in this case.

A word about the “Brogrammer” culture..

You probably know about it. If not, look it up on our favorite search engine. The fact is, guys are often not the sharpest knives in the drawer socially and are often in need of an increase in maturity level. Women have a tough enough time in this business. I know several women that do a lot of work in getting more girls interested in software development. Sad as it is, Adria Richards did more to set that effort back than the two guys she was offended by. That’s a perfect example of irony!! It’s really a shame. Ms. Richards looks to be a pretty sharp individual – one who appears to have better common sense than she displayed here. Learn from it folks.

Posted in Uncategorized | Tagged , | 54 Comments

Memo to Microsoft – If you want Windows 8 to succeed, among other things, get apps in the store that people want

Let me first say I like Windows 8. As on OS, it performs well. I like the way the OS is essentially a first class citizen with the development environment. The consistency across apps, as to sharing, searching, etc. – is a good thing. The WinRT device – very slick. Great battery life. For browsing and cranking out business documents, not a bad device. Some of the native apps – especially email – need to be way better.

BUT……

Where are the apps? Granted, Words with Friends is finally in store. The new ESPN App is nice. But what about Taxi Magic and Pandora? How about a better FaceBook and Twitter app? Instagram? I was just at an event where somebody was showing Vine – a really cool iOS app. I looked for it on the Windows App Store…. :-( How about Instapaper???

I’ve taken the plunge to give the Windows Phone a fair shake. I love the UI. What is needed are apps…apps people want – which will drive the platform. Whether Microsoft wants to admit it, the Apple AppStore is the store by which the Windows Store is measured. There’s A LOT of noise on the Windows Store. Note – quantity is not quality. If there is a top app in iOS, Windows needs to have that app. Microsoft needs to be focused on those vendors to get these apps built.

Another nit is the difference between Windows 8 and Windows Phone. It would be great if those two worlds could come closer together from a development standpoint. On the plus side, the process by which apps are certified for the store is simple. The Windows App Certification Kit is a nice utility and easy to use. If your app fails, there is clear guidance on what to fix.

None of this is to say there are not useful apps on the Windows/Windows Phone Stores – there are. And when it comes to things like Live Tiles, Microsoft nailed that one. A very useful feature – which makes the negative things especially frustrating to deal with.

At the end of the day, like many, I want to see Windows 8 succeed. I think and believe there to be a great amount of potential. But to succeed, the public needs to see the apps that are available in other ecosystems. Until that day comes, Windows 8, and in particular Windows Phone, will continue to be third in a 3 horse race – which shouldn’t be the case.

Posted in Windows 8 | 4 Comments

Windows 8: Be a good sharing citizen

Note: Code samples are WinJS

I’ve been working with Windows 8 and building Windows Store Apps more and more. Building native Windows Apps with HTML/JS/CSS is, in a word, awesome. I’ve mentioned before how the OS is a first class citizen in the development space. Having standard API’s in the dev environment to handle common tasks like searching and sharing is another nice feature in Windows 8 Development. I wanted to take a quick moment to talk about the sharing contract. You can download a full working example of how to implement the sharing contract here.

This example does a great job of dealing with situations where you can and want to share. But what about times when sharing is not appropriate? A good user experience means the user not having to guess as to whether encountered functionality is intended or a bug. By default, when the share contract is not implemented you get a pretty blunt message back: “This app can’t share.”

cantShare

Looks pretty, but it’s not all that informative.  Fortunately, it’s very simple to provide your users with enough information so they know what they see is what you, as the app developer intended. The following code is a basic and typical share contract data request function:

  function dataRequested(e) {
        var request = e.request;

        // Title is required
        var dataPackageTitle = document.querySelector("article .item-title").textContent
        if ((typeof dataPackageTitle === "string") && (dataPackageTitle !== "")) {
            var dataPackageText = document.querySelector("article .item-content").innerHTML
            if ((typeof dataPackageText === "string") && (dataPackageText !== "")) {
                request.data.properties.title = dataPackageTitle;
                request.data.setText(dataPackageText);
            } else {
                request.failWithDisplayText("A problem occurred with this sharing request");
            }
        } else {
            request.failWithDisplayText("A problem occurred with this sharing request");
        }
    }

This still doesn’t do everything we need. For example, using the Grid Template as an example, this code would only work on the item detail page. If you happen to invoke the Share Contract from the Group Items or Group Details page, you will either get an error or the necessary data won’t be found. In most cases, it’s an individual item you are looking to share.  With that in mind, consider adding code like this to your common share data request function:

if (WinJS.Navigation.history.current.location != "/pages/itemDetail/itemDetail.html") {
   request.failWithDisplayText("Please note, you must navigate to an individual item in order to share.");
   return;
}

Now, when the user wants to share something in a context that does not account for that functionality, the user will know two things:
1. It’s not intended to be used in this context and;
2. The user knows where the sharing context is

This yields much better results:

cantShareGridDemo

canShareItem

canShareItem2

Posted in Windows 8, WinJS | 2 Comments