Monday, February 6, 2017

AngularJS Tutorial: AngularJS Controller As Syntax

Introduction to AngularJS Controller As Syntax


In the previous installment of this series we discussed scopes and what problems nested scopes can cause. There are a couple of solutions to this problem: the so-called Controller As syntax introduced by AngularJS 1.2 and .component() method introduced by AngularJS 1.5. The latter option is a recommended way to go if you are thinking about upgrading your application to newer Angular versions. In this post we’ll talk about AngularJS Controller As syntax.

As was mentioned previously, when we instruct Angular to use a controller with the ng-controller directive, a new instance of a controller and a child scope is created. Alternatively, the same directive but with a different syntax can be used to create a controller and to attached it to a newly-created scope as the snippet below shows.


The differences are that, first, in the ng-controller directive we not only pass the name of the registered controller, but also, a variable name for an instance of the controller; vm stands for ViewModel but a more meaningful name can be used and we’ll talk about it later. Second, when we use double curly braces or the ng-model directive, we use vm.myModel to access to the variable defined in the controller. The following snippet shows how a controller using Controller As syntax looks like.


It differs from the version using $scope; we don’t pass the $scope variable to our controller, so there is also no necessity to add code that copes with minification. Also, we create the vm variable and store the value of this it it to prevent future problems when working with this. The most important point here that all the variables and methods are created inside the vm object; this helps to clear scope from our data and methods. The visualization of AngularJS scopes obtained by Batarang is shown in the following picture.



The fact that we don’t pass $scope to our controller doesn’t mean that it is impossible. In fact, $scope has useful methods and if we decide to use them we can pass $scope to our controller. The idea is to store everything we create in a special vm object. To stress once again how Controller As syntax is used by AngularJS I’ll show you an example of a controller’s test that relies on it.


Now we create a new $scope using $rootScope in order to rely on JavaScript prototypal inheritance and use scope methods. Also, we obtain the aforementioned root scope inside beforeEach method and use Controller As syntax to obtain an instance of our HelloController from the $controller() function. Finally, inside the it() method, we obtain our data using scope.

A more succinct version of the controller’s test that doesn’t rely on AngularJS scope is shown below.


After we’ve refactored our code, we could make sure that we haven’t broken anything and this could be accomplished using Protractor. A single problem is that we extract some elements by their model but now it is vm.myModel, not myModel. After ironing out this wrinkle launching Protractor e2e tests should end up in success.

AngularJS Nested Scopes


After we’ve introduced AngularJS Controller As syntax, it’s high time to see how it helps solve the nested scope problem. The HTML snippet below shows how to use the syntax in this case. While it’s possible to name each controller as vm because each of the controllers attached to a different scope, we use more clear names for controllers to prevent name collisions.


The code for controllers is similar to the above one for HelloController and can be found here. The scopes look like in the pictures below. The first is for the parent scope.



And the second one is for the child scope.



Testing is done in the similar way to the HelloController and test examples can be found here. Also, is we talk about end-to-end testing using Protractor, it is easier to extract elements by their model because the latter contains the name of the controller, so we don’t need to manipulate arrays of elements with the same model name.

Summary


In this tutorial we learned how to use AngularJS Controller As syntax. In the next post we’ll talk about AngularJS components introduced by version 1.5.


Resources

Sunday, February 5, 2017

AngularJS Tutorial: Introduction to AngularJS Scopes

Introduction to AngularJS Scopes



In the previous tutorial of this series we learned how to test controllers using Jasmine and Karma. In this post we discussed how data is passed from controller to view using $scope, which is the glue that links model and view. In this tutorial we’ll talk more about scopes, what are some possible pitfalls in using them, and later we’ll talk about the ways to overcome possible problems, as well as get over Batarang, a Chrome extension from AngularJS team, which can be used to analyze scopes inside an AngularJS application.


By adding the ng-app directive to some HTML tag we specify that an AngularJS will be created and in the process of application creation Angular creates the so-called root scope. Some other directives such as ng-controller create a child scope. To visualize scopes one can use a Google Chrome extension called Batarang. The picture below shows the root scope for the AngularJS application and the child scope created by HelloController, which contains a single variable myModel.





What if we created another controller, say to work not with greetings but farewells and that controller would contain a variable with the same name as in HelloController? It is possible to have  variables with the same name that belong to different scopes. The snippet below shows the code for our GoodbyeController. While variables have the same name, the content is different.




Now we should add another section to our index.html file and attach a controller to it as shown below.




It should be noted that it’s necessary to add the link to the controller’s code to the HTML file. The source code for this tutorial can be found here. Now we have two scopes inside the root scope, each of which was created by one of the two controllers, which is depicted in the following images.





The myModel variable in the scope of the first controller has the value ‘World’ and the value ‘Everyone’ in the scope of the second controller.





When we write tests for our second controller, the code is pretty much the same as in the first case, but things are different with e2e tests because we extracted elements by their model and now we have two models with the same name. To solve this problem one should replace a piece of code that finds a single element


element(by.model('myModel'))


by the code that extracts the list of elements with the same model name and then specify the position of the desired element in the list.


element.all(by.model('myModel')).get(1)


Nested AngularJS Scopes



A more complex case is shown by the following snippet of code when we have an article nested in a section and each of them has its own controller.




In each of the controllers we have variables with the same name, myModel. The code for the parent controller is shown below.




Also, each controller has a variable specific to it. The following snippet show the code for a child or nested controller.




Now we can use Batarang to explore scopes. We see that the myModel variable in the parent scope has the value different than in the child scope as shown by the screenshots below.





Also, we have access to the variable created in the parent scope inside the child scope as can be seen from the web page.





The explanation of the fact that we have access to a variable created in the parent scope from inside the child scope is that parent and child scope are linked with JavaScript Prototypal Inheritance relationship, which means that when the onlyParent variable is not found in the child scope, JavaScript looks for it in the parent, parent of a parent, etc. scopes.


The question is whether we can access the value of the myModel variable defined in the parent scope from the child scope. The answer is yes and this can be accomplished by the snippet of code shown below.


<p>{{$parent.myModel}}</p>


The takeaway from this post is that AngularJS scopes are difficult to work with because AngularJS directives may create their own scopes and variables defined in a parent scope can be hidden by the ones defined in child scopes. This can be error prone but there are some best practices that help one to avoid this kind of problems.


Summary


In this tutorial we talked about scope creation and how to visualize scopes using a Chrome extension called Batarang. Also, we talked about nested scopes and to what problems that could lead as well as how to do end-to-end testing in this case. In the next tutorial we’ll talk about the best practices that allow to avoid problems with AngularJS nested scopes.


Resources

  1. JavaScript Inheritance and the Prototype Chain

Monday, January 30, 2017

AngularJS Tutorial: Unit Testing Angular Applications Using Jasmine and Karma

In the previous installment of this series we’ve learned how to perform End-to-End application testing using Jasmine and Protractor. In this part, we’ll discuss how to test controllers and how to automate this process. In fact, running tests manually may make the whole process tedious and may prompt one not to use tests altogether, so we’ll learn how to make test run in background and restart when you save your code.



Adding Karma to AngularJS project


As a first step, we’ll add test automation to our project. To streamline testing of Angular applications, Google created a special test automation framework called Karma which in turn can rely on various testing frameworks such as Jasmine and run tests any time you save a file in your project. To add Karma and other tools necessary for testing to the project it is necessary to execute the following command.

npm install karma karma-jasmine karma-chrome-launcher jasmine-core angular-mocks --save-dev

We added several development dependencies simultaneously. After that, we should configure Karma and the configuration file, karma.conf.js is created by issuing the command shown below.

node_modules/.bin/karma init

The picture shows all the answers that were given during the initialization process.


Here is the karma.conf.js configuration file file.


The most important part to pay attention to is the files array. There we enumerate all AngularJS files, then all our code files to be tested and tests after that; order is important. Also, to run tests on save we set the values of autoWatch to true and singleRun to false; single runs can be used by a Continuous Integration system.


Refactoring the application code to follow AngularJS style guide


Currently, the code that creates our module and the one that creates the controller reside in the same file, namely app.module.js. According to Angular 1 style guide, we should split the code according to its functionality, that is we’ll put the code of our HelloController into a separate hello folder inside the app folder. Controller is placed into the file named hello.controller.js because it’s a naming convention to describe the purpose of code using a suffix, such as controller.

Now, we copy all the code from the app.module.js file and paste it to the hello.controller.js file. After that, we remove square brackets and comma from the module() function because the former are necessary to create a module but we, here, need to add a controller to an existing module.


In app.module.js we leave only the code to create our module.


Finally, we should add the file containing the controller to index.html before the closing body tag and after our other scripts.


Here is the moment where we can use Protractor to check that we haven’t broken our application after refactoring. As an experiment, you can comment out the recently-added script from the index.html file and see what happens.


Adding and running Jasmine tests for AngularJS controller


Now, we are ready to add a test for our controller. According to AngularJS Style Guide the test should be placed into the same folder where our controller lives. The name of the test file, according to the guide is the same as the one of the controller, followed by the spec suffix and js extension.

Our algorithm for testing is first, to load our module before each test, second, to inject the controller, our system under test, and finally, to check that the controller works correctly. The code for the test is shown below.


The test file contains a single test that checks that the word ‘World’ was set as a value of the myModel variable in the controller. Generally, controllers will contain more complex logic and there will be more tests, but here we try to keep the example as simple as possible. Anyway, we described the variables to store an instance of our controller under test and a variable to pass instead of $scope and see what the controller adds to it.

The code to obtain the instance of the controller and to initialize the scope variable is placed into beforeEach() method which means that the initialization is performed before each test method and test methods does not influence each other because they use brand new instances of the controller and scope.

In the snippet above, we load the app module in the beforeEach() method and then retrieve the controller. It allows us to test the desired unit of code, namely the controller, so the name of such kind of tests is unit tests.

Now, we should change our karma.conf.js file and specify what files we need to be loaded to test our controller. The content of the files array is shown below.


To run the test execute the following command.

node_modules/.bin/karma start

And here is the result, the tests have successfully passed.


The command we run to start test is too long to type, so we can use npm to make it shorter, namely we could edit the package.json file and change the test command it contains. Inside the file, look for the scripts object and we’ll change the content of the test field from

"test": "echo \"Error: no test specified\" && exit 1",

to

"test": "node_modules/.bin/karma start",

After that change, it’s enough to type

npm test

to start testing our files; Karma will watch changes in our files as it was mentioned above.


Summary


In this tutorial we added unit tests for our controller and automated their execution using the test runner Karma from Google. Also, we learned some best practices of naming files and organizing our code. In the next tutorial we’ll discuss AngularJS scope in more detail, learn how to use Google Chrome extension called Batarang to analyze scopes and go over some best practices for writing code in your controllers.




Resources
  1. AngularJS Templates, section Testing Non-global Controllers
  2. Seed Project for AngularJS apps, Karma configuration



Friday, January 13, 2017

AngularJS Tutorial: Introduction to End-to-End Testing of AngularJS Applications using Jasmine and Protractor

Introduction to software testing



In the previous installment of this series we discussed how to create a simple Hello World application using AngularJS. In this tutorial you will start learning how to streamline the development process and would tools Angular offers to the developers.


When project is under active development, new features are often added to it and some previously created features are modified. It is possible that some application functionality is broken in the process. To prevent this from happening, it is a good idea to check how all the functionality works after modifications but that could be difficult because one should remember all the cases for all the features added since the beginning. Also, it’s tedious to manually place your application into various conditions and see if it works, so one can rely on automation, that is one can record all the tests in a format that computers can understand and delegate the menial task of testing to a computer.


Checking if previously added features work after modifying the code is called regression testing and it allows to streamline the development process as the bugs can be spotted and squashed immediately after making changes. In addition, testing can be used in the process of development. For instance, if one is tasked to write a function that formats a date or converts currencies, it is not necessary that the whole application be deployed and test data be added via application Graphical User Interface. One can create a test to run a specific function and check the results returned by it in various conditions. Such test are called unit tests as they test the smallest possible part of code and using tests for development purposes can be used for Test-Driven Development (TDD) and Behavior-Driven Development (BDD).


Furthermore, application can consist of various parts such as authentication subsystem, database access part, subsystems that access external systems etc. and we need to check how several parts work together. In this case we deal with Integration Testing with checks if small number of application parts work well together. If we check the entire application we talk about System or End-to-End (e2e) testing.


Our application is very simple, the are not many parts to it, so we can use e2e tests to check that it works as intended. Namely, we can check that the default value of our greeting is produced when the application starts and that it changes as desired if some text is added to the input field. To accomplish this task we’ll rely on special tools, namely on Jasmine framework, a JavaScript framework that allows to specify tests in a language that computer can understand and Protractor, a testing tool created by the AngularJS team, which allows one to check the data produced by our application in a browser, change values in input fields and obtain the output results to check its correctness by the test framework.


Getting to know Jasmine


Jasmine is defined as a BDD framework on its site and is widely used to test JavaScript code. First, we have to install Jasmine. This is accomplished using the following command.


npm install jasmine-node -g


Now, we’ll place our End-to-End test inside a special e2e subfolder in the main folder of our project. A Jasmine test consists of so-called test suits - a number of related test with verbal description, e.g. ‘fun with numbers’. Each test with a description is called a specification and a suit contains several specifications or specs. The code for simple tests is shown below.




To create a suit one uses a describe() function which takes a string description of a suite and another function as its parameters. Specs are created using it() function with same argument types.


Each test contains one or more expectation which are specified using expect() function and matchers toEqual() an toBe() functions in our case which checks that the actual result is the same as desired.


To run the tests one should execute the following.


jasmine-node e2e/.


If the expected result are altered, Jasmine reports errors.


To prevent VS Code from reporting errors in our specs, one should modify ESLint settings in the .eslintrc.js as follows.




We added the jasmine plugin and specified the "env" value.


In addition. One can add Jasmine-specific ESLint rules by running the command below.


npm install eslint-plugin-jasmine --save-dev


Protractor for end-to-end testing



Protractor is a Node.js End-to-End testing framework which relies on Selenium, a testing framework written in Java. The latter means that one should install JDK before trying to install Protractor. To install Protractor one should run the following command.


npm install protractor -g


After that, it is necessary to update webdriver manager.


webdriver-manager update


Now we need to start a server.


webdriver-manager start


Before running tests we should configure Protractor; a sample configuration file protractor.conf.js is shown below.



Here we specified that our test framework is jasmine, obtained the Selenium server address from the command window where we started the server and specified the location of our test files.


Now, it’s time to add a test.




First, we define a variable that we’ll pass to the name input field. Second, we define a handle to an input element with model ng-model; we’ll use the handle to set the value into the input field. A new feature here is the beforeEach() function that is used to connect to our application; this function is called before each spec. Finally, we have three tests.


The first one checks the title of the window. The second reads the value from the input field and checks that it equals to the default value. The last one clearcs the value of the input field using clear() method, after that, then() method is called, which waits until the value is cleared and then sets the new value to the input field and checks that the correct greeting is produced.


To start the test it is necessary to start our AngularJS application and to type the following in the CLI.


protractor protractor.conf.js


Summary



In this tutorial we started the discussion about how to test AngularJS applications using Jasmine and Protractor. As can be seen, e2e speeds up testing in comparison with manual testing. On the other hand, things can become too slow for a more complex application. In the next tutorial we’ll learn how to split the application into more manageable and testable parts, best practices of accomplishing this task and other methods of application testing mentioned in this tutorial.


Resources