Angular JS – 10 (End to End Testing – Karma)

In the previous blog we looked at what is need to build a end to end test and run those test manually. In this blog, we will see how we can run this automatically in the background. The good thing is, there is nothing special end to end testing rather how you run it. Hopefully you got something from my previous blog on how to write an end to end test.

If you haven’t gotten the Intro to Karma project from GitHub, please do get it. It has the sample code and everything needed to run automated end to end test. Couple of things you need to run end to end test using Karma. You need a web server so in our case we will be using ‘node’. If you do not have it, please install it. Once you have node, you need to install Karma. Now that we have the sample code and required components like node and Karma, lets see how we can run Karma to test end to end tests.

To run karma, one would need a configuration file. Now if you got the introduction to karma project  from the GitHub then it comes with a simple configuration file. We will use that to run the end to end test. So lets first run the test with the configuration file already in the project. It is a two step process to do automated end to end tests.

  • Start the node server. Navigate to the location of the project. From the root directory, in DOS/terminal

node test\scripts\web-server.js

  • Now that node is running, lets run the Karma in another DOS/terminal from the root location of the project

karma start config\karma-e2e.conf.js

After the two steps, the test should run only once, it will not wait for code change and keep running the tests. We will modify that little later.

image

If you notice, we run Karma pointing to Karma.e2e.conf.js. Lets look at the configuration file.

1 basePath = '../'; 2 3 files = [ 4 ANGULAR_SCENARIO, 5 ANGULAR_SCENARIO_ADAPTER, 6 'test/e2e/**/*.js' 7 ]; 8 9 autoWatch = false; 10 11 browsers = ['Chrome']; 12 13 singleRun = true; 14 15 proxies = { 16 '/': 'http://localhost:8000/' 17 }; 18 19 junitReporter = { 20 outputFile: 'test_out/e2e.xml', 21 suite: 'e2e' 22 }; 23

The complete documentation of the configuration file can be found in the Karma documentation. Lets look at this simple configuration file.

Line 1: This is to set the base path for all the file references. I always like to make the base path to the root of the project. In this case, the karma configuration file is sitting @ config folder under the root folder so we will change one directory to the root directory.

Line 3-7: specifies what are the files to use for running the tests, Line 3-5 are default values. Line 6 specifies where is the end to end test.

Line 9: This option specifies, if you want to continue watch the files for any changes. In our case it is ‘false’, which means, it will run only once and it will not continue watching for any changes.

Line 11: Which browsers will be used for end to end tests.

Line 13:  This one is critical. This option specifies, do you want to run the test only once or run once and run and wait for changes the run automatically. So to run the end to end test automatically in the background as you are developing is by setting this ‘false’ and also Line 9 and set the value to ‘true’.

Advertisements

Angular JS – 9 (End to End Testing – manual)

Continuing from the previous blog, lets look at end to end testing. Based on what you have seen so far, it is very obvious without telling, how easy it to test Angular JS. The true separation of view and controller lend itself to test controller very easily. Everything is injectable which makes everything mockable in Angular JS. Now that we know, we can test controller with ease with Jasmine and Karma. Lets look at the other cool testing we can do in Angular, which is End To End test.

Angular End to End test allows the developer to do UI testing. This allows developer to enter values directly in the DOM elements and perform operations and then validate the results. This have been a difficult task so far with other client technologies and Angular JS made it easy for us. These end to end tests are called scenario tests. Angular follows Jasmine model of writing tests for end to end test as well.

If you have not already downloaded the Intro to Karma from Github, please download and we will use the same code to go over the end to end test.

There are two ways one could run end to end test. The first approach is to create your test and run the test manually and verify if the tests are passing. The second approach is to have the test run automatically in the background all the time while you developing your application and writing the tests. With this approach there is no need to run the test every time one would make a change to the code or tests. We will review the first approach in this blog.

Manual Test:

First lets look at the test we are going to write. Our application is very simple, it takes two numbers, multiplies and show the result on the screen as shown below

image

Since we are doing the UI testing, lets see the view under test.

1 <table> 2 <tr><td>First Number</td><td><input type="text" ng-model='firstNumber'/></td></tr> 3 <tr><td>Second Number</td><td><input type="text" ng-model='secondNumber'/></td> 4 <td><button ng-click='Multiply(firstNumber, secondNumber)'>Multiply</button></td> 5 ><td><input type="text" ng-model='decimals'/></td></tr> 6 <tr><td>Result</td><td>{{result | number: decimals}}</td></tr> 7 </table>

The two input fields are bound to ‘firstNumber’ and ‘secondNumber’, so in our test, we need to enter values for those two fields. Then find the button and click the button. Which would then perform the multiplication and save the result to ‘result’. So to confirm our UI code worked properly, we need to verify if ‘result’ contains the expected result. With this knowledge lets look at the test. The end to end test is available under test\e2e\mainscenario.js

As I mentioned before, end to end test also borrowed testing pattern from jasmine where we describe what we are testing and before each test and after each test, one could perform some task. All tests where marked by ‘it’. So going back to the test we were going to do;

1 it('should multiply two numbers', function(){ 2 input('firstNumber').enter(2); 3 input('secondNumber').enter(2); 4 element(':button').click(); 5 expect(binding('result')).toEqual('4.00'); 6 });

Line 1: starts the test with ‘it’, followed by two parameters, first one is the description of the test, followed by the test itself.

Line 2: Find the input for ‘firstNumber’ and enter value ‘2’.

Line 3: Find the input for ‘secondNumber’ and enter value ‘2’.

Line 4: Find the only button and click the button to perform multiplication.

Line 5: Find the ‘result’ and verify the result is ‘4.00’. Even though when we multiply 2 * 2 is 4, by default the decimal digit is set to 2 and result ‘4’ is send to number filter so the result becomes ‘4.00’.

When we do end to end test, we are testing the html page, so before each test, we need to make sure, the browser is pointing to the page under test. To do that, one need to define the beforeEach or at the start of each test. In our case, we define a beforeEach to route to the index.html as shown below

1 beforeEach(function(){ 2 browser().navigateTo('../../app/index.html'); 3 });

Line 2: has ‘../../app/index.html’. This is very important. To run, end to end test, one need to run the a web server first. Since I will be using node and the web server script is at test/script, it is very important you run the web server first from this location as follows

node test\scripts\web-server.js

now if you follow the line (2), what we are doing is, trying to find index.html from app folder two directories up from web-server.js location. That’s why we have the navigation. If web-server.js placed in root directory, then our navigateto would be ‘app/index.html’.

With node server is running, we need to create a html file to run our end to end script. It will be very simple script, we need to point to angular-scenario.js script and also our end to end script that’s all about it. So here is our runner.html file

1 <!doctype html> 2 <!-- to run e2e make sure you are running your web server --> 3 <!-- in our example we run node test/scripts/web-server .js --> 4 <!-- also open browser and point to http://localhost:8000/test/runner.html --> 5 <!-- we need to make sure we run node same way when we run the e2e test in command line as well --> 6 <html lang="en"> 7 <head> 8 <title>End2end Test Runner</title> 9 <script src="lib/angular-scenario.js" ng-autotest></script> 10 <script src="e2e/mainscenario.js"></script> 11 </head> 12 <body> 13 </body> 14 </html>

Please read step 2-5 in the html file to make sure everything is setup.

Now launch Chrome and point to the url in line 4 and that is it. You will have your end to end test run.

image

If you get the above screen then you are all set. In case if you run into problem, then you might not have one or more of the following not setup properly as mentioned in ng-model website. Also please try with Chrome do not try with IE.

Refactor C# code using Action<T> or Func

Currently we are using Sonar to identify the health of our application. One of the code metric it gives is duplicate code. I was going through the code along with one of my colleague and found out that most of the code can be easily refactored except some complicated one.  We ran into a scenario where everything is same except some where in the middle the block of code is different. We were debating to split the common code in separate methods or use some strategy pattern to solve it. But then I remembered about C#’s nifty Action<T> and Func. So in this case, we refactored the whole method into a common method, except the small code block nested inside the code as an Action<T> and pass it to the common method.

Here is a very simple example on how to use Action<T>; we have two action methods, one (line 5 – 9) will display numbers from 0 to x, where x is the parameter passed in and the second (line 11 – 14) just display the number passed it

 

1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Action<int> singleLoop = new Action<int>(p => 6 { 7 for (int i = 0; i < p; i++) 8 Console.WriteLine(i); 9 }); 10 11 Action<int> singleWrite = new Action<int>(p => 12 { 13 Console.WriteLine(p); 14 }); 15 16 PrintValue(singleLoop, 10); 17 PrintValue(singleWrite, 5); 18 Console.ReadKey(); 19 } 20 21 private static void PrintValue(Action<int> singleLoop, int param) 22 { 23 Console.WriteLine("starting"); 24 singleLoop.Invoke(param); 25 Console.WriteLine("ending"); 26 } 27 } 28

As you can see from this example, you can inject the code snippet inside the code block based on which every logic you feel warranted. Func behave the same way, except, Action takes parameters but does not return a value back, on the other hand, Func returns a value.

Hope this helps someone.