The Router Function

Now that we’ve got a failing test, we can write the router function. To get our router test to pass, we have to add three things. We need to create a view container in the markup to give the router a place to add the views. We need to create the showView function and have it create a minimal version of the problem view. Lastly, we need to create a namespace where our router function—and the rest of our application—can live. Once those things are complete, we’ll have the first version of our router in place. All it will be able to do is switch from one view to another, but that’s a good start.

Since our test is complaining about not being able to find the learnjs namespace, we’re going to start with that.

Creating a Namespace

You might be wondering why we need a namespace at all. While we could define showView by itself, when building our application we must avoid accidentally using function and variable names that are already defined in the global scope. We call these name collisions, and they can be a real problem. By containing our application in a namespace, we can prevent name collisions and ensure our app works with current and future browsers.

The JavaScript runtime environment provided by all major browsers includes a number of different APIs. To access these APIs, browsers define a window object as a sort of top-level entry point. You can reference this object to make API calls. For example, you can get the current URL by calling window.location.toString(), and you can programmatically navigate in the browser by assigning window.location to a URL string.

In addition to being the access point for the browser APIs, the window object is the container for all global variables. This is convenient in that you don’t have to prefix all of your API calls with window, because they are essentially global. For example, in place of using window.location.toString(), you can use location.toString(). Unfortunately, this also means that any global names you create might collide with names in the APIs. Even if you’re sure that your current names won’t collide, it’s hard to predict what new APIs browser makers will introduce.

Fortunately, there’s a simple way to avoid this problem. We can create a namespace for our application. A namespace is just a JavaScript object that we can use to hold the parts of our application. This namespace is the first thing we’ll add to our app.js file.

 'use strict'​;
 var​ learnjs = {};

See? Nothing to it. This simple but powerful technique provides some structure to our application and helps avoid name collisions. We can add our application’s functions and variables to this object without having to worry if our application names will collide with names on the global window object, or any global names defined by any of our libraries.

We’ve also included the ’use strict’; statement here to tell the browser to enforce stricter rules when evaluating our JavaScript. This means that rather than ignoring problems, we’ll get a nice error telling us what went wrong. Since we’ve put this statement at the top of app.js, we’re only enforcing strict mode for our code and any code loaded after it.

Adding the Router Function

Our test is still failing, but now that we’ve created a namespace for our application, the error message is different.

 1 spec, 1 failure
 LearnJS can show a problem view
  TypeError: learnjs.showView is not a function

Here, the test is complaining that learnjs.showView isn’t a function. That’s true…it’s undefined,[25] because we haven’t created it yet. We have two more steps to make our test pass, and this is one of them. Since our test is complaining about not being able to find the showView function, we’ll do that next.

This means the first function we’ll add to our application namespace will be the showView() function. In this function, we’ll use jQuery to select the view-container element and append the view markup to it. We haven’t created a separate function for the problem view yet, so to start, we’ll just hard-code this function to append a <div> with the problem-view class, because that’s all this test requires. We’ll add the showView() implementation to our namespace in app.js.

 'use strict'​;
 var​ learnjs = {};
 learnjs.showView = ​function​(hash) {
 var​ problemView = $(​'<div class="problem-view">'​).text(​'Coming soon!'​);
  $(​'.view-container'​).empty().append(problemView);
 }
Joe asks:
Joe asks:
Am I Really Going to Create the View Markup Like This?

Although it’s possible—and sometimes useful—to create markup dynamically with jQuery, creating large amounts of markup with nothing but jQuery can be a bit tedious. The first implementation of showView() does this, but this implementation isn’t going to last long.

When this is added, the failure message of our test changes:

 1 spec, 1 failure
 LearnJS can show a problem view
 Expected 0 to equal 1.

You want to avoid adding anything else to the problem view at this point. You’ll add functionality to it later (with tests). For now, you need to focus on driving out the behavior of the router. The good news is, you’re getting closer, because the assertion in our test is now failing as you expect.

Creating a View Container

Before, this test was raising JavaScript errors. Now it’s actually failing the assertion. All the code is executing without error; it’s just that the test sees zero elements when it expected one. These are the kinds of failures we want out of our tests. They’re specific, and they lead us to what we need to do next.

In this case, although our showView function is creating and appending markup, there’s no view container in the page for it to append it to, so when we call jQuery’s append function, the markup goes nowhere. To fix this, we’re going to have to make two changes to our markup. We’ll have to create the view container. We’ll also need to introduce a new element into our application that will give our tests access to the markup in our application.

Right now, our tests have no way to access the markup in our app. The test runner at tests/index.html is a different document than our app in index.html. There’s a way to bring them together, but we’re going to need to add something to our app to do it.

In our prepared workspace, our test runner has a file named public/tests/SpecHelper.js. This file has some code that copies any markup in our application that’s contained in an element with the markup class. It then takes that markup and appends it to the body of the test runner’s page, making it available to all of our tests. To make our view container—and all of our application’s markup—visible from our tests, you need to create this element.

While you’re doing this, you also need to add the view-container class to the <div> with the Skeleton container class on it. We’re going to make this our view container element. Since we’re making our view container a Skeleton container, our views can create their markup with rows and columns from the Skeleton grid, knowing that the content will be placed properly in a container.

Once you make both of these changes, the <body> of our application’s index.html file will look like this:

 <body>
  <div class=​'markup'​>
  <div class=​'view-container container'​>
  <div class=​'row'​>
  <div class=​'one-half column'​>
  <h3>Learn JavaScript, one puzzle at a time.</h3>
  <a href=​''​ class=​'button button-primary'​>Start Now!</a>
  </div>
  <div class=​'one-half column'​>
  <img src=​'/images/HeroImage.jpg'​/>
  </div>
  </div>
  </div>
  </div>
 </body>

Once you save that change, our test should run.

 1 spec, 0 failure
 LearnJS can show a problem view

Now our test is passing! We’ve taken some important steps here. We’ve written our first automated test and made it pass. We’ve created a router function that lets our application navigate between multiple views without reloading. We’ve created a view container that all of our views can use to enclose their markup. Lastly, we’ve made all of our application markup visible to our tests, making it easy for us to test our views and their UI elements.

If you don’t feel comfortable writing Jasmine tests yet, don’t worry. We’ve only started to use them in our app, so you don’t need to be an expert. Rather than having me spend a lot of time telling you everything Jasmine can do for you, let’s move forward, and you’ll see what it can do along the way. The tests are important to us, and while we expect to get back much more value than the effort we put in to writing them, we want to stay focused on building our app. After all, you don’t make customers happy by writing tests; you make them happy by delivering software that excites and delights them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.79.250