4elements, Amsterdam, Holland

  1. JavaScript Tools of the Trade: JSBin

    We’ve all been there. There are times when you simply want to throw some JavaScript code up and see how it works. Sure, you could go through the hassle of:

    • Setting up a dedicated directory
    • Create a file with markup
    • Finding the latest version of your favorite libraries, downloading them and including them in your code
    • Creating your stylesheet
    • Configuring your webserver

    That seems like an awful lot of work just do do some simple code testing. Thankfully there are tools that make this type of work trivial.

    In this tutorial, I’d like to go over one of my favorite tools for interactive JavaScript testing, JSBin.


    The Case for JSBin

    As I mentioned previously, in many cases you simply need to test a small subset of JavaScript code. Setting up a whole development environment for such a use case, in most cases, doesn’t really make a lot of sense unless there’s a clear dependency on hardware (for example, WebRTC) or reliance on a third party API or product where you need backend services to successfully access information.

    What JSBin offers is a browser-based user interface where you can enter:

    • HTML markup
    • CSS
    • JavaScript

    … and get immediate feedback based on your code. In addition, you can optionally include any number of popular frameworks into your onscreen code, allowing you to leverage the framework’s capabilities as well. The main benefit is the real-time feedback you get from the updates you make.

    Let’s look at these tools a little more closely.


    Getting to Know JSBin

    JSBin was created and is actively maintained by well-respected developer Remy Sharp. The idea to develop it came from the need to collaborate interactively with other developers to debug JavaScript code. It has since matured into a robust tool which:

    • Allows groups of developers to work together to solve code problems
    • Serves as a sort of bin that developers can go back to reference
    • Makes sharing code and solutions incredibly easy

    JSBin is also opensource licensed under the liberal MIT license allowing community members to freely contribute to it or fork it to create their own customized solutions.

    JSBin offers a straightforward UI that breaks each type of code into individual vertical panels.

    jsbin

    Each panel provides a mini-IDE that allows you to enter code and receive immediate feedback via the Output panel. For example, if I add the following code to the HTML panel:

    <div>Rey Bango</div>

    I’ll immediately see the new element and the text render in the Output panel.

    jsbin-html

    Of course, you can add any number of elements to the markup allowing you to create a page quickly and interactively. Being able to style your markup is equally important since in some cases, the JavaScript you’re testing is explicitly designed to manipulate styles and CSS rules applied to your elements. That’s where the CSS panel comes in. It offers full CSS style capability, so you can layout your elements to suit your needs, even taking advantage of CSS3 rules. So adding the following code:

    div { 
      color: red; 
      font:20px Tahoma,sans-serif; 
      border: 1px solid black; 
      width: 100px;
      margin: 30px;
      padding: 10px; 
      transform:rotate(15deg);
      -webkit-transform:rotate(15deg); 
    }

    … provides the following results:

    jsbin-css

    So far, the code has been simple but I need to stress that the important thing here is not the complexity of the code but the fact that you’re able to receive immediate feedback. I could easily grab more involved code, like that of the CSS Transitions demo on the Mozilla Developer Network and add that into JSBin to produce a similar effect for my test code:

    div { 
      color: red; 
      font:20px Tahoma,sans-serif; 
      border: 1px solid black; 
      width: 100px;
      margin: 30px;
      padding: 10px; 
      -moz-transition:width 2s, height 2s, background-color 2s, -moz-transform 2s;
        -webkit-transition:width 2s, height 2s, background-color 2s, -webkit-transform 2s;
        -o-transition:width 2s, height 2s, background-color 2s, -o-transform 2s;
        transition:width 2s, height 2s, background-color 2s, transform 2s;
    }
    
    div:hover {
        background-color: #FFCCCC;
        width:200px;
        height:200px;
        -moz-transform:rotate(180deg);
        -webkit-transform:rotate(180deg);
        -o-transform:rotate(180deg);
        transform:rotate(180deg);
    }
    
    jsbin-csstrans

    So while I’m more specifically focused on the JavaScript aspect of JSBin, it’s clear that web developers in general can benefit from the interactive nature of the tool.


    Using JavaScript

    For me, the main benefit of JSBin is the ability to test JavaScript quickly. I’m able to whip up quick and dirty code that I can test and adjust on-the-fly without the need to spin up a whole work environment. Sure, most browsers provide developer tools that offer a console where you can enter quick snippets but they’re not yet at a point where you can interactively test large amounts of code, let alone define complementary custom markup and styling to the output.

    JSBin’s JavaScript panel is where you’re able to define your custom JavaScript code. As expected, you have full access to the language as well as the DOM API supported by the browser. This means that when I write:

    var myDiv = document.querySelector( "div" );
    
    myDiv.innerHTML = "Foo";
    

    it:

    • Allows me to create a local variable
    • Provides access to the div element I created in the HTML panel
    • Changes the element’s content

    The results are immediate, allowing me to debug as I’m writing the code.

    Having access to plain ole JavaScript is great but it’s very common to use a JavaScript utility library like jQuery or a full-blown framework like Ember to abstract the complexities of cross-browser development or create app-like experiences in the browser. JSBin addresses this by allowing you to include most of the popular libraries into your test code.

    Clicking on the Add library menu option provides a very long list of supported libraries that can be injected into your JSBin project. What this does is creates a script tag in your code that pulls the JavaScript file from a CDN. Selecting “jQuery 2.0.2” from the list injects the following:

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
    <meta charset=utf-8 />
    

    … while selecting Backbone adds the following:

    <script src="http://documentcloud.github.io/underscore/underscore-min.js"></script>
    <script src="http://documentcloud.github.io/backbone/backbone-min.js"></script>
    

    Notice how JSBin uses different CDNs based on where the files are available. Most of the big name projects are listed, including:

    • jQuery
    • Dojo
    • Modernizr
    • Bootstrap

    … and many more.

    Adding in jQuery gives me full access to all of the libraries’ excellent helper methods and capabilities. I can switch to using its nice, terse API to access DOM elements and set values in one nicely-chained line of code:

    $( "div" ).text( "Foo" );

    Or, I can take it a bit further and test out an Ajax request to Flickr’s API to pull back JSON data and render images based on it:

    (function() {
      var flickerAPI = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?";
      $.getJSON( flickerAPI, {
        tags: "mount rainier",
        tagmode: "any",
        format: "json"
      })
        .done(function( data ) {
          $.each( data.items, function( i, item ) {
            $( "<img>" ).attr( "src", item.media.m ).appendTo( "div" );
            if ( i === 3 ) {
              return false;
            }
          });
        });
    })();
    

    The code above would render as follows:

    jsbin-ajax

    Having the full power of these libraries and frameworks really opens up the testing scenarios that you can setup with JSBin.

    Again, this is a list of the most popular libraries and frameworks available and clearly, some niche ones just won’t be in the list. If you need to add your own custom library, the documentation shows how you can add it in yourself.


    Additional Features and Resources

    I find JSBin invaluable for my desktop development and as I shift to focusing on mobile devices, I’m glad to see that I’ll be able to continue to use it to test on those devices as well. As of version three, JSBin has incorporated a feature called “live rendering” which acts as a simulcast across multiple connected devices. These devices aren’t explicitly connected but instead, leverage a specific URL which allows them to essentially render the results at the same time. You can see this feature in action in the following video.

    Another important feature is the ability to create your own JSBin account where you can save your bins for future reference and sharing. Registration is simple and you can even leverage your Github credentials via Github’s OAuth functionality.

    jsbin-register

    The key benefit to registering is the ability to keep a history of the bins you create so that you can revisit them later.

    To really get a feel for the full breadth of functionality offered by JSBin, I urge you to go to Remy’s Youtube channel for JSBin, where he’s done a bang up job of creating tutorial videos exploring all of the excellent features of the service. The FAQ also does a great job of answering common questions you might have.

    JSBin is one of my most valuable tools I’ve found for JavaScript development. The fact that it’s free and open source makes it a no-brainer to add to any toolkit. And Remy’s continued commitment to the service is commendable. All of this combined, makes it easy for me to spread the word about such a great tool.

     

    0 Comments

    Leave a comment › Posted in: Daily

    1. Creating Brackets Extensions

      A little while ago I wrote about the recent updates to the Brackets editor. Brackets is an open source project focused on web standards and built with web technologies. It has a narrow focus and therefore may not have a particular feature you’ve come to depend upon. Luckily, Brackets ships with a powerful extension API that lets you add any number of new features. In this article, I’m going to discuss this API and demonstrate how you can build your own extensions.

      It is crucial that you remember that Brackets is in active development. This article is being written in December of 2013. It is certainly possible that the code demonstrated below is now out of date. Keep that in mind and be sure to check the wiki for the latest updates to the extension API.


      Getting Started

      I’m going to assume you read my last article and are already familiar with the extension manager. This provides a simple, one click method of installing extensions. One of the best ways you can learn to write extensions is by looking at the work done by others (that’s how I learned). I’d recommend grabbing a few extensions (there’s almost 200 available now) and tearing apart their code. Don’t be afraid to break a few while you’re at it.

      Brackets puts all installed extensions within one main folder. To find that folder, go to the Help menu and select “Show Extensions Folder“. For my OS X install, this was located at /Users/ray/Library/Application Support/Brackets/extensions/user. If you go up from that folder, you’ll notice a disabled folder as well. Brackets will make a valiant effort to load no matter what, but if you ever find yourself in a situation where Brackets has completely crapped the bed and simply will not work, consider moving potentially bad extensions into the disabled folder. Later on in the article, I’ll discuss how you can monitor and debug extensions to help prevent such problems in the first place.

      Begin by going to your user folder and creating a new folder, helloworld1. Yes, even though it is completely lame, we’re going to build a HelloWorld extension. Don’t hate me, I like simple. Inside that folder create a new file called main.js. Listing one shows what the contents of this file should be. Note that in this article I’ll go through a couple of different iterations of the helloworld extension. Each one will be named with a progressively higher number. So our first example is from helloworld1, the next helloworld2, and so on. It would make sense for you to simply copy the code into one folder, helloworld, instead of copying each one by themselves. If you do, you’ll have multiple related extensions running at once and that can definitely confuse things.

      Listing 1: helloworld1/main.js
      define(function(require, exports, module) {
      
          function log(s) {
                  console.log("[helloworld] "+s);
          }
      
          log("Hello from HelloWorld.");
      });
      

      The first line defines our extension as a module that will be picked up by Brackets automatically on application load. The rest of the extension is a custom log message (you will see why in a second) and a call to that logger. Once you have this file saved, go back to Brackets, select the Debug menu, and hit Reload. (You can also use Command/Control+R to reload as well.)

      Brackets will reload and … nothing else will happen. The extension we built didn’t actually do anything that we could see, but it did log to the console. But where is that console? Brackets provides an easy way to view the console. Simply go back to the Debug menu and select Show Developer Tools. This will open a new tab in Chrome with a familiar Dev Tools UI. In the screen shot below I’ve highlighted our log. Other extensions, and Brackets itself, will also log messages to this screen. By prefixing my log messages with [helloworld], I can make my own stuff a bit easier to find.

      Brackets console messages

      Note that the full Chrome console.api works here. You can do stuff like this to format your console messages:

          
      function log(s) {
          console.log("%c[helloworld] "+s,"color:blue;font-size:large");
      }
      

      Go crazy, but try to remove these messages before you share your code with the rest of the world. In case you’re curious, you can’t use dev tools in another browser, like Firefox, at this time.


      Integration Points

      Now that you know the (very) basics, let’s talk about what Brackets extensions can do to the editor:

      • They can create keyboard shortcuts, allowing them to respond to custom keystrokes.
      • They can add to the top level menu.
      • They can add context menus (and to a specific area, like the file listing or the editor window).
      • They can create UI items. This can be a modal dialog or even a panel. (Currently the panel is locked to the bottom of the screen).
      • They can create a linting provider (essentially they can register themselves as a code checker for a file type).
      • They can create their own inline editors (a major feature of Brackets).
      • They can register as a documentation provider (for example, adding MDN support for docs).
      • They can integrate with Quick Find and Quick Open.
      • They can add custom code hints and syntax colors.
      • They can read the current file open in the editor as well as modify it. (They can also see the current selected text, if any.)

      That describes how extensions can modify Brackets, but what can extensions actually do in terms of code? Keeping in mind that you’re writing extensions in pure web standards (HTML, JavaScript, and CSS), you actually have quite a bit of power. The only real limits relate to binary data. There is a File system API that gives you control over files but is limited to text data only. Luckily, you have a way out.

      Any Brackets extension can integrate with Node.js. If you’ve got an existing Node.js package your extension can make calls to it and do, well, whatever Node.js can do, which is essentially anything.

      Let’s update our extension to integrate with the editor a bit better. I’ll start by simply adding a menu item for the extension.

      Listing 2: helloworld2/main.js
      /*
      Based - in part - on the HelloWorld sample extension on the Brackets wiki:
      
      https://github.com/adobe/brackets/wiki/Simple-%22Hello-World%22-extension
      
      */
      define(function(require, exports, module) {
      
          var CommandManager = brackets.getModule("command/CommandManager"),
                  Menus = brackets.getModule("command/Menus"),
                  AppInit = brackets.getModule("utils/AppInit");
          function log(s) {
                  console.log("[helloworld2] "+s);
          }
          function handleHelloWorld() {
                  alert("You ran me, thanks!");
          }
          AppInit.appReady(function () {
      
                  log("Hello from HelloWorld2.");
      
                  var HELLOWORLD_EXECUTE = "helloworld.execute";
      
                  CommandManager.register("Run HelloWorld", HELLOWORLD_EXECUTE, handleHelloWorld);
      
                  var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
                  menu.addMenuItem(HELLOWORLD_EXECUTE);
      
          });
      
      });
      

      We’ve got a few changes here so let’s tackle them one by one. You’ll notice that the extension begins with three calls to brackets.getModule. All extensions have access to a brackets object that provides an API where we can load in core functionality from the editor. In this case the extension has loaded two libraries we’ll need for the menu (CommandManager and Menus) and one which will be used to help initialize the extension (AppInit).

      Lets talk about AppInit. You can see that most of the extension is now loaded with a appReady callback. This callback is fired when Brackets has completed loading and is generally considered “best practice” for extensions to make use of.

      Registering a menu item takes a few steps. I begin by defining a “command ID”, a unique identifier for the item I’ll be adding to the UI. The typical way to do this is with the format extensionname.someaction. In my case, I used helloworld.execute. I can then register this command along with the function (handleHelloWorld) that should be called when the command is fired.

      The final step is to add this command to the menu. You can probably guess that my menu item will be added under the View menu based on this value: Menus.AppMenuBar.VIEW_MENU. How did I know that value? Simple, I saw other extensions do it. Seriously though, there is no specific list of items like this yet. Don’t forget that Brackets is open source. I can easily pop over to the GitHub repo and check it out. In this case, the file is Menus.js, located on Github. In there I can see where the various different core menus are defined:

      /**
        * Brackets Application Menu Constants
        * @enum {string}
      */
      var AppMenuBar = {
           FILE_MENU       : "file-menu",
           EDIT_MENU       : "edit-menu",
           VIEW_MENU       : "view-menu",
           NAVIGATE_MENU   : "navigate-menu",
           HELP_MENU       : "help-menu"
      };      
      

      As a general rule of thumb, it makes sense to have at least a cursory understanding of what’s available in Brackets itself. Your extensions will, from time to time, make use of multiple different features so it’s definitely in your best interest to at least know the lay of the land.

      After reloading Brackets, you’ll now see the menu item in the View menu. Exactly where it is may be a bit random as you may have other extensions installed.

      View menu updated

      You can actually be a bit more specific about your position. Again, this is where the source code will help you. The same file I linked to above also contains the addMenuItem definition.


      Put Some Lipstick on That Pig

      Now that you’ve seen a simple example of how an extension can integrate into Brackets, let’s look at how we update the UI. In the previous version of our code, an alert was used to send a message. While this works, it isn’t very pretty. Your code can access the Brackets editor just like any other DOM modification code. While you can do anything you want, there are a few standard ways extensions update the UI in Brackets. (As a warning, in general you do not want to touch the DOM of the main editor UI. You can, but with future updates, your code may break. Also, users may not be happy if your extension changes something core to Brackets.)

      The first method we’ll look at uses modal dialogs. Brackets already uses this and has an API available for extensions to call. As a simple example, let’s just update the HelloWorld extension to use a modal instead.

      Listing 3: helloworld3/main.js
      /*
      Based - in part - on the HelloWorld sample extension on the Brackets wiki:
      
      https://github.com/adobe/brackets/wiki/Simple-%22Hello-World%22-extension
      
      */
      define(function(require, exports, module) {
      
          var CommandManager = brackets.getModule("command/CommandManager"),
              Menus = brackets.getModule("command/Menus"),
              Dialogs = brackets.getModule("widgets/Dialogs"),
              DefaultDialogs = brackets.getModule("widgets/DefaultDialogs"),
              AppInit = brackets.getModule("utils/AppInit");
      
          function log(s) {
                  console.log("[helloworld3] "+s);
          }
      
          function handleHelloWorld() {
              Dialogs.showModalDialog(DefaultDialogs.DIALOG_ID_INFO, "Hello World", "Same Important Message");
          }
      
          AppInit.appReady(function () {
      
              log("Hello from HelloWorld3.");
      
              var HELLOWORLD_EXECUTE = "helloworld.execute";
      
              CommandManager.register("Run HelloWorld", HELLOWORLD_EXECUTE, handleHelloWorld);
      
              var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
              menu.addMenuItem(HELLOWORLD_EXECUTE);
      
          });
      
      });
      

      Note the addition of two additional Brackets modules: Dialogs and DefaultDialogs. The next change is in handleHelloWorld. One of the methods in the Dialog library is the ability to show a dialog (no surprise there, I suppose). The method wants a class, a title, and a body, and that’s it. There’s more you can do with dialogs, but for now, this demonstrates the feature. Now when we run the command, we get a much prettier UI. (Along with default buttons and behaviours to handle closing the dialog.)

      Dialog example

      That’s one example, now lets look at another: creating a bottom panel. As with dialogs, we’ve got support from Brackets to make it easier. Let’s look at an example and then I’ll explain the changes.

      Listing 4: helloworld4/main.js
      /*
      Based - in part - on the HelloWorld sample extension on the Brackets wiki:
      
      https://github.com/adobe/brackets/wiki/Simple-%22Hello-World%22-extension
      
      */
      define(function(require, exports, module) {
      
          var CommandManager = brackets.getModule("command/CommandManager"),
          Menus = brackets.getModule("command/Menus"),
          PanelManager = brackets.getModule("view/PanelManager"),
          AppInit = brackets.getModule("utils/AppInit");
      
          var HELLOWORLD_EXECUTE = "helloworld.execute";
          var panel;
      
          function log(s) {
                  console.log("[helloworld4] "+s);
          }
      
          function handleHelloWorld() {
              if(panel.isVisible()) {
                  panel.hide();
                  CommandManager.get(HELLOWORLD_EXECUTE).setChecked(false);
              } else {
                  panel.show();
                  CommandManager.get(HELLOWORLD_EXECUTE).setChecked(true);
              }
          }
      
          AppInit.appReady(function () {
      
                  log("Hello from HelloWorld4.");
      
                  CommandManager.register("Run HelloWorld", HELLOWORLD_EXECUTE, handleHelloWorld);
      
                  var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
                  menu.addMenuItem(HELLOWORLD_EXECUTE);
      
                  panel = PanelManager.createBottomPanel(HELLOWORLD_EXECUTE, $("<div class='bottom-panel'>HTML for my panel</div>"),200);
      
          });
      
      });
      

      Let’s focus on the changes. First, I dropped the Dialog modules as I’m no longer using them. Instead, we load up the PanelManager. Down in the appReady block I’ve defined a new panel using the PanelManager API method createBottomPanel. Like the menu command this takes in a unique ID so I just reuse HELLOWORLD_EXECUTE. The second argument is a jQuery-wrapped block of HTML (and in case you’re wondering, yes we can do this nicer), and finally, a minimum size. This sets up the panel but doesn’t actually execute it.

      In the event handler, we have tied to the menu, we can ask the panel if it is visible and then either hide or show it. That part should be pretty trivial. For fun I’ve added in a bit more complexity. Notice that CommandManager lets us get a menu item and set a checked property. This may be unnecessary as the user can see the panel easily enough themselves, but adding the check just makes things a little bit more obvious. In the screen shot below you can see the panel in its visible state.

      Panel example

      Right away you may be wondering about the panel HTML. Is there a better way to provide the HTML? Anyway to style it? Yep, lets look at a more advanced version.

      Listing 5: helloworld5/main.js
      /*
      Based - in part - on the HelloWorld sample extension on the Brackets wiki:
      
      https://github.com/adobe/brackets/wiki/Simple-%22Hello-World%22-extension
      
      */
      define(function(require, exports, module) {
          var CommandManager = brackets.getModule("command/CommandManager"),
          Menus = brackets.getModule("command/Menus"),
          PanelManager = brackets.getModule("view/PanelManager"),
          ExtensionUtils          = brackets.getModule("utils/ExtensionUtils"),        
          AppInit = brackets.getModule("utils/AppInit");
      
          var HELLOWORLD_EXECUTE = "helloworld.execute";
          var panel;
          var panelHtml     = require("text!panel.html");
      
          function log(s) {
                  console.log("[helloworld5] "+s);
          }
      
          function handleHelloWorld() {
              if(panel.isVisible()) {
                  panel.hide();
                  CommandManager.get(HELLOWORLD_EXECUTE).setChecked(false);
              } else {
                  panel.show();
                  CommandManager.get(HELLOWORLD_EXECUTE).setChecked(true);
              }
          }
      
          AppInit.appReady(function () {
      
              log("Hello from HelloWorld5.");
              ExtensionUtils.loadStyleSheet(module, "helloworld.css");
              CommandManager.register("Run HelloWorld", HELLOWORLD_EXECUTE, handleHelloWorld);
      
              var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
              menu.addMenuItem(HELLOWORLD_EXECUTE);
      
              panel = PanelManager.createBottomPanel(HELLOWORLD_EXECUTE, $(panelHtml),200);
      
          });
      
      });
      

      As before, I’m going to focus on the changes. First note that I’ve included a variable called panelHtml that is loaded via require. This lets me define my HTML outside of my JavaScript code. (You can also use templating engines. Brackets ships with Mustache.) The HTML behind the panel is rather simple.

      Listing 6: helloworld5/panel.html
      <div class="bottom-panel helloworld-panel" id="helloworldPanel">
      <h1>My Panel</h1>
      
      <p>
      My panel brings all the boys to the yard,<br/>
      And they're like<br/>
      It's better than yours,<br/>
      Damn right it's better than yours,<br/>
      I can teach you,<br/>
      But I have to charge
      </p>
      </div>
      

      Returning to main.js, I’ve demonstrated another feature, loadStyleSheet. This lets you load an extension specific style sheet. I created a file, helloworld.css, with some simple (but tasteful) CSS styles.

      Listing 7: helloworld5/helloworld.css
      .helloworld-panel h1 {
              color: red;
      }
      
      .helloworld-panel p {
              color: blue;
              font-weight: bold;
      }
      

      Note that I prefixed my styles with a unique name. This helps ensure my classes don’t conflict with anything built into Brackets. With these simple changes my panel now looks much better, and you can see why I’m known world wide for my superior design skills.

      Epic CSS

      Packaging and Sharing Your Kick Butt Extension

      Of course, just creating the coolest Brackets extension isn’t quite enough. You probably (hopefully!) want to share it with others. One option is to just zip up the directory and put it on your website. Folks can download the zip, extract it, and copy it to their Brackets extensions folder.

      But that’s not cool. You want to be cool, right? In order to share your extension and make it available via the Brackets Extension manager, you simply need to add a package.json file to your extension. If you’ve ever used Node.js, then this will seem familiar. Here is a sample one for our extension.

      Listing 8: helloworld6/package.json
      {
          "name": "camden.helloworld",
          "title": "HelloWorld",
          "description": "Adds HelloWorld support to Brackets.",
          "homepage": "https://github.com/cfjedimaster/something real here",
          "version": "1.0.0",
          "author": "Raymond Camden <raymondcamden@gmail.com> (http://www.raymondcamden.com)",
          "license": "MIT",
          "engines": {
              "brackets": "<=0.34.0"
          }
      }
      

      Most of this is self-explanatory, but the real crucial portion is the engines block. Brackets updates itself pretty rapidly. If Brackets added a particular feature at some point that your extension relies on, you can add a simple conditional here to ensure folks don’t try to install your extension on an incompatible version. (You can find a full listing of the possible settings on the Wiki.)

      Once you’ve done this, the next part is to upload it to the Brackets Registry. You will need to log in via your GitHub account, but once you’ve done that, you can then simply upload your zip. Your extension will then be available to anyone using Brackets. Even better, if you update your extension, the Extension Manager will actually be able to flag this to the user so they know an update is available.


      What Else?

      Hopefully, you’ve seen how easy it is to extend Brackets. There’s more we didn’t cover, like the Linting API and NodeJS integration, but this article should be more than enough to get you started. As a reminder, do not forget there is a large collection of extensions available for you to start playing with right now. Good luck!

       

      0 Comments

      Leave a comment › Posted in: Daily

    1. Validation and Exception Handling: From the UI to the Backend

      Sooner or later in your programming career you will be faced with the dilemma of validation and exception handling. This was the case with me and my team also. A couple or so years ago we reached a point when we had to take architectural actions to accommodate all the exceptional cases our quite large software project needed to handle. Below is a list of practices we came to value and apply when it comes to validation and exception handling.


      Validation vs. Exception Handling

      When we started discussing our problem, one thing surfaced very quickly. What is validation and what is exception handling? For example in a user registration form, we have some rules for the password (it must contain both numbers and letters). If the user enters only letters, is that a validation issue or an exception. Should the UI validate that, or just pass it to the backend and catch any exceptions that my be thrown?

      We reached a common conclusion that validation refers to rules defined by the system and verified against user provided data. A validation should not care about how the business logic works, or how the system for that matter works. For example, our operating system may expect, without any protests, a password composed of plain letters. However we want to enforce a combination of letters and numbers. This is a case for validation, a rule we want to impose.

      On the other hand, exceptions are cases when our system may function in an unpredicted way, wrongly, or not at all if some specific data is provided in a wrong format. For example, in the above example, if the username already exists on the system, it is a case of an exception. Our business logic should be able to throw the appropriate exception and the UI catch and handle it so that the user will see a nice message.


      Validating in the User Interface

      Now that we made clear what our goals are, let’s see some examples based on the same user registration form idea.

      Validating in JavaScript

      To most of today’s browsers, JavaScript is second nature. There is almost no webpage without some degree of JavaScript in it. One good practice is to validate some basic things in JavaScript.

      Let’s say we have a simple user registration form in index.php, as described below.

      <!DOCTYPE html>
      <html>
      	<head>
      		<title>User Registration</title>
      		<meta charset="UTF-8">
      	</head>
      	<body>
      		<h3>Register new account</h3>
      		<form>
      			Username:
      			<br/>
      			<input type="text" />
      			<br/>
      			Password:
      			<br/>
      			<input type="password" />
      			<br/>
      			Confirm:
      			<br/>
      			<input type="password" />
      			<br/>
      			<input type="submit" name="register" value="Register">
      		</form>
      	</body>
      </html>
      

      This will output something similar to the image below:

      RegistrationForm

      Every such form should validate that the text entered in the two password fields are equal. Obviously this is to ensure the user does not make a mistake when typing in his or her password. With JavaScript, doing the validation is quite simple.

      First we need to update a little bit of our HTML code.

      <form onsubmit="return validatePasswords(this);">
      	Username:
      	<br/>
      	<input type="text" />
      	<br/>
      	Password:
      	<br/>
      	<input type="password" name="password"/>
      	<br/>
      	Confirm:
      	<br/>
      	<input type="password" name="confirm"/>
      	<br/>
      	<input type="submit" name="register" value="Register">
      </form>
      

      We added names to the password input fields so we can identify them. Then we specified that on submit the form should return the result of a function called validatePasswords(). This function is the JavaScript we’ll write. Simple scripts like this can be kept in the HTML file, other, more sophisticated ones should go in their own JavaScript files.

      <script>
      	function validatePasswords(form) {
      		if (form.password.value !== form.confirm.value) {
      			alert("Passwords do not match");
      			return false;
      		}
      		return true;
      	}
      
      </script>
      

      The only thing we do here is to compare the values of the two input fields named “password” and “confirm“. We can reference the form by the parameter we send in when calling the function. We used “this” in the form’s onsubmit attribute, so the form itself is sent to the function.

      When the values are the same, true will be returned and the form will be submitted, otherwise an alert message will be shown telling the user the passwords do not match.

      PasswordDoNotMatchAlert

      HTML5 Validations

      While we can use JavaScript to validate most of our inputs, there are cases when we want to go on an easier path. Some degree of input validation is available in HTML5, and most browsers are happy to apply them. Using HTML5 validation is simpler in some cases, though it offers less flexibility.

      <head>
      	<title>User Registration</title>
      	<meta charset="UTF-8">
      	<style>
      		input {
      			width: 200px;
      		}
      		input:required:valid {
      			border-color: mediumspringgreen;
      		}
      		input:required:invalid {
      			border-color: lightcoral;
      		}
      	</style>
      </head>
      <body>
      	<h3>Register new account</h3>
      	<form onsubmit="return validatePasswords(this);">
      		Username:
      		<br/>
      		<input type="text" name="userName" required/>
      		<br/>
      		Password:
      		<br/>
      		<input type="password" name="password"/>
      		<br/>
      		Confirm:
      		<br/>
      		<input type="password" name="confirm"/>
      		<br/>
      		Email Address:
      		<br/>
      		<input type="email" name="email" required placeholder="A Valid Email Address"/>
      		<br/>
      		Website:
      		<br/>
      		<input type="url" name="website" required pattern="https?://.+"/>
      		<br/>
      		<input type="submit" name="register" value="Register">
      	</form>
      </body>
      

      To demonstrate several validation cases, we extended our form a little bit. We added an email address and a website also. HTML validations were set on three fields.

      • The text input username is just simply required. It will validate with any string longer than zero characters.
      • The email address field is of type “email” and when we specify the “required” attribute, browsers will apply a validation to the field.
      • Finally, the website field is of type “url“. We also specified a “pattern” attribute where you can write your regular expressions that validate the required fields.

      To make the user aware of the state of the fields, we also used a little bit of CSS to color the borders of the inputs in red or green, depending on the state of the required validation.

      HTMLValidations

      The problem with HTML validations is that different browsers behave differently when you try to submit the form. Some browsers will just apply the CSS to inform the users, others will prevent the submission of the form altogether. I recommend you to test your HTML validations thoroughly in different browsers and if needed also provide a JavaScript fallback for those browsers that are not smart enough.


      Validating in Models

      By now many people know about Robert C. Martin’s clean architecture proposal, in which the MVC framework is only for presentation and not for business logic.

      HighLevelDesign

      Essentially, your business logic should reside in a separate, well isolated place, organized to reflect the architecture of your application, while the framework’s views and controllers should control the delivery of the content to the user and models could be dropped altogether or, if needed, used only to perform delivery related operations. One such operation is validation. Most frameworks have great validation features. It would be a shame to not put your models at work and do a little validation there.

      We will not install several MVC web frameworks to demonstrate how to validate our previous forms, but here are two approximate solutions in Laravel and CakePHP.

      Validation in a Laravel Model

      Laravel is designed so that you have more access to validation in the Controller where you also have direct access to the input from the user. The built-in validator kind of prefers to be used there. However there are suggestions on the Internet that validating in models is still a good thing to do in Laravel. A complete example and solution by Jeffrey Way can be found on his Github repository.

      If you prefer to write your own solution, you could do something similar to the model below.

      class UserACL extends Eloquent {
          private $rules = array(
              'userName' => 'required|alpha|min:5',
              'password'  => 'required|min:6',
      		'confirm' => 'required|min:6',
      		'email' => 'required|email',
      		'website' => 'url'
          );
      
          private $errors;
      
          public function validate($data) {
              $validator = Validator::make($data, $this->rules);
      
              if ($validator->fails()) {
                  $this->errors = $validator->errors;
                  return false;
              }
              return true;
          }
      
          public function errors() {
              return $this->errors;
          }
      }

      You can use this from your controller by simply creating the UserACL object and call validate on it. You will probably have the “register” method also on this model, and the register will just delegate the already validated data to your business logic.

      Validation in a CakePHP Model

      CakePHP promotes validation in models as well. It has extensive validation functionality at model level. Here is about how a validation for our form would look like in CakePHP.

      class UserACL extends AppModel {
      
          public $validate = [
      		'userName' => [
      			'rule' => ['minLength', 5],
      			'required' => true,
      			'allowEmpty' => false,
      			'on' => 'create',
      			'message' => 'User name must be at least 5 characters long.'
      		],
              'password' => [
                  'rule'    => ['equalsTo', 'confirm'],
                  'message' => 'The two passwords do not match. Please re-enter them.'
              ]
          ];
      
          public function equalsTo($checkedField, $otherField = null) {
      		$value = $this->getFieldValue($checkedField);
              return $value === $this->data[$this->name][$otherField];
          }
      
      	private function getFieldValue($fieldName) {
      	    return array_values($otherField)[0];
      	}
      }

      We only exemplified the rules partially. It is enough to highlight the power of validation in the model. CakePHP is particularly good at this. It has a great number of built-in validation functions like “minLength” in the example and various ways to provide feedback to the user. Even more, concepts like “required” or “allowEmpty” are not actually validation rules. Cake will look at these when generating your view and put HTML validations also on fields marked with these parameters. However rules are great and can easily be extended by just simply creating methods on the model class as we did to compare the two password fields. Finally, you can always specify the message you want to send to the views in case of validation failure. More on CakePHP validation in the cookbook.

      Validation in general at the model level has its advantages. Each framework provides easy access to the input fields and creates the mechanism to notify the user in case of validation failure. No need for try-catch statements or any other sophisticated steps. Validation on the server side also assures that the data gets validated, no matter what. The user can not trick our software any more as with HTML or JavaScript. Of course, each server side validation comes with the cost of a network round-trip and computing power on the provider’s side instead of the client’s side.


      Throwing Exceptions from the Business Logic

      The final step in checking data before committing it to the system is at the level of our business logic. Information that reaches this part of the system should be sanitized enough to be usable. The business logic should only check for cases that are critical for it. For example, adding a user that already exists is a case when we throw an exception. Checking the length of the user to be at least five characters should not happen at this level. We can safely assume that such limitations were enforced at higher levels.

      On the other hand, comparing the two passwords is a matter for discussion. For example, if we just encrypt and save the password near the user in a database, we could drop the check and assume previous layers made sure the passwords are equal. However, if we create a real user on the operating system using an API or a CLI tool that actually requires a username, password, and password confirmation, we may want to take the second entry also and send it to a CLI tool. Let it re-validate if the passwords match and be ready to throw an exception if they do not. This way we modeled our business logic to match how the real operating system behaves.

      Throwing Exceptions from PHP

      Throwing exceptions from PHP is very easy. Let’s create our user access control class, and demonstrate how to implement a user addition functionality.

      class UserControlTest extends PHPUnit_Framework_TestCase {
      	function testBehavior() {
      		$this->assertTrue(true);
      	}
      }

      I always like to start with something simple that gets me going. Creating a stupid test is a great way to do so. It also forces me to think about what I want to implement. A test named UserControlTest means I thought I will need a UserControl class to implement my method.

      require_once __DIR__ . '/../UserControl.php';
      class UserControlTest extends PHPUnit_Framework_TestCase {
      
      	/**
      	 * @expectedException Exception
      	 * @expectedExceptionMessage User can not be empty
      	 */
      	function testEmptyUsernameWillThrowException() {
      		$userControl = new UserControl();
      		$userControl->add('');
      	}
      
      }

      The next test to write is a degenerative case. We will not test for a specific user length, but we want to make sure we do not want to add an empty user. It is sometimes easy to lose the content of a variable from view to business, over all those layers of our application. This code will obviously fail, because we do not have a class yet.

      PHP Warning:  require_once([long-path-here]/Test/../UserControl.php):
      failed to open stream: No such file or directory in
      [long-path-here]/Test/UserControlTest.php on line 2

      Let’s create the class and run our tests. Now we have another problem.

      PHP Fatal error:  Call to undefined method UserControl::add()

      But we can fix that, too, in just a couple of seconds.

      class UserControl {
      
      	public function add($username) {
      
      	}
      
      }

      Now we can have a nice test failure telling us the whole story of our code.

      1) UserControlTest::testEmptyUsernameWillThrowException
      Failed asserting that exception of type "Exception" is thrown.

      Finally we can do some actual coding.

      public function add($username) {
      	if(!$username) {
      		throw new Exception();
      	}
      }

      That makes the expectation for the exception pass, but without specifying a message the test will still fail.

      1) UserControlTest::testEmptyUsernameWillThrowException
      Failed asserting that exception message '' contains 'User can not be empty'.

      Time to write the Exception’s message

      public function add($username) {
      	if(!$username) {
      		throw new Exception('User can not be empty!');
      	}
      }

      Now, that makes our test pass. As you can observe, PHPUnit verifies that the expected exception message is contained in the actually thrown exception. This is useful because it allows us to dynamically construct messages and only check for the stable part. A common example is when you throw an error with a base text and at the end you specify the reason for that exception. Reasons are usually provided by third party libraries or application.

      /**
       * @expectedException Exception
       * @expectedExceptionMessage Cannot add user George
       */
      function testWillNotAddAnAlreadyExistingUser() {
      	$command = \Mockery::mock('SystemCommand');
      	$command->shouldReceive('execute')->once()->with('adduser George')->andReturn(false);
      	$command->shouldReceive('getFailureMessage')->once()->andReturn('User already exists on the system.');
      	$userControl = new UserControl($command);
      	$userControl->add('George');
      }

      Throwing errors on duplicate users will allow us to explore this message construction a step further. The test above creates a mock which will simulate a system command, it will fail and on request, it will return a nice failure message. We will inject this command to the UserControl class for internal use.

      class UserControl {
      
      	private $systemCommand;
      
      	public function __construct(SystemCommand $systemCommand = null) {
      		$this->systemCommand = $systemCommand ? : new SystemCommand();
      	}
      
      	public function add($username) {
      		if (!$username) {
      			throw new Exception('User can not be empty!');
      		}
      	}
      
      }
      
      class SystemCommand {
      
      }

      Injecting the a SystemCommand instance was quite easy. We also created a SystemCommand class inside our test just to avoid syntax problems. We won’t implement it. Its scope exceeds this tutorial’s topic. However, we have another test failure message.

      1) UserControlTest::testWillNotAddAnAlreadyExistingUser
      Failed asserting that exception of type "Exception" is thrown.

      Yep. We are not throwing any exceptions. The logic to call the system command and try to add the user is missing.

      public function add($username) {
      	if (!$username) {
      		throw new Exception('User can not be empty!');
      	}
      
      	if(!$this->systemCommand->execute(sprintf('adduser %s', $username))) {
      		throw new Exception(
      				sprintf('Cannot add user %s. Reason: %s',
      						$username,
      						$this->systemCommand->getFailureMessage()
      				)
      			);
      	}
      }

      Now, those modifications to the add() method can do the trick. We try to execute our command on the system, no matter what, and if the system says it can not add the user for whatever reason we throw an exception. This exception’s message will be part hard-coded, with the user’s name attached and then the reason from the system command concatenated at the end. As you can see, this code makes our test pass.

      Custom Exceptions

      Throwing exceptions with different messages is enough in most cases. However, when you have a more complex system you also need to catch these exceptions and take different actions based on them. Analyzing an exception’s message and taking action solely on that can lead to some annoying problems. First, strings are part of the UI, presentation, and they have a volatile nature. Basing logic on ever changing strings will lead to dependency management nightmare. Second, calling a getMessage() method on the caught exception each time is also a strange way to decide what to do next.

      With all these in mind, creating our own exceptions is the next logical step to take.

      /**
       * @expectedException ExceptionCannotAddUser
       * @expectedExceptionMessage Cannot add user George
       */
      function testWillNotAddAnAlreadyExistingUser() {
      	$command = \Mockery::mock('SystemCommand');
      	$command->shouldReceive('execute')->once()->with('adduser George')->andReturn(false);
      	$command->shouldReceive('getFailureMessage')->once()->andReturn('User already exists on the system.');
      	$userControl = new UserControl($command);
      	$userControl->add('George');
      }

      We modified our test to expect our own custom exception, ExceptionCannotAddUser. The rest of the test is unchanged.

      class ExceptionCannotAddUser extends Exception {
      
      	public function __construct($userName, $reason) {
      		$message = sprintf(
      			'Cannot add user %s. Reason: %s',
      			$userName, $reason
      		);
      		parent::__construct($message, 13, null);
      	}
      }

      The class that implements our custom exception is like any other class, but it has to extend Exception. Using custom exceptions also provides us a great place to do all the presentation related string manipulation. Moving the concatenation here, we also eliminated presentation from the business logic and respected the single responsibility principle.

      public function add($username) {
      	if (!$username) {
      		throw new Exception('User can not be empty!');
      	}
      
      	if(!$this->systemCommand->execute(sprintf('adduser %s', $username))) {
      		throw new ExceptionCannotAddUser($username, $this->systemCommand->getFailureMessage());
      	}
      }

      Throwing our own exception is just a matter of changing the old “throw” command to the new one and sending in two parameters instead of composing the message here. Of course all tests are passing.

      PHPUnit 3.7.28 by Sebastian Bergmann.
      
      ..
      
      Time: 18 ms, Memory: 3.00Mb
      
      OK (2 tests, 4 assertions)
      
      Done.

      Catching Exceptions in Your MVC

      Exceptions must be caught at some point, unless you want your user to see them as they are. If you are using an MVC framework you will probably want to catch exceptions in the controller or model. After the exception is caught, it is transformed in a message to the user and rendered inside your view. A common way to achieve this is to create a “tryAction($action)” method in your application’s base controller or model and always call it with the current action. In that method you can do the catching logic and nice message generation to suit your framework.

      If you do not use a web framework, or a web interface for that matter, your presentation layer should take care of catching and transforming these exceptions.

      If you develop a library, catching your exceptions will be the responsibility of your clients.


      Final Thoughts

      That’s it. We traversed all the layers of our application. We validated in JavaScript, HTML and in our models. We’ve thrown and caught exceptions from our business logic and even created our own custom exceptions. This approach to validation and exception handling can be applied from small to big projects without any severe problems. However if your validation logic is getting very complex, and different parts of your project uses overlapping parts of logic, you may consider extracting all validations that can be done at a specific level to a validation service or validation provider. These levels may include, but not need to be limited to JavaScript validator, backend PHP validator, third party communication validator and so on.

      Thank you for reading. Have a nice day.

       

      0 Comments

      Leave a comment › Posted in: Daily

    1. Working With LESS and the Chrome DevTools

      This is a complete tutorial to using LESS with Chrome’s DevTools. If you’ve already used Sass with Chrome’s DevTools, you’ll most likely already be familiar with the concepts introduced here.

      The Tl;dr

      • LESS has very recently added support for Source Maps, so this is new and exciting!
      • DevTools mapping means you can view LESS styles for all your relevant CSS.
      • Edit LESS source files within DevTools and have them save to disk.
      • Source Map adoption is improving with Sass, CoffeeScript, UglifyJS2 and more.

      Introduction

      Not too long ago, the Chrome DevTools added a number of IDE-like features (and continues to do so), one of which is the ability to understand the mapping between a compiled file and its corresponding source file. This is made possible thanks to Source Maps.

      image_0-2

      What This Tutorial Will Cover

      • How to generate Source Maps from LESS files.
      • Debugging LESS code through the DevTools.
      • Authoring LESS code in the DevTools and seeing changes immediately via Workspaces and Grunt.

      Everything mentioned here is available in Chrome Canary.


      Configuring LESS for Source Maps

      First thing’s first, install the latest (1.5.1 at the time of this writing) version of LESS through NPM (Source Maps arrived in 1.5.0):

      $ npm install -g less
      $ lessc -v
      lessc 1.5.1 (LESS Compiler) [JavaScript]
      
      image_1

      At this point, you can run the LESS compiler in your terminal using the lessc command.

      image_2

      Create a new LESS file, for demonstration purposes, it’ll be kept short and simple.

      @color: #4D926F;
      #header {
        color: @color;
      }
      

      To turn the LESS file into a CSS file, it’s a simple case of running:

      lessc header.less header.css
      
      image_3

      We now need a Source Map file. Create it with the -source-map flag.

      lessc --source-map=header.map header.less header.css
      

      Using the LESS code shown above, running this command produces a Source Map file with the following contents:

      {"version":3,"file":"header.css","sources":["header.less"],"names":[],"mappings":"AAEQ;EACP,cAAA"}
      

      Using DevTools to Map to LESS Source Files

      In a world without Source Maps, DevTools would display styles originating from the compiled CSS. Line numbering would not be useful due to a mismatch between compiled CSS and the source CSS. With Source Maps, when inspecting a DOM node on the page, DevTools will automatically show the styles originating from the LESS source file.

      Viewing a web page which references the previously mentioned header.css is now inspectable in a more meaningful way.

      image_4

      While holding Command (Ctrl on Windows), click any property, value or selector to jump to the line of code in the corresponding LESS source file within the Sources Panel.


      Authoring Workflow With DevTools & LESS

      Viewing LESS code in the DevTools is certainly useful, but integrating an authoring workflow can speed up your iteration cycle. The next step is to tell DevTools how the resources on a web page map to files on a file system. Enter: Workspaces.

      Note: Workspaces are suitable for many projects, not just those using CSS preprocessors.

      Workspaces

      You might already be familiar with the Sources panel from an editing perspective. The general idea is that you have a file navigator in the sidebar where each file is typically a stylesheet, script or HTML resource that the web page has loaded.

      image_6

      Clicking on a resource displays the contents in the main panel, you may notice the similarity this has with the Resources panel, however there is at least one major difference: the Sources panel contains a live editor. Changes you make to stylesheets are applied to the page instantly and changes you make to scripts are injected back into the V8 engine and evaluated immediately. Not only does this work for remotely hosted files, but also for local ones with the added benefit of persisting your changes to a file.

      Note: To make use of Workspaces, the following steps are only required once per project.

      Step 1.

      Open up a local webpage and add its corresponding folder on your file system to the workspace by Right-Clicking in the Sources panel sidebar and selecting Add folder to Workspace.

      image_7

      Step 2.

      Allow DevTools access to the folder you’ve just added.

      image_8

      Step 3.

      Your newly added folder will appear in the sidebar navigation.

      image_9

      Right-click on a file within a network resourced folder in the Sources Panel (make sure it has an obvious mapping to a file on your file system) and select Map to File System Resource.

      image_10

      Step 4.

      The first suggestion provided by DevTools is the correct one. It has noticed that the file on my file system (/Users/.../bootstrap.css) has the same name as a network resource file (http://localhost/.../bootstrap.css). Verify the mapping by selecting the correct resource.

      image_11

      DevTools now understands the mapping between filesystem resources and network resources. When you Cmd/Ctrl-Click a selector from the Styles pane and end in the Sources Panel, you’re now being shown your actual LESS source file. You can edit a file in the Sources panel and those changes will persist to disk when you Command/Control+S.

      We’ve come all this way, so let’s complete this workflow by using a Grunt watch task to watch for changes made to the LESS files and then automatically compile our CSS and make a corresponding Source Map file.

      Using Grunt to Watch & Compile LESS

      With Workspaces set up, configure Grunt (or another tool of your choice) to watch for changes to LESS source files and compile a new CSS file (with a Source Map). DevTools will pick up this change automatically and apply any new styles to the page.

      Note: Enable the Auto-reload generated CSS flag in the Settings panel to use this workflow.

      image_12

      Here is an outline of the automated steps which will occur:

      1. You save a change to a LESS file via DevTools.
      2. A watch task monitors LESS files for changes and then runs a LESS task.
      3. The LESS task compiles a new CSS file plus a Source Map file.
      4. DevTools injects the new CSS file onto the current page without a page refresh.

      Here’s a simplified Gruntfile:

      module.exports = function(grunt) {
          'use strict';
      
          require('matchdep').filterDev('grunt-!(cli)').forEach(grunt.loadNpmTasks);
      
          grunt.initConfig({
              less: {
                  dev: {
                      options: {
                          sourceMap: true,
                          sourceMapFilename: 'bootstrap.map'
                      },
                      files: {
                          'less/bootstrap.css': 'less/bootstrap.less'
                      }
                  }
              },
              watch: {
                  all: {
                      files: ['less/**/*.less'],
                      tasks: ['less'],
                  }
              }
          });
      
          grunt.registerTask('default', ['less', 'watch']);
      };
      

      Note: The code snippet above comes from the demo repository.

      After an npm install, running grunt in your terminal should show a watch task running.

      image_13

      DevTools already has write access to your development folder (through Workspaces). Cmd/Ctrl+S your changes in the Sources Panel to have DevTools overwrite the source LESS file with your new change, Grunt compiles a new CSS file which DevTools pulls in and applies to the page.


      Conclusion

      • During development and debugging, looking at your source file (rather than the compiled file) will almost always be more useful to you.
      • For DevTools to understand source file mappings, it needs to be compatible with the Source Map v3 proposal which is up to the compilation tool to implement.
      • Tools adopting Source Maps are improving, we have Sass, Compass, LESS, autoprefixer, UglifyJS2, CoffeeScript and more. There are grunt-contrib-* tasks for most of these tools (Sass, Compass, LESS, autoprefixr, UglifyJS2, CoffeeScript) which tie in nicely with a livereload workflow.
      • Viewing LESS files will work out of the box with DevTools. To actually edit files, try out Workspaces which gives you the ability to persist changes to disk.

      Further Reading

      Source Maps

      LESS

      Chrome DevTools

       

      0 Comments

      Leave a comment › Posted in: Daily

    1. Ember.js Testing

      When I started playing around with Ember.js almost a year ago, the testability story left something to be desired. You could unit test an object without any trouble, but a unit test is only one way to get feedback when you’re building a software product. In addition to unit tests, I wanted a way to verify the integration of multiple components. So like most people testing rich JavaScript applications, I reached for the mother of all testing tools, Selenium.

      Now before I bash it, without a proper introduction, it’s worth mentioning that Selenium is a great way to verify your entire web application works with a full production-like database and all your production dependencies, etc. And from a QA perspective, this tool can be a great resource for teams who need end-to-end UI acceptance tests.

      But over time, a seemingly small test suite built on Selenium can begin to drag the velocity of your team to a snails pace. One easy way to reduce this pain is to avoid building a large application in the first place. If you build a handful of smaller web applications instead, it might help keep you afloat for a little longer because no individual build will crush the team, as you grow.

      But even on a small project, the real problem with Selenium is that it’s not part of the test driven development process. When I’m doing red/ green/ refactor I don’t have time for slow feedback in any form. I needed a way to write both unit and integration tests that would provide quick feedback to help me shape the software I was writing in a more iterative way. If you are using a version of Ember.js >= RC3, you’re in luck because writing a unit or integration test is a walk in the part.


      Installing the Test Runner

      Now that we can write JavaScript tests for our application, how do we execute them? Most developers start out using the browser directly, but because I wanted something I could execute headless from the command line in a CI environment with a rich ecosystem full of plugins, I looked to Karma.

      What I liked about Karma is that it only wants to be your test runner. It doesn’t care what JavaScript test framework you use or what client side MVC framework you use. It’s simple to get started with and writing tests that execute against your production Ember.js application is just a few lines of configuration.

      But before we can configure Karma, we need to install it using npm. I recommend installing it locally so you can keep your npm modules isolated per project. To do this, add a file named package.json‘ to the root of your project that looks something like the below.

      {
        "dependencies": {
          "karma-qunit": "*",
          "karma": "0.10.2"
        }
      }
      

      This example will require both Karma, and a plugin for QUnit. After you save the package.json file above, drop back to the command line and type npm install to pull down the required Node modules.

      After the npm install completes, you will now see a new folder with the name node_modules in the root of your project. This folder contains all the JavaScript code we just pulled down with npm, including Karma and the QUnit plugin. If you drill down even further to node_modules/karma/bin/ you will see the Karma executable. We will be using this to configure the test runner, execute tests from the command line, etc.


      Configure the Test Runner

      Next we need to configure karma so it knows how to execute the QUnit tests. Type karma init from the root of the project. You will be prompted with a list of questions. The first will ask what testing framework you want to use, hit Tab until you see qunit, then hit Enter. Next answer no to the Require.js question, as we won’t be using it for this sample application. Tab until you see PhantomJS for the third question and you will need to hit Enter twice as it allows multiple options here. As for the rest, just leave them at their default option.

      When you are done, you should see Karma has generated a configuration file named karma.conf.js in the root or your project. If you want to read more about the various options Karma supports, you might find the comments helpful. For the sake of this example, I have a simplified version of the configuration file to keep things beginner friendly.

      If you want to follow along, delete the generated configuration file and replace it with this one.

      module.exports = function(karma) {
        karma.set({
          basePath: 'js',
           
          files: [
            "vendor/jquery/jquery.min.js",
            "vendor/handlebars/handlebars.js",
            "vendor/ember/ember.js",
            "vendor/jquery-mockjax/jquery.mockjax.js",
            "app.js",
            "tests/*.js"
          ],
           
          logLevel: karma.LOG_ERROR,
          browsers: ['PhantomJS'],
          singleRun: true,
          autoWatch: false,
            
          frameworks: ["qunit"]
        });
      };
      

      This should be fairly similar to what Karma generated earlier, I’ve just removed all the comments and cut out a few options we don’t care about right now. In order to write the first unit test, I had to tell Karma a little more about the project structure.

      At the top of the configuration file, you will see that I’ve set the basePath to js because all of the JavaScript assets live under this folder in the project. Next, I told Karma where it can find the JavaScript files required to test our simple application. This includes jQuery, Handlebars, Ember.js and the app.js file itself.


      Writing the First Unit Test

      Now we can add the first unit test file to the project. First make a new folder named tests and nest it under the js folder. Add a file in this new directory named unit_tests.js that looks something like this.

      test('hello world', function() {
        equal(1, 1, "");
      });
      

      This test isn’t doing anything valuable yet, but it will help us verify we have everything wired up with Karma to execute it correctly. Notice in the Karma files section, we already added the js/tests directory. This way Karma will pull in every JavaScript file we use to test our application with, going forward.

      Now that we have Karma configured correctly, execute the qunit tests from the command line using ./node_modules/karma/bin/karma start.

      If you have everything setup correctly, you should see Karma execute one test and it being successful. To verify it executed the test we just wrote, go make it fail by altering the equals statement. For example, you could do the following:

      test('hello world', function() {
        equal(1, 2, "boom");
      });
      

      If you can fail this and make it pass again, it’s time to write a test with a little more purpose.


      The Sample Application

      But before we get started, lets discuss the sample application used throughout this post. In the screenshot below, you see we have a very simple grid of users. In the HTML table, each user is shown by first name along with a button to delete that user. At the top of the application you will see an input for the first name, last name and finally a button that will add another user to the table when clicked.

      https://dl.dropboxusercontent.com/u/716525/content/images/2013/pre-tuts.png

      The example application has three problems. First, we want to show the user’s first and last name, not just the first name. Next, when you click a delete button it won’t actually remove the user. And finally, when you add a first name, last name and click add, it won’t put another user into the table.

      On the surface, the full name change appears to be the simplest. It also turned out to be a great example that shows when you should write a unit test, an integration test or both. In this example, the quickest way to get feedback is to write a simple unit test that asserts the model has a computed property fullName.


      Unit Testing the Computed Property

      Unit testing an ember object is easy, you simply create a new instance of the object and ask for the fullName value.

      test('fullName property returns both first and last', function() {
        var person = App.Person.create({firstName: 'toran', lastName: 'billups'});
        var result = person.get('fullName');
        equal(result, 'toran billups', "fullName was " + result);
      });
      

      Next if you go back to the command line and run ./node_modules/karma/bin/karma start, it should show one failing test with a helpful message describing fullName as undefined currently. To fix this, we need to open the app.js file and add a computed property to the model that returns a string of the combined first and last name values.

      App.Person = Ember.Object.extend({
        firstName: '',
        lastName: '',
        fullName: function() {
          var firstName = this.get('firstName');
          var lastName = this.get('lastName');
          return firstName + ' ' + lastName;
        }.property()
      });
      

      If you drop back to the command line and run ./node_modules/karma/bin/karma start you should now see a passing unit test. You can extend this example by writing a few other unit tests to show that the computed property should change when either the first or last name is updated on the model.

      test('fullName property returns both first and last', function() {
        var person = App.Person.create({firstName: 'toran', lastName: 'billups'});
        var result = person.get('fullName');
        equal(result, 'toran billups', "fullName was " + result);
      });
      
      test('fullName property updates when firstName is changed', function() {
        var person = App.Person.create({firstName: 'toran', lastName: 'billups'});
        var result = person.get('fullName');
        equal(result, 'toran billups', "fullName was " + result);
        person.set('firstName', 'wat');
        result = person.get('fullName');
        equal(result, 'wat billups', "fullName was " + result);
      });
      
      test('fullName property updates when lastName is changed', function() {
        var person = App.Person.create({firstName: 'toran', lastName: 'billups'});
        var result = person.get('fullName');
        equal(result, 'toran billups', "fullName was " + result);
        person.set('lastName', 'tbozz');
        result = person.get('fullName');
        equal(result, 'toran tbozz', "fullName was " + result);
      });
      

      If you add these two additional tests and run all three from the command line, you should have two failing. To get all three tests passing, modify the computed property to listen for changes on both the first name and last name. Now if you run ./node_modules/karma/bin/karma start from the command line, you should have three passing tests.

      App.Person = Ember.Object.extend({
        firstName: '',
        lastName: '',
        fullName: function() {
          var firstName = this.get('firstName');
          var lastName = this.get('lastName');
          return firstName + ' ' + lastName;
        }.property('firstName', 'lastName')
      });
      

      Add the Karma-Ember-Preprocessor and Configure It

      Now that we have a computed property on the model, we need to look at the template itself because currently we don’t use the new fullName property. In the past, you would need to wire up everything yourself, or use Selenium to verify the template gets rendered correctly. But with ember-testing you can now integration test this by adding a few lines of JavaScript and a plugin for Karma.

      First open the package.json file and add the karma-ember-preprocessor dependency. After you update the package.json file, do npm install from the command line to pull this down.

      {
        "dependencies": {
          "karma-ember-preprocessor": "*",
          "karma-qunit": "*",
          "karma": "0.10.2"
        }
      }
      

      Now that you have the pre-processor installed, we need to make Karma aware of the template files. In the files section of your karma.conf.js file add the following to tell Karma about the Handlebars templates.

      module.exports = function(karma) {
        karma.set({
          basePath: 'js',
          
          files: [
            "vendor/jquery/jquery.min.js",
            "vendor/handlebars/handlebars.js",
            "vendor/ember/ember.js",
            "vendor/jquery-mockjax/jquery.mockjax.js",
            "app.js",
            "tests/*.js",
            "templates/*.handlebars"
          ],
          
          logLevel: karma.LOG_ERROR,
          browsers: ['PhantomJS'],
          singleRun: true,
          autoWatch: false,
           
          frameworks: ["qunit"]
        });
      };
      

      Next we need to tell Karma what to do with these handlebars files, because technically we want to have each template precompiled before it’s handed over to PhantomJS. Add the preprocessor configuration and point anything with a file extension of *.handlebars at the ember preprocessor. Also you need to add the plugins configuration to register the ember pre-processor (along with a few others that normally get included with Karma’s default configuration).

      module.exports = function(karma) {
        karma.set({
          basePath: 'js',
           
          files: [
            "vendor/jquery/jquery.min.js",
            "vendor/handlebars/handlebars.js",
            "vendor/ember/ember.js",
            "vendor/jquery-mockjax/jquery.mockjax.js",
            "app.js",
            "tests/*.js",
            "templates/*.handlebars"
          ],
           
          logLevel: karma.LOG_ERROR,
          browsers: ['PhantomJS'],
          singleRun: true,
          autoWatch: false,
           
          frameworks: ["qunit"],
           
          plugins: [
            'karma-qunit',
            'karma-chrome-launcher',
            'karma-ember-preprocessor',
            'karma-phantomjs-launcher'
          ],
           
          preprocessors: {
            "**/*.handlebars": 'ember'
          }
        });
      };
      

      Integration Testing the Data-Bound Template

      Now that we have the Karma configuration setup for integration testing, add a new file named integration_tests.js under the tests folder. Inside this folder we need to add a simple test to prove we can stand up the entire Ember.js application without error. Add a simple qunit test to see if we can hit the '/' route and get the basic HTML returned. For the initial test, we are only asserting that the table tag exists in the HTML that was generated.

      test('hello world', function() {
        App.reset();
        visit("/").then(function() {
          ok(exists("table"));
        });
      });
      

      Notice we are using a few helpers that are built into ember-testing like visit and find. The visit helper is an ember friendly way of telling the application what state to be at during the execution. This test starts at the '/' route because that is where the People models get bound to the template and our HTML table is generated. The find helper is a quick way to lookup elements in the DOM using CSS selectors like you would with jQuery to verify something about the markup.

      Before we can run this test we need to add a test helper file that will inject the test helpers and set a generic root element. Add the code below, to a file named integration_test_helper.js in the same tests directory. This will ensure our application has the test helpers at execution time.

      document.write('<div id="ember-testing-container"><div id="ember-testing"></div></div>');
       
      App.rootElement = '#ember-testing';
      App.setupForTesting();
      App.injectTestHelpers();
      
      function exists(selector) {
        return !!find(selector).length;
      }
      

      Now from the command line you should be able to execute the integration test above. If you got a passing test, remove the table from the handlebars template to make it fail (just to help prove Ember was generating the HTML using that template).

      Now that we have the integration tests setup, it’s time to write the one that asserts we show each user’s fullName instead of their firstName. We want to first assert that we get two rows, one for each person.

      test('hello world', function() {
        App.reset();
        visit("/").then(function() {
          var rows = find("table tr").length;
          equal(rows, 2, rows);
        });
      });
      

      Note: The application is currently returning hard coded data to keep everything simple at the moment. If you are curious why we get two people, here is the find method on the model:

      App.Person.reopenClass({
        people: [],
        find: function() {
          var first = App.Person.create({firstName: 'x', lastName: 'y'});
          var last = App.Person.create({firstName: 'x', lastName: 'y'});
          this.people.pushObject(first);
          this.people.pushObject(last);
          return this.people;
        }
      });
      

      If we run the tests now, we should still have everything passing because two people are returned as we would expect. Next, we need to get the table cell that shows the person’s name and assert it’s using the fullName property instead of just firstName.

      test('hello world', function() {
        App.reset();
        visit("/").then(function() {
          var rows = find("table tr").length;
          equal(rows, 2, rows);
          var fullName = find("table tr:eq(0) td:eq(0)").text();
          equal(fullName, "x y", "the first table row had fullName: " + fullName);
        });
      });
      

      If you run the above test you should see a failing test because we haven’t yet updated the template to use fullName. Now that we have a failing test, update the template to use fullName and run the tests using ./node_modules/karma/bin/karma start. You should now have a passing suite of both unit and integration tests.


      Should I Write Unit or Integration Tests?

      If you are asking yourself, “when should I write a unit test vs. an integration test?”, the answer is simply: what will be less painful? If writing a unit test is faster and it explains the problem better than a much larger integration test, then I say write the unit test. If the unit tests seem less valuable because you are doing basic CRUD and the real behavior is in the interaction between components, I say write the integration test. Because the integration tests written with ember-testing are blazingly fast, they are part of the developer feedback cycle and should be used similarly to a unit test when it makes sense.

      To show a CRUD like integration test in action, write the following test to prove the add button puts the person into the collection and that a new row gets rendered in the handlebars template.

      test('add will append another person to the html table', function() {
        App.Person.people = [];
        App.reset();
        visit("/").then(function() {
          var rows = find("table tr").length
          equal(rows, 2, "the table had " + rows + " rows");
          fillIn(".firstName", "foo");
          fillIn(".lastName", "bar");
          return click(".submit");
        }).then(function() {
          equal(find("table tr").length, 3, "the table of people was not complete");
          equal(find("table tr:eq(2) td:eq(0)").text(), "foo bar", "the fullName for the person was incorrect");
        });
      });
      

      Start by telling the test what state you want to work with, then using the fillIn helper, add a first name and last name. Now if you click the submit button it should add that person to the HTML table, so in the returning then we can assert that three people exist in the HTML table. Run this test and it should fail because the Ember controller isn’t complete.

      To get the test passing, add the following line to the PeopleController

      App.PeopleController = Ember.ArrayController.extend({
        actions: {
          addPerson: function() {
            var person = {
              firstName: this.get('firstName'),
              lastName: this.get('lastName')
            };
            App.Person.add(person);
          }
        }
      });
      

      Now if you run the tests using ./node_modules/karma/bin/karma start it should show three people in the rendered HTML.

      The last test is the delete, notice we find the button for a specific row and click it. In the following then we simply verify one less person is shown in the HTML table.

      test('delete will remove the person for a given row', function() {
        App.Person.people = [];
        App.reset();
        visit("/").then(function() {
          var rows = find("table tr").length;
          equal(rows, 2, "the table had " + rows + " rows");
          return click("table .delete:first");
        }).then(function() {
          equal(find("table tr").length, 1, "the table of people was not complete
        });
      });")})})
      

      To get this passing, simply add the following line to the PeopleController:

      App.PeopleController = Ember.ArrayController.extend({
        actions: {
          addPerson: function() {
            var person = {
              firstName: this.get('firstName'),
              lastName: this.get('lastName')
            };
            App.Person.add(person);
          },
          deletePerson: function(person) {
            App.Person.remove(person);
          }
        }
      });
      

      Run the tests from the command line and you should once again have a passing suite of tests.


      Conclusion

      So that wraps up our sample application. Feel free to ask any questions down in the comments.

      Bonus: But I’m Already Using Grunt…

      If you prefer to use Grunt instead of the karma-ember-preprocessor, simply remove the plugins and preprocessors configuration. Also remove templates/*.handlebars from the files section as Karma won’t need to precompile the templates. Here is a simplified karma.conf.js that works when using grunt to precompile the handlebars templates.

      module.exports = function(karma) {
        karma.set({
          basePath: 'js',
       
          files: [
            "lib/deps.min.js", //built by your grunt task
            "tests/*.js"
          ],
          
          logLevel: karma.LOG_ERROR,
          browsers: ['PhantomJS'],
          singleRun: true,
          autoWatch: false,
           
          frameworks: ["qunit"]
        });
      };
      

      And that’s it!

       

      0 Comments

      Leave a comment › Posted in: Daily

  • Page 1 of 18 pages  1 2 3 >  Last ›
  • Browse the Blog

    Syndicate

    governing-bruise