Lessons Learned: Upgrading an Enterprise Angular App

July 23, 2015
Reading Time: 2 minutes

I recently completed an upgrade for an Enterprise Angular app from 1.2.24 to 1.3.15. Doing an upgrade on a large system is no small undertaking. Finding solutions to resolve upgrade incompatibilities can seem like a bit of black magic at times. This upgrade was no exclusion to just that.

The most common error I got was Error: $rootScope:infdig Infinite $digest Loop. Staring at these errors in the console all I could think about was how on earth was I going to fix them?! With a codebase that’s more than 45k lines for just the front end, I start questioning if I’m going to be able to even do this, if I’m a good enough developer, etc. The typical Imposter’s Syndrome that’s so prevalent in this line of work.

This error typically gives you 0 hints what’s causing it, and where it’s coming from, but I found some resources that helped me realize that anything that has a watcher needs to be Idempotent in AngularJS. If it’s not, it could be the source of an infinite digest loop.

So I thought rather than make a long write up of all the different pieces I solved in my project, I thought I’d supply the main resources that I had to read and understand in order to solve different errors. Let’s face it, all projects will be different, but the overall upgrade challenges I’d assume are going to be relatively similar. Here’s the list:

Scope Work

http://stackoverflow.com/questions/13743058/how-to-access-the-angular-scope-variable-in-browsers-console

https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply()

Infinite Digest

https://github.com/angular/angular.js/issues/705 (Idempotent – Important to know for usually fixing Infinite Digest Errors)

http://stackoverflow.com/questions/20567614/errors-in-angularjs-often-causes-infinite-loops

http://stackoverflow.com/questions/17466872/infinite-loop-with-angular-expression-binding

http://stackoverflow.com/questions/21322755/tracking-down-infinite-digest-errors

http://stackoverflow.com/questions/24592283/angular-infinite-digest-loop

Filters

http://stackoverflow.com/questions/25877704/what-is-stateful-filtering-in-angularjs

http://stackoverflow.com/questions/27402326/angularjs-1-3-async-filter-not-working

Grep/Ack Tricks

http://stackoverflow.com/questions/9081/grep-a-file-but-show-several-surrounding-lines

Enhanced performance is a major upgrade that you get when going from 1.2.x to 1.3.x. If you make sure your filters aren’t stateful and you start setting up all two-way data bindings that never change to use the ‘::’ one time binding syntax you can quite easily supercharge an app with performance issues. Feel free to connect with me if you have any particular difficult bug that you’re trying to fix during an upgrade.

Unit Testing Full Stack Part 2 – AngularJS Part 1 of 3

July 16, 2015
Reading Time: 6 minutes

This is part 2 of my multi part guide for setting up and testing a full stack JavaScript application. Next up is AngularJS. I’ve broken this up into 3 separate parts, as this is a bit more complex for testing the front end, since we have both unit tests and end to end tests. The parts will be broken up as follows:

Part 2A – Installation, Routes, Controllers

Part 2B – Services, Directives, Filters

Part 2C – Coverage Reports, End to End (e2e)

Installation & Configuration

To get started, install the following:

Karma (test runner) in conjunction with Jasmine (unit testing framework). You can use other unit testing frameworks, if you so desire, just check here, under ‘Framework’, to see which ones are compatible.

So let’s start with our AngularJS project, with npm, it will install both karma, the jasmine plugin and the chrome launcher plugin, as well as any required dependencies for those packages.

Something to be aware of, is that because Angular runs in the browser, it requires the chrome browser to launch when running tests, so that they can execute. This will launch and destroy a chrome browser for you automatically, but if you’re not wanting to have a browser launch, you can use PhantomJS for everything to be just run in a headless browser (A browser engine without any graphical interface, it runs in memory only).

Once these are complete, you’re next goal is configure karma to run through the tests for us. To do this, we need to create a configuration for Karma. Navigate to your /test directory and we’ll type (where karma-unit.conf.js is the name of the configuration file):

You’ll be asked a series of question (see here), once done, you will inevitably go into the Karma configuration itself and setup the correct order for loading your project files under the ‘files’ property array. This will probably take looking at your own projects index.html file and making sure that the files are all there and in proper order. Everything source file that you use in your project will need to be loaded this way, and again, in proper order.

To do the unit tests, you will also need to load the angular-mock file. This allows us to mock the backend requests over http, as jasmine doesn’t actually process async calls to an api properly. So be sure to add that file to your files array. Here’s a link you can add to the array for the angular-mock.js file form the google api CDN, for v1.2.26:

My files array looks like this:

As you can tell, it has some wildcard symbols there, where ** means all sub-folders and * means all files, and in my file, *.js means all files ending in .js. So these are all of the files included in the testing.

Next up are the plugins. My plugins looks like:

I have a few extra karma packages installed, if you’d like to use them, you can npm install them. karma-ng-html2js-preprocessor makes it possible to inject a directive template into the tests for testing. karma-mocha-reporter is the type of report that gets generated that I like, and finally karma-coverage is a coverage reporting tool built on istanbul.

Finally, here are the preprocessors, reports, and coverageReporter configs:

I need to configure the preprocessor details for both ng-html2js and the coverage plugin, and configure the coverage reporter output details.

Finally, we’re ready to start writing some tests.

Once we write tests, we can run the tests by typing:

Routes

I have my route test spec file in /test/unit-angular/routeSpecs/routeSpec.js.

I need to create the file just like any typical mocha test, with the describe, beforeEach, it, etc. functions. So a very basic route spec file will look like this:

Going through this, is pretty straight forward. we need to inject the different services location, route and rootScope. The inject function also ignores the surrounding ‘_’ for the service names. This is just to help readability within the test file. Now we can use these services in the tests themselves.

Any request made to any server requires us to use the $httpBackend to intercept the expected call and return what response the that should be expected.

In order to navigate, you need to use location.path(…) and follow it up with a manual call to $digest().

This is pretty much the entire pattern for testing your different routes. If your application requires you to login in order to test routes, you will need to create the objects, etc. to simulate a user logging. Remember, since it’s not actually making any calls to a server, you don’t need to worry about a token being authenticated, etc. Those kinds of tests should be run as unit tests against the API and/or end to end tests.

Controllers

I place my controllers in /test/unit-angular/controllerSpecs/<ctrlName>ControllerSpec.js.

Testing controllers is also fairly straight forward, but requires understanding a few important concepts.

1) We have to manually create and setup the scopes for the controllers we want to test.

2) You need to perform $httpBackend.flush() after we want to perform the $httpBackend calls in controllers.

Here’s a sample controller spec file:

The beforeEach is a bit more complex for the controller:

As you can see, I create the new controller and bind the scope to it by first creating the new scope with $rootScope.$new() and then setting it for the manual dependency injection with the $controller service {$scope: scope}.

Following this, I prefer to test all of the functions in a controller to be sure that they’re defined before I start testing them.

If the application is refactored, just realize if the function changes name or is removed, you’ll need to keep your controller test files current.

Finally, testing the actual scope functions is required. You’ll need to setup any $httpBackend expected calls first before you test the scope function, otherwise you’ll get errors for unexpected $http calls.

 

Any required objects for the scope function should be passed in at this time as well so that the function runs properly.

You can see how in the one test I try and use an empty object, and what I expect the api to respond with.

The rest comes down to just writing test coverage for all of your controllers functions based on different scenarios. Time to write your test plans! 🙂

Next part in this series we’ll cover the Services, Directives and Filters. We’ll go in-depth with testing Directives, importantly, for how to test their isolate scopes and functions.

I hope you enjoyed the read, and let me know if you find any issues with the above so that I can edit any mistakes.

AngularJS Error: $compile:multidir Multiple Directive Resource Contention

May 12, 2015
Reading Time: 1 minute

I recently had been working on an upgrade from 1.2.x to 1.3.x branch of AngularJS for this project I’ve been working on.

While doing this, I got this error:

Clicking on the link the Chrome console brought me to the AngularJS page giving me more details on the error thrown. It said that two different directives had a conflict with each other.

However, the code snippet gave me about 0 details, and the information was still, while something, a bit archaic.

The notes on the page mention to do a few different things to resolve it:

I checked the first scenario, and it wasn’t the case for the directive. I removed the third scenario, and it still was thrown. Next I checked to see if there was a directive naming conflict with ack:

Scrolling through the list to look at the filenames, I noticed that a third party library had the exact same name as one of my directive names. Building the library to not include that filename resolved my issue, and after a few more bug fixes, I successfully upgraded my app to the 1.3.x branch. It’s a LOT faster! I highly suggest upgrading your app as soon as possible.

If you would like to read the full write up of lessons learned which includes more of the issues I ran into, as well as a pretty solid list of the different resources I used to resolve many of the upgrade issues read this post: http://www.stephenbero.com/lessons-learned-upgrading-an-enterprise-angular-app-from-1-2-x-to-1-3-x/

Unit Testing Full Stack Part 1 – node/io.js with express

April 6, 2015
Reading Time: 2 minutes

This is going to be a multi-part series of posts to detail my current process for unit testing a full stack javascript application. Consider this my brain dump of information that I’ve either found from others posts, found in the official documentation or I’ve just been doing it that way because it makes sense in my head.

Unit testing has to be one of the most important aspects for any developer that’s serious about their work to start doing, and be disciplined enough to continue doing it regardless of some of the mind-numbing aspects of it.

Starting off we will be establishing the testing procedure for our javascript backend, which consists of node/io.js using express to serve up our restful api. I was shocked once I finally got everything working properly, with how easy it was to get going.

You will need to npm install the following modules:

  • mocha
  • supertest
  • chai

These are the only modules necessary to do all your assertion/expect testing.

Once installed, I would suggest creating a test folder at the root of your application directory. Inside of this directory I will typically split groups of tests for each Controller in my application. Ending up with something like this:

The controller specs should be setup something like this:

Now with that setup, you can just run from your project root, from the command line:

and it will watch all test files for changes and run all your tests again, if a change is detected.

That’s all there is to it for getting true automatic testing going for your existing or next express api.

The next post will be for how to properly setup testing for the angular end of your application.

Node, Express and { [Error: socket hang up] code: ‘ECONNRESET’ }

March 29, 2015
Reading Time: 1 minute

I’m not sure how many scenarios this issue would crop up in, but I wanted to at least post about the one that I found:

This happens on my iojs/express api that I’m working on, and trying to do a file upload test with mocha and supertest.

If you are doing something like this:

.attach() is not compatible with .send().

You need to remove .send() and put that data into .field() function calls like this:

Doing this completely resolved the { [Error: socket hang up] code: ‘ECONNRESET’} error that I was receiving.

Hope this helps anyone with the same issue.

Revise Your Release Schedule!!

February 7, 2015
Reading Time: 2 minutes

Why in the world do people/companies/etc. release on Fridays? It makes no sense from a time or problem solving perspective.

Consider this: You spend an entire sprint or two preparing the next set of app updates, to only find out after pushing it into production that there is a critical bug that was uncovered. Now, if you’ve setup your production environment correctly, you more than likely are able to rollback to the previous release with the use of Capistrano or some other tool. If you haven’t, well, then your developers and QA get an enjoyable weekend of not having a weekend 🙂

I highly suggest any serious company looking to minimize their employees stress, to do releases on Tuesday mornings. You get nearly the entire week to fix any issue and push the changes back out to production before the weekend without sacrificing your employees time off. There won’t be any disrupting your employees personal lives anymore than they already are, so as a result your employees will be happier.

The mindset of releasing on Friday’s I think is because of this innate human condition to want some type of closure at the end of something, such as the work week. Where-in you can release it, and then goof off the rest of the day at work, unless there is an issue in production then you know you may have no weekend and still have to work on Friday. I think most people can agree that actually breaking many of our psychological habits, are what will make us better at what we do, and be better poised to move forward with what we’re working on.

Just because something is what’s always been done, or something is the norm, doesn’t make it better or even the best solution. And in this scenario, I think it’s a horrible solution.

Node/ExpressJS Can’t Set Headers Bug…Possible solution

February 1, 2015
Reading Time: 1 minute

I was working on some of my more complex project aspects today, after spending an entire weekend setting up, and building out most of my applications unit and end-to-end tests when I noticed this issue when I moved onto the new build features inside of the Angular app:

Possibly unhandled Error: Can’t set headers after they are sent.

I’m scouring the code EVERYWHERE. How is this possible? According to my unit tests, I have code coverage across all of these functions with literally every permutation of tests imaginable, or did I???

Upon further inspection, I noticed that my AngularJS front end was making two identical calls to my API. This simultaneous connection request was enough to throw the error in the Node/ExpressJS backend.

tl:dr; – Check to be sure your AngularJS / Front End isn’t making simultaneous calls incorrectly to your API/Backend.

JavaScript Design Patterns

December 9, 2014
Reading Time: 1 minute

While in the process of needing to add some more complex functionality to my current ordering system project, I knew that I needed to start tackling the implementation for a number of design patterns for the front end. I finally took the time over the weekend to sit down and learn the ones that I needed to use and incorporated them with a basic AngularJS/Bootstrap/JQuery template.

Removing everything but exactly what I was trying to accomplish made understanding and implementing the patterns much more reasonable, as well as efficient.

I created a github repo to put them into in the event anyone else is looking to actually learn some design patterns in JavaScript as well. Check it out here:

https://github.com/SBero/JavascriptPatterns

I’ve so far implemented the following patterns:

  • Factory
  • Command
  • Memento
  • State
  • Strategy
  • Visitor
  • Chaining
  • Lazy Load

Hope this helps anyone out there looking to implement the same things themselves.

 

CORS OPTIONS Mind Bender

November 22, 2014
Reading Time: 2 minutes

So I finally got time to jump back onto my personal project for my next startup, and must say I ran into quite the issue. Because my API is setup and deployed on my server, I’m required (because of AJAX) to do OPTIONS requests, which upon success, will follow up with the actual request on success.

But something went wrong.

I thought, maybe I changed a configuration file or there’s some bug. Looked in the application logs, as well as the apache logs. Nothing.

I googled every possible permutation that came to my mind for what mind show me some possible idea as to what in the world was happening. Mind you, all other requests (GET, POST, PUT, DELETE) were all working correctly. But I needed OPTIONS to work for my application. I reviewed all the apache and program configurations.

In total, I spent probably 3-4 hours on this. Did curl requests to only get an error (52) empty response. It finally dawned on me that something had to be interfering with my connection. I wasn’t even getting a response from the server, but since the other responses worked, I knew the server was working.

I finally stumbled upon this information on Ben Nadel’s site: http://www.bennadel.com/blog/2559-cisco-anyconnect-vpn-client-may-block-cors-ajax-options-requests.htm

During the week I installed Cisco AnyConnect so that I could get my company vpn working on my macbook without having to use their laptop, which just slows me down from sometimes doing what I need to do. Uninstalling Cisco AnyConnect completely fixed my issues instantly!!!

I’d never felt so relieved in my life! After losing a better portion of the day, I finally was back in the position to start making headway on my application.

Hope this can help anyone who comes across it.

I’m also adding my list of googled search terms in the event anyone else has the same issue, but hasn’t found the right fix yet:

apache header set access-control-allow-origin “*”

apache Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at

chrome OPTIONS (failed) net::ERR_EMPTY_RESPONSE

cors not working in apache

apache no response from OPTIONS

apache not adding allow-headers

htaccess access control allow origin not working

apache options request failed

apache options request empty response

OPTIONS curl Empty reply from server

 

Unable to connect to local XAMPP installation over the LAN

October 29, 2014
Reading Time: 1 minute

I’ve only had this problem on OSX after I recently upgraded to v1.8.3-4 and v1.8.3-5 on OSX Yosemite. It may exist on Linux and Windows, however, it may not.

I could always connect to my local installation over my LAN when it’s running until I 1) Upgraded to OSX Yosemite, and 2) Upgraded XAMPP. Googling the issue returned me 0 results. It wasn’t until I attempted to connect to the XAMPP installation, BEFORE I changed the default document directory in Apache that I was confronted with the area to look for a solution.

In the file: /Applications/XAMPP/xaamppfiles/etc/extra/httpd-xampp.conf – Lines 59 – 65

59 # New XAMPP security concept
60 #
61 #
62 #<LocationMatch “^/(?i:(?:xampp|security|licenses|phpmyadmin|webalizer|server-status|server-info))”>
63 # Require local
64 # ErrorDocument 403 /error/XAMPP_FORBIDDEN.html.var
65 #</LocationMatch>

Comment these out and restart apache. You’ll then be able to remotely connect to the installation.

I’m sure some people may have an issue with this being commented out, but if I care, I can just stop the apache service if I’m on a public network, and/or just uncomment these sections.

My current workflow requires me to cross browser tests from about 5 different OS’ and multiple browsers on each, so I need to have LAN access to my local XAMPP installation.

Hope this helps anyone else wondering what in the world the problem is.