Which version of Magento should I use? This will help you decide

A brief guideline that will help you to choose which version of Magento to use and if you’re on V1 identify if it’s a good idea to migrate your current store to V2.

Overview

Magento is one of the most widely used eCommerce platform today. It has two major versions: 1.x and 2.x. You find yourself asking the question: which one should I choose?

Image from Alan Kent’s slideshare

This would be easy to answer when you’re starting a new project: pick the one with the latest version. But what do you do with an active Magento 1 project? You should ask yourself the question of..  Do you migrate or not?

In this post I will try to bring a guideline that will help with this decision process.

Why should I migrate to Magento 2?

Unfortunately, there is no simple answer to this question as there are list of advantages and disadvantages for both versions. However, I will provide a list of pros and cons that will help you to select the best option for the project you work on.

Pros and cons

Let’s start with advantages of Magento 2

  • The Backend Admin is Designed for Non-Technical Users

The new default theme, “Luma”, provides an eye-catching theme that is drastically improved compared to the previous “Madison Island” theme.

 

  • Improved flexibility

The new platform structure has improved flexibility which consists of high code coupling, enabling developers to create complex features such as checkout, SMS, CRM, and sales.

  • Better code underneath the hood with real unit testing

With a completely overhauled codebase, created with reliable composer packages, the entire application is now covered by unit tests. This greatly improves stability and should put your mind at ease when upgrading.

  • Integrates with Popular Payment Gateways

Magento 2 is able to integrate with many of the popular payment processors, such as PayPalWorldPay, and Cybersource.

  • It is user-friendly

The Magento 2 checkout process is better streamlined, making it easier and quicker for customers to navigate through from the cart to the completed order than Magento 1. The customizable checkout now requires less customer information and steps, therefore it reduces the checkout time, increases sale conversions and minimizes abandoned carts.

  • Improved scalability and performance

Studies have shown that a one-second delay in page load time can result in a 7% loss in sales conversions. Magneto 2 runs approximately 20% faster than Magento 1, which can lead to improved SEO and increased sales. All of the content from a static page can be cached, thus increasing site performance and drastically reducing the server load. This makes the Magento 2 platform more scalable for large eCommerce stores.

But there’s still some disadvantages

  • Magento 1 themes can’t be ported

Magento 1 themes cannot be transferred to Magento 2, it will need to be built from scratch, making it an expensive endeavor.

  • Not All Extensions Are Available Yet

Unfortunately if you are already using extensions for Magento 1, unfortunately, you cannot port them into Magento 2. You’ll need to purchase the extensions and integrate them into your Magento 2 platform, also add to your overall costs.

  • Enterprise Edition Cost Rises

Although Magneto Community Edition (CE) remains free, for the Enterprise Edition (EE) a single license has increased in price from $18,000 to $22,000 per year.

  • It still has A Steep Learning Curve

All that flexibility comes at a cost, and the cost is time. You can manipulate the platform to your heart’s content, but getting over that steep learning curve is already going to be a big obstacle for any developer already unfamiliar with Magento and how it works.

  • … and hosting it can still be tricky

Dedicated file servers that can be configured to Magento’s hosting requirements absolutely must be employed, adds to the true cost of using Magento.

How to migrate

Have you decided to migrate from Magento 1 to Magento 2?

Based on Magento official documentation,  a best practice to perform migration consist in two main steps:

  1. Build and test new Magento 2
  2. Migrate four components: data, extensions, themes, and customizations.

Step 1: Build and test Magento 2

To prepare for the migration, make sure you do all of the following:

  • Set up a Magento 2.0 system using a topology and design that matches your existing Magento 1 system
  • Provide back-up of your Magento 1.x database in case of unexpected issues. We advise you to replicate your Magento 1.x database and use this Magento 1.x data for your migration
  • Install Magento 2 on a system that meets our system requirements

Next steps

Follow the links below to learn more about each of the four components.

  • Theme Migration: Since themes cannot be migrated directly, there are two options provided by official documentation: you can pick an existing theme or work with a front-end developer to create a new theme based on your current theme.
  • Extension Migration: Most of third party extensions providers offer to updated version of the product. In case you want to migrate an extension created by yourself, just refer the next paragraph.
  • Customizations Migration: Most of the code wrote for Magento 1 is compatible with Magento 2, but for those customizations that need a migration, Magento provides a Code Migration Toolkit.
  • Data Migration: Data Migration allows you to migrate several types of data from your Magento 1 store to Magento 2 store. There is a CLI tool that will help you with the process, Data Migration Tool.

Conclusion

As I mentioned above, there is no right answer in choosing between the two versions of Magento as there are advantages and disadvantages to each Magento. If you are about to start a new project, I strongly encourage you to pick the latest, it is optimized to be used with PHP 7 + and nginx server and you will be able to enjoy the goodies of this product. And if you already has a Magento 1 store, sooner than later you will have to move forward, my advise is prepare a good plan for migration and go ahead, you always can outsource this process to an agency like Arroyo Labs.

I’m glad you’re still here! Thank you for reading this post. Please leave us with questions and feedbacks if there are any! Our future post will be about an example of extension migration.

Creating an AngularJS Feature Module with exported components & routing

Creating feature models in Angular JS is a powerful way to create re-usable software. How you expose the module is a very important step. We’ll explore some of the common ways to extend and modify co

Intro

The AngularJS framework is built upon the promise of modularity and we should always strive to write reusable code when applicable. The easiest way to accomplish this is by creating feature modules to encapsulate your services and components.

If you have been following along with our AngularJS series you will know that we have recently spent some time turning an application we created with Angular CLI into a feature module that we have published on npm. If you have missed them, feel free to read up here: Part One, Part Two.

In the code we discussed in our previous posts we explicitly exported our components & services for re-use (you can see this code here) in this post we will talk about why we did this and how to use this exported code. We will talk about how to extend and overload the exported routes and how to extend the provided components so you can add functionality after you import a feature module.

Scope & Encapsulation of your Feature Module

One of the biggest advantages to creating a feature module is that you can encapsulate your services from the parent application. This gives us a whole namespace to work inside and keeps the parent application free from some random services.

Exporting Routes

Routing is a VERY integral part of an AngularJS application because as your application becomes more complex, so will your routing scheme. There are two ways of getting routes contained in your feature module to the parent app module:

  • Lazy Loading
  • Exporting the feature module routes as another module

Plenty has been written on the subject of lazy loading, so I would like to focus on the second option.

This snippet illustrates our feature routing module:


import { AuthGuard } from './auth.guard';
...
import { UserListComponent } from './user-list/user-list.component';
...
// clang-format off
const userAdminRoutes = [
  ...
  {
    path: 'list',
    canActivate: [
      AuthGuard
    ],
    component: UserListComponent
  },
  ...
];
// clang-format on

export const UserAdminRouting = RouterModule.forChild(userAdminRoutes);

And this is how we export the routing module (in an explicit way) so we can use this in our parent application:


export { UserAdminRouting } from './src/user-admin.routing';

Exporting also allows you to add some routing on top of this exported module as well.

Here’s another snippet showing how we import this into our module and add a route not present in this routing definition:


import { NotFoundComponent } from './not-found/not-found.component';

// clang-format off
const appRoutes: Routes = [
  { path: '**', component: NotFoundComponent }
];
// clang-format on

export const AppRouting = RouterModule.forRoot(appRoutes, {
useHash: false
});

We can provide routes not originally provided by the package we import by adjusting the order of our imports. This is most easily explained by an example:


...
import { AppRouting } from './app.routing';

import { UserAdminRouting } from '@erdiko/ngx-user-admin';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    UserAdminRouting, // Import the package routes
    AppRouting // import our application routes
  ],
  providers: [
    ...
  ],
bootstrap: [AppComponent]
})
export class AppModule { }

Over-riding your routes with resetConfig

In the example above we show how you can add a route to your module’s exported routes if one does not exist. While this is great, this does not help you overload a route config module that already exists. What if you wanted to replace the “Home” route with a new component, or you wanted to redirect a user when they attempt to go to a route you wish to deprecate? Enter the “resetConfig” method.

This method, which the current AngularJS documentation that leaves something to be desired to say the least, allows you to “reset” your route config and push in new route definitions! If this sounds clunky, that’s because in my opinion it is, but this appears to work well. Let’s take a look at a snippet that improves upon the example above:


// Import Router and Route into your component
import { Router, Route } from '@angular/router';

// Import the component we wish to overload the existing route config
import { NotFoundComponent } from './not-found/not-found.component';

...

export class AppComponent implements OnInit {

// make sure we inject the router into this component
constructor(private router: Router) {

}

ngOnInit() {

 /**
  * Define a new route to overload the existing one for 'list' so
  * we can show the "Not Found" as an example.
  *
  * PLEASE NOTE: cast the object to a Route before attempting to add
  * this to your list of routes
  *
  */
  let r: Route = {
    path: 'list',
    component: NotFoundComponent
  };

  /**
   * call the resetConfig method and push in your newly defined route.
   *
   */
  this.router.resetConfig([r, ...this.router.config]);

  }

}

Here is what the route looks like based on the import routing config from `ngx-user-admin`:

Now here is the route after we use ‘resetConfig’ to overload it to display a component created in our Angular app:

Please note that this example shows a very simple example route defined in a component. It is good practice to move route definitions like this into a separate file for inclusion.

Exporting Components for reuse

It’s always a great practice to be explicit in what you expose to the parent application from your feature module. In most cases, you are creating a feature module to wrap a series of components and related services. The parent application really only needs to have the components exposed for use in its module.

Here is an example where we demonstrate exporting some components from our UserAdmin feature module in `ngx-user-admin`:


@NgModule({
  imports: [
    ...
  ],
  declarations: [
    ...
  ],
  exports: [
     HeaderComponent,
     LoginComponent,
     HomeComponent,
     ...
  ],
  providers: [
    ...
  ]
})

As you see above, we explicitly export our components exactly what we want to expose to the parent application.

Let’s take a look at the snippet below as a practical example of extending a feature module component and route config:

Here we create a new component to extend the existing feature module HomeComponent:


import { AppRouting } from './app.routing';

import { UserAdminRouting } from '@erdiko/ngx-user-admin';

// create a new component we created to extend the ngx-user-admin HomeComponent
import { MyhomeComponent } from './myhome/myhome.component';

@NgModule({
  declarations: [
    AppComponent,
    NotFoundComponent,
    // Include our new component
    MyhomeComponent
  ],
  imports: [
    // include the feature module
    UserAdminModule.forRoot(),
    
    // include the feature module routing defintion
    UserAdminRouting,
    AppRouting
  ],
  providers: [
  
  ],
  // add your new component as an entry point to the application

  // so the routing can access it
  bootstrap: [AppComponent, MyhomeComponent]
})
export class AppModule { }

From the previous example where a new route was created, we overload the “home” route to use the new component below. Now take a look at this new snippet where we overload the “home” route to use a new component:


ngOnInit() {

/**
* Define a new route to overload the existing one for 'Home' so
* we can use our newly extended component instead of the one from
* the feature module
*/
let r: Route = {
  path: '',
  component: MyhomeComponent
};

this.router.resetConfig([r, ...this.router.config]);

}

And finally here is our new component definition where we extend the feature module provided component:


import { Component, OnInit } from '@angular/core';

import { HomeComponent } from '@erdiko/ngx-user-admin'

@Component({
  ...
})
export class MyhomeComponent extends HomeComponent {

}

Here is what the “home” route looks like based on the import routing config from `ngx-user-admin`:

Here is what the “home” route looks like after we extend and overload the routing config:

Conclusion

As you develop Angular applications you will find yourself creating modules to encapsulate feature sets, common utilities and even define basic routes. How you export your code for use is dependent on your application and certainly affects how you can extend these for use in other AngularJS applications.

Introducing Erdiko User Admin v1

We are extremely excited to announce the first stable release of our Erdiko User Admin project. Find out more about how this open source project can help with your next web application or SPA. Contributions welcome!

We are extremely excited to announce the first stable release of our Erdiko User Admin project! After some hard work, we have a robust backend with an attractive UI to allow you to easily manage a set of roles and users you can host yourself!

We have strived to create a modular and complete solution for managing a persistent set of user records with an attractive and extendable UI.

Project Overview

The Erdiko User Admin is an Erdiko based application that provides a backend for, and serves, a custom AngularJS application. This Angular Application provides an attractive UX to help view and manage the user records we store in a database.
Here are some screenshots to give you a basic idea of the UX:

Login & User Authorization

Only authorized user’s can use the application, and we provide an simple (and attractive) login form allowing a user to input their user credentials.
Any user who is not logged in will be redirected to this form.

Home

This view is the “landing” page for a logged in user. It displays some links to our other features, but mainly it’s the default page for authorized users.

User List

The user list is a page that displays a sortable and paginated list of users in our database. This screen allows you to select a user to edit or delete.

Create User

This page shows a form allowing you to create new user.

Edit User

This page, actually the same code as the Create User, allows you to edit an existing user. This page will become more powerful as we add features in the future.

User Event Log

This page shows a paginated and sortable list of user events logged by the system. This page too will become more powerful as we add features and more options on the data we log as we continue to develop this project.

Erdiko User Admin Modules & Packages

In case you were interested in how this whole project works and some of the underlying code, we’ll give a brief overview of the modules that we used to create this project.

We have worked hard to make this package easily extendible and customizable. While the User Admin uses all of these packages at once, you can extend or replace many of these packages for your own uses.

If you are looking for more in depth information about these packages, or how you can use these packages in your custom project, please refer to their respective documentations.

erdiko/authenticate

The erdiko/authenticate package provides an authentication interface that allows us to verify a user’s provided credentials and log a user in and out. We use this to make sure you are who you say you are after logging in.
We have designed this package specifically to be flexible and extendable. If you would like to customize the authorization process, or even provide your own interface to verify a user’s identity, please refer to the documentation about extending this package.

erdiko/authorize

The erdiko/authorize package provides a role based system that allows users who have the permissions to log in and edit user records. This gives us a level of access and security for each action, and makes sure your data is safe.

erdiko/users

The erdiko/users is a package adding Service Models and AJAX endpoints for user management in a Erdiko application or your custom application.
This package requires both the erdiko/authenticate and erdiko/authorize packages to make sure a user is ‘allowed’ to interact with user records based on a requested action.

erdiko/user-admin

The erdiko/user-admin is a Erdiko MVC application that we have created in order to provide routing for our erdiko/users AJAX routes and to serve the AngularJS application we use for our UX.
If you would like more information about our Erdiko project to create a powerful and minimalistic MVC application, please refer to our documentation on Erdiko.org.

ngx-user-admin

The erdiko/ngx-user-admin package is our npm package that provides the routes, services and components we use in the AngularJS application. We have developed this in a way that will ease extension/customization as well as a focus on code re-use.

If you would like to extend some of this code for customization, please refer to our documentation.

What’s next?

We have some big plans for this project and you should expect to see in the near future:

  • More user roles!
  • Bulk User Editing!
  • An end-user interface & User Profiles!

How can you help?

We would love to have your help in our continued development of this project. Everything from development, testing and documentation; we welcome any and all feedback.

Trying it out

We highly suggest trying out the project yourself. This is the most effective way to evaluate a new project and we would love to get some feedback on how you feel about the application.

Quick start and installation instructions can be found at our official documentation site.

Reporting Bugs / Feature Requests

This project is very much a living and evolving one! We welcome feature requests and encourage our users to report bugs.

Feel free to create feature requests or report bugs on the User Admin repo we host on GitHub.

If you have a bug or feature request specific to a package please create the issue on the respective GitHub repo.

Pull Requests

Do you know what is causing an issue or a bug? Is there a missing feature or something you have worked on that you think would help out other users who use this project? We would love to see your code!

We encourage our developer end users to create Pull Requests from their forked repositories! Please make sure you abide by our contribution guidelines detailed in our official documentation.

 

Thanks so much for reading, we look forward to hearing some feedback on our project!

Managing Multiple Bootstrap Modals

Introduction

If you have managed to find your way to this blog, there is no doubt that you also have some experience with bootstrap. We here at Arroyo Labs love the bootstrap as it provides us the tools to enhance the user experience of our products. Although we love its shiny new toy aspects of bootstrap,they always come with some unexpected complexity.

This blog post was inspired by a real case we have ran into with one of our client’s project that requires alternating the two bootstrap modals. The following animation exactly replicates the problem we had to a simplest form:

Modal has background scrolling enabled which causes issues.

Although the snippets of code in this blog are AngularJS 2 and typescript, I have written this post in hopes that it will be helpful to many who are unfamiliar with them. Now lets continue…

The following describes few notes about our scenario:

  1. There are two modals currently present which are creatively named ModalOne and ModalTwo. The view of each modal will alternate at a specified button click. For example, you should be able to call ModalTwo while ModalOne is open and vice versa. The transition between ModalOne’s closing and ModalTwo’s opening should be seamless and without problem.
  2. Each respective button and modal are separated into different Angular Components. They are connected by Angular Services and Observables passing in Boolean values to signify whether to show the modal or not. This allows us to invoke the modal from anywhere in the web application at a click of the button.
  3. The Observables and Services are set up so that the modals would show and hide with the following line of code:
    // when showModal receives value 'true', modal shows itself
    this.modalOneService.showModal = true;
    
    
    // when showModal receives value 'false', modal hides itself
    this.modalOneService.showModal = false;

If you’ve had extensive experience in bootstrap, you may find that managing multiple bootstrap modals may not be so simple. Unless your goal is to open a modal that is nested inside already open modal, you may see an occurrence as if the two modals are conflicting with each other. We will review more on that topic later in this post.

Deeper into the issue

If you take a closer look inside the developer’s tool in the Chrome browser while opening and closing a single bootstrap modal, “modal-open” class is added to the body element when the modal is open and removes the class when closed.

HTML code when Modal when currently open
HTML code when Modal when currently not open

Inner-workings may be simple when dealing with a single modal but when managing multiple modals, it becomes a lot more problematic.

If you go back to the Chrome developer’s tool again while managing both bootstrap modal, you may realize that the both modal is fighting with eachother to make its respective changes to the body class with class “modal-open”. When ModalOne is to close to make room for ModalTwo, both modals fight to make its respective changes: ModalOne wants to remove the “modal-open” class while ModalTwo tries to add “modal-open” to the body element at the same time.

This is a phenomenon known as Race Condition.

So, what is race condition? This article from techtarget.com explains it the best:

A race condition is an undesirable situation that occurs when a device or system attempts to perform two or more operations at the same time, but because of the nature of the device or system, the operations must be done in the proper sequence to be done correctly.

In this case, before ModalOne has chance to close completely, ModalTwo opens and tries to add modal-open class to the <body> nearly at the same time ModalOne removes the same class. The ModalTwo’s implementation to body tag comes in after and competes/interferes with ModalOne’s change implemented few milliseconds earlier.

The most important part to take away from the definition of race condition is the following:

“…the operation must be done in the proper sequence to be done correctly”.

In this case, ModalOne should be allowed to close itself completely by completing its modal animation fully and make its changes to the <body> before ModalTwo to take action. (and vice versa).

Path to Solution

Although there is no “one-size fits all” solution to this problem as it would depend on the architecture of the app and how the modals are implemented, I hope to at least provide a guideline to help you along the way to a solution.

In the ngx-bootstrap documentation the following directives useful to this case are available. Full documentation is available here: http://valor-software.com/ngx-bootstrap/#/modals#modal-directive

onHidden This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete).
onShown This event is fired when the modal has been made visible to the user (will wait for CSS transitions to complete)

I will only focus on onHidden as it is the only directive we need.

The solution I have created is to implement the onHidden event to the modal:

<!-- ModalOne -->
<div class="modal fade" bsModal 
  #modal1="bs-modal"
  [config]="{backdrop: 'static'}" 
  tabindex="-1"
  role="dialog" 
  aria-labelledby="mySmallModalLabel" 
  aria-hidden="true"
  (onHidden)="hideModal()" >
.....

When the modal hides itself completely, hideModal(), will be called.

The main idea to consider is that after ModalOne is hidden, we have to differentiate in what manner ModalOne is called to be hidden:

Is ModalOne being hidden because we want to close it and go back to the main page? Or is ModalOne being hidden to switch the view to ModalTwo?

In other words, after the ModalOne has been hidden completely, we want the ModalTwo to appear ONLY when ModalTwo button is clicked. If the “x” button in the upper right corner is clicked, the ModalOne should be hidden completely with no subsequent action.

To differentiate such two actions, I have created a property modalStatus, and new methods closeModal and hideModal

/*
  If modalStatus is set true, modal is currently showing
  If modalStatus is set false, modal is currently inactive
  If modalStatus is set null, modal is closed completely.
*/
private modalStatus: any;
//(click) event binds the 'x' button of the Modal to this function
public closeModal() {
  this.modalOneService.showModal = null;
}
//this function is called when modal is completely hidden with the (onHidden) directive.

public hideModal() { 
  if(this.modalStatus!=null) {   
    this.modalTwoService.showModal = true; 
  } 
}

With the solution implemented, the switching of modal is race-condition free.

Managing Modal is now race condition free!

Thank you for making this far! While the example provided has exclusively been AngularJS 2 and above, I hope I have written this post for everyone having similar trouble. Please drop by for any questions and comments.

Thank you!

Converting your Angular CLI application into a NPM Module: Part Two

In the second part of our NPM & Angular CLI series we discuss how we turned our internal application into an npm package and some of the challenges we experienced.

Intro

In my last post we reviewed the process of converting some pieces of your Angular CLI application into a package hostable on NPM.

In this post we will discuss a real world example in which I converted one of our own Angular CLI applications into an npm package (@erdiko/ngx-user-admin) and some of the lessons we learned while doing so.

I had some challenges from local development setup, component templates and publishing my package to a namespaced npm organization.

Hopefully we can help you avoid these small pitfalls so you can focus on creating a fantastic package!

Local development & testing with npm link

To start to move code from the Angular CLI application into my new package I had to set my environment up so the Angular CLI application would reference my local code. Honestly, finding an easy way to do this became a giant pain but I think we have found an easy method. I’ll note two methods I used and the side effects of each.

npm i [directory]

The first method I used was installing the local package with each build by providing the full path to my local directory.

Here’s an example of installing the package into your destination project (assuming local package location /home/andy/ngx-user-admin and your destination package is in /home/andy/user-admin):

cd /home/andy/user-admin/app/themes/user-admin
npm i /home/andy/ngx-user-admin

One downside to this method is that you must re-install using this command after each build of your local package. Every. Time.

Clearly this is not ideal and also a productivity time suck.

npm link

The second, and preferred method, is using the npm link command to create a reference to your local code. This method ‘tricks’ npm into installing and referencing your local code instead of the npm registry code.

This method also uses a ‘live’ reference, similar to a symlink, that makes sure your destination or parent package use the most up to date code after you build.

Here’s an example installing the package into your destination project (assuming local package location /home/andy/ngx-user-admin and your destination package is in /home/andy/user-admin):

cd /home/andy/ngx-user-admin
npm link
cd /home/andy/user-admin/app/themes/user-admin
npm link @erdiko/ngx-user-admin

Please note that your linked packages will still be linked after deleting your local node_modules directories. This might cause confusion with later development and testing so be sure to delete all link references when you are done developing with this command:

npm uninstall -g ngx-user-admin

Templates and Bundling

Another difficult challenge I ran into was including an HTML template as a separate file for the components.

When creating a component in an application you can easily reference your HTML templates by a simple path and the compiler includes the files automatically. All of this kind of goes out the window when you attempt to use the AOT Compiler / RollupJS to create a UMD package. Your components now have no idea where the HTML file path is relative to.

I have seen some documentation about using a module ID to reference your module path canonically, but this seems to have been deprecated I eventually settled on reading the HTML into a variable. This method avoided the pitfalls of file paths and I could easily control the HTML I imported.

To achieve this I moved all of the component template files into files with an extension of “.tpl.ts” to make sure they were compiled, and I moved all the HTML into an exported variable to return the code.

Let’s take a closer look at the Home component template file ‘home/home.component.tpl.ts‘:

export const tpl: string= `
<div class="row">
<div class="col-xs-12">
<h1 id="welcome-title">Erdiko User Admin</h1>
</div>
</div>
...

Here is where we actually import and include this template as a variable in `home/home.component.ts`

import { tpl } from './home.component.tpl';
...
@Component({
  selector: 'app-home',
  template: tpl
})
export class HomeComponent implements OnInit {
...

I also used rollup-plugin-angular plugin to validate & minify the inline HTML I import. This allows us to check the HTML before each build as well as remove some whitespace to make this package a little smaller.

From my rollup.config.js file:

plugins: [
angular({
  preprocessors: {
    template: template => minifyHtml(template, htmlminOpts)
  }
}),

While originally VERY frustrating, I think this solution could work in a variety of packages even if you do not choose to bundle your packages up with rollup.

Publishing your package with an organizational namespace

npm’s registry is a great and free tool that allows you to publish your packages for open source software, and they even offer methods to host packages for an organization and even some to prevent public access.

After some research we found it is possible to publish your package under your organization without a paid account, despite the lack of documentation on how to do this.

When publishing your application, use the “–access public” flag.

Here is how we initially published this package:

npm publish --access public

Note: you will only need this flag on your initial publish. Subsequent updates and publishes will not require this flag.

Please note that you must add the organizational namespace to your package.json file before you attempt to publish like this:

{
  "name": "@erdiko/ngx-user-admin",
  "version": "x.x.x",
  ...
}

Documentation and Bug Tracking

Once you publish your package it’s your responsibility to provide good documentation for other developer and end-user documentation.

We plan on creating some end user documentation (coming soon!) using mkdocs since we like it’s themes and it’s ease of use. We also plan including some custom user documentation as we find it’s quite easy to generate attractive HTML from markdown files.

We will use a project called compodocs to create some information about the code itself. This project combs through your typescript code and generates documentation from docblocks. It also creates a handy report noting your comment to code coverage ratio.

It’s also VERY important to provide some channels for your end users to ask questions and report bugs. Since this is an open source project hosted on Github, our general plan is to use the Github Issue tracker to allow user’s to ask questions and report bugs. We believe this is the most straightforward method to interface with our users and to communicate with our development team.

Conclusion

Creating a package can present some significant non-coding challenges and I’m hoping we were able to save you some grief. We’re looking forward to a stable release of this package very soon, and we’re also excited about creating more packages in the future since we now have a major one under our belt.

If you have any questions about this process or about this package, feel free to reach out in the comments or on our github repo!

Converting your Angular CLI application into a NPM Module: Part One

Creating a custom application with Angular CLI is easy and fun. Converting your application into re-usable code is often the next logical step but can be quite a confusing process. We will discuss the process of converting your code into something you can actually use in multiple projects and distribute for others to use.

Intro

Angular CLI is a great tool to start an angular application easily and quickly. The latest version brings some great tools to the workflow like the module bundler WebPack.

Creating components and services quickly is a strong pro for the Angular CLI too, but at some point, you can only get so far with a single application. For example, you might find that you need to split some of the components into a discrete package for distribution.

Splitting your components and services into another package also has additional benefit of allowing you to consume and extend your code.

NPM

For those unfamiliar, NPM (Node Package Manager) is a JavaScript package registry that allows for easy distribution. It’s a great way to find packages and one stop place for information on updates and support. There are thousands of packages currently published and you should be very excited to add yours!

A package is defined by its config file, package.json which provides some of its meta data, the basic helper scripts and dependencies you need to run and compile your application. There is no doubt you have seen these files before. Angular CLI creates a basic package config when it creates your application and we will detail some of the steps to edit this file for distribution.

How to decide what to move from your app to a package

While every piece of code you write is likely a brilliant gem that should be printed on resume stock and handed out as examples of Great Code, likely only some of it is custom code deserves to be distributed to the masses.

Here are some questions you should ask yourself before deciding if a component or service is worthy of its own module:

  • Could this be a simple building block to solving a larger issue?
  • Do you see some of your angular code as being part of a solution to a larger issue?
  • Is this component something you or someone else will re-use on another project?
  • Does this solve a common problem you encounter?
  • Have you written code like this before and find yourself writing it repeatedly?
  • Have you written code like this before and find yourself writing it over and over again?
  • Are these collections of components unique enough that they are almost their own project?
  • Did you find the point of this application revolved around a few choice components?

Your module’s directory structure

The easiest way to explain how to create a new npm package is to show you a ‘complete’ package. Let’s look at an example below:

 ├── dist
 │   ├── bundles
 │   │   ├── ngx-foo-bar.umd.js
 │   │   └── ngx-foo-bar.umd.min.js
 │   ├── index.d.ts
 │   ├── index.js
 │   ├── index.js.map
 │   ├── index.metadata.json
 │   ├── node_modules
 │   ├── package.json
 │   └── src
 │       ├── foo-bar.module.d.ts
 │       ├── foo-bar.module.js
 │       ├── foo-bar.module.js.map
 │       ├── foo-bar.module.metadata.json
 │       ├── user.model.d.ts
 │       ├── user.model.js
 │       ├── user.model.js.map
 │       ├── user.model.metadata.json
 │       ├── user.service.d.ts
 │       ├── user.service.js
 │       ├── user.service.js.map
 │       └── user.service.metadata.json
 ├── index.html
 ├── index.ngsummary.json
 ├── index.ts
 ├── karma-test-shim.js
 ├── karma.conf.js
 ├── node_modules
 │   ├── @angular
 │   ├── @types
 │   ├── abbrev
 │   ├── ansi-align
 │   └── zone.js
 ├── package.json
 ├── rollup.config.js
 ├── src
 │   ├── foo-bar.module.ngfactory.ts
 │   ├── foo-bar.module.ngsummary.json
 │   ├── foo-bar.module.ts
 │   ├── user.model.ngsummary.json
 │   ├── user.model.ts
 │   ├── user.service.ngsummary.json
 │   └── user.service.ts
 ├── systemjs.config.js
 └── tsconfig.json

Two major directories to note in this example are: `src` and `dist`

The `src` or source directory is where you edit files and do your work. It also has its own `package.json` file that we will discuss more in depth later.

The `dist` or distribution directory is the compilation destination directory and is where we store the files we publish to npmjs. As I mentioned before we go more in-depth into this post.

Angular AOT Compiling

If you are reading this article you are most likely also aware of AOT (Ahead Of Time compilation).

For those of you who are familiar, this differs from “old school” angular compilation by doing a lot of the work that was normally done in the browser at the compilation time. Formerly this was all done by the JIT compiler where the browser would put together all the code. Now, this can all be handled by an offloaded backend process that “tree shakes” the code and trims off the fat.

Tree shaking this result in a much smaller codebase … translates to less data to send to the user … meaning faster load times!

This, of course, is a very brief introduction to the concept of AOT. For more information please review the official docs.

Ignoring some files in your Repo

There’s a lot of files that are created in the AOT build process you are not normally used to seeing in your previous JS/TypeScript projects. Make sure you do not include these in your repo or your npm package by adding these patterns to your .gitignore file:

*.metadata.json
*.map.js
*.js

Also, create a new type of ignore file called .npmignore.

*.ngFactory.ts
*.ts

Setting up your package config files for compilation and distribution

You should create two package.json files: one for development, and another for distribution. The development package file will allow you to edit and run your code for easy debugging. The production package file will allow you to distribute your smaller and compiled module to the masses.

Development package.json

Let’s take a look at an example development package.json file:

{
  "name": "my-package",
  "version": "1.0.0",
  "description": "An amazing module for Angular.",
  "scripts": {
    "transpile": "ngc -p tsconfig.json",
    "package": "rollup -c",
    "minify": "uglifyjs dist/bundles/my-package.umd.js --screw-ie8 --compress --mangle --comments --output dist/bundles/my-package.umd.min.js",
    "build": "npm run transpile && npm run package && npm run minify"
  },
  "types": "./index.d.ts",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/example/my-package.git"
  },
  "author": "Foo Bar",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/example/my-package/issues"
  },
  "homepage": "https://github.com/example/my-package#readme",
  "devDependencies": {
    "@angular/common": "~2.4.0",
    "@angular/compiler": "^2.4.10",
    ...
    "uglify-js": "^2.8.22",
    "webdriver-manager": "10.2.10",
    "zone.js": "^0.7.4"
  }
}

You will see the expected key values. Some are meta information about the package, etc.

There are some major differences in this file compared to the production package.json file: devDependencies & scripts.

NPM Package Scripts, as you know, are used to execute build & test commands and we need to install some devDependencies to allow you to work on your code.

Now let’s look at your production file…

Production package.json

You should create a production package.json file for your end users. This file should live in your `dist` directory as it’s really on. Here is an example production package.json file:

{
  "name": "my-package",
  "version": "1.0.0",
  "description": "An amazing module for Angular.",
  "main": "bundles/my-package.umd.js",
  "module": "index.js",
  "typings": "index.d.ts",
  "keywords": [
    "angular 2",
  ],
  "repository": {
    "type": "git",
    "url": "git+https://github.com/example/my-package.git"
  },
  "author": "Foo Bar",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/example/my-package/issues"
  },
  "homepage": "https://github.com/example/my-package#readme",
  "peerDependencies": {
    "@angular/core": "^2.4.0 || ^4.0.0",
    "rxjs": "^5.0.1"
  }
}

Note this file is significantly smaller than the development version. You do not need to include the devDepencies and you only point to your compiled module.

Demo-ing you Project

It’s a great idea to let end users see your package in action before they download and install it. I like to include a barebones application that implements and demonstrates my component.

This is a good way to promote your project and allows you to prove your code works.

Conclusion

We have reviewed the process of taking your code from an Angular CLI project into a fully-fledged npmjs package for others to use. We hope you can use this advice and apply it to your own projects.

We’ll explore how we ‘took apart’ one our internal Angular CLI applications and turned large portions of it into an npm package in my next post.

Thanks for reading!

Docker Tomcat container SSH tips and tricks

Explains how to define environment vars available for tomcat inside docker container when JAVA_OPTS is not enough. We’ll explore some examples are based on one of our favorite customer’s projects.

Intro

Hello! In this post we’ll discuss a real customer use case and talk about some of the issues we solved in the process.

The customer’s architecture requirements included interfacing with a third party service into our custom PHP framework code. As the customer’s requirements also stipulated the service code must be written in Java (or .Net) we had to introduce Tomcat into the equation.

Even though PHP and Tomcat shared the server on the initial system, we decided to wrap all services within their own Docker containers.

Creating a Docker container for Tomcat

Let’s start with a docker-compose file that will define our tomcat container. We used tomcat:8.5.13-jre8-alpine as the base image.

At first glance this file contains 3 big sections, volumes, ports and expose.

The Volumes section will map files and folders needed to run a tomcat instance, included our app. You will notice in the example below that I included, in addition with .war file, JKS certificates and some configuration files I will explain later in this post.

The ports section will just bind container’s listen port with internal tomcat port (8080).

In the expose section we open some ports, in particularly 8009, that is required for server admin.

version: '2.1'

services:
  my_tomcat:
    container_name: my_tomcat
    image: tomcat:8.5.13-jre8-alpine
    volumes:
      - ./conf/catalina.properties:/usr/local/tomcat/conf/catalina.properties
      - ./client-keystore.jks:/etc/tomcat/client-keystore.jks
      - ./truststore.jks:/etc/tomcat/truststore.jks
      - ./myApp.war:/usr/local/tomcat/webapps/myApp.war
    env_file: ./environment.env
    ports:
      - "8080:8080"
    expose:
      - "8009"
      - "8080"

Setting our environment vars

As you may have noticed, we isolated the environment variables out of the docker-composer, in a new environment.env file, specified in env_file.

In addition to defining container variables, it will define JVM  requirements, such as JAVA_OPTS.

SHELL=/bin/sh


TOMCAT7_GROUP=tomcat7

TOMCAT_CFG_LOADED="1"

JAVA_OPTS="-Djavax.net.debug=ssl,handshake,keymanager,verbose  -Dendpoint=https://3rd-party.domain.com/services/api.wsdl -Djavax.net.ssl.keyStore=/etc/tomcat/client-keystore.jks -Djavax.net.ssl.keyStorePassword=secret -Djavax.net.ssl.trustStore=/etc/tomcat/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit -Djava.awt.headless=true -Xms512m -Xmx2048m -XX:+UseConcMarkSweepGC -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 -Djdk.tls.client.protocols=TLSv1.1,TLSv1.2 -Dsun.security.ssl.allowUnsafeRenegotiation=true"

SECURITY_MANAGER="false"

For this example, we’re telling the JVM to show verbose debug info for ssl and keymanager use (-Djavax.net.debug), which is the endpoint of the service (-Dendpoint), keystore and truststore files and passphrases repectively (-Djavax.net.ssl.keyStore, -Djavax.net.ssl.keyStorePassword, -Djavax.net.ssl.trustStore and -Djavax.net.ssl.trustStorePassword), among others.

Unfortunately, this is not enough with Alpine based container. In shortest explanation, when you start the container it runs catalina.sh that loads default configuration from the image.

But don’t panic, here’s the trick: the custom configuration can be placed in the catalina.properties file, letting those vars available for the system to be accessed like below:

System.getProperty("endpoint");

These custom properties file will be mounted as volume, replacing the default one and voila.

./conf/catalina.properties:/usr/local/tomcat/conf/catalina.properties

Adding and managing a Keystore

Once you have created your certificates stores (there is a powerful tool provided by Java, the keytool, which will be a topic for our future blog post), just copy the catalina.properties from standard tomcat and append variables at the end:

endpoint=https://3rd-party.domain.com/services/api.wsdl
javax.net.ssl.keyStore=/etc/tomcat/client-keystore.jks
javax.net.ssl.keyStorePassword=secret
javax.net.ssl.trustStore=/etc/tomcat/truststore.jks
javax.net.ssl.trustStorePassword=changeit

Final Thoughts

While this was a unique project, the common solution often works well. When I ran into common issues I also found a lot of recommendations for adding or updating a JAVA_OPTS environment variable. We did end up improvising to a point, but this was mostly reserved for edge cases.

I am glad you’re still here! Thank you and hope you have enjoyed reading. See you in next posts.

oAuth – Part 2

A practical example of oAuth integration into your system for authentication process.

Hello readers, today we will walk through a practical example about how to implement a simple login using the oAuth concepts described
in the previous post. To accomplish this goal we going to to create a new Erdiko project with three additional package that will help us to interact with Facebook API. Those packages are Erdiko-Authenticate and oauth2-client  and oauth2-facebook from The League of Extraordinary Packages. But before we can start coding we need to create a developer account and register our app.

How to register your app

This is the easy step; let’s demonstrate how to register using Facebook.
The first step is login in the developers site and sign in with a valid Facebook user. The next step is set you as Developer. To do this go to account, click on the button and follow instructions. Easy, right?
And the last step is to complete and submit this form. That’s it! Now you have registered your app to use Facebook API.

Prepare host project for the example

In this step we just need to create a new Erdiko project, for more details please refer to Erdiko

composer create erdiko/erdiko oauth_authenticate_sample

The next step is add the additional libraries.

In both cases, inside the project directory, will add new required packages

composer require erdiko/authenticate
composer require league/oauth2-client
composer require league/oauth2-facebook

setup erdiko-authenticate

Once it’s added we will need to add the config file in app/config/default/authenticate.json this is an example:

{
  "authentication": {
    "available_types": [{
      "name": "mock",
      "namespace": "erdiko_authenticate_Services",
      "classname": "Mock",
      "enabled": true
    }]
  },
  "storage": {
    "selected": "session",
    "storage_types": [{
      "name": "session",
      "namespace": "erdiko_authenticate_Services",
      "classname": "SessionStorage",
      "enabled": true
    }]
  }
}

we will revisit this file in future sections.

SETUP oAuth2 Client (from thephpleague)

This package doesn’t need a special configuration, but let’s take a look at constructor parameters we will user in our extension.

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => 'demoapp',    
    'clientSecret'            => 'demopass',   
    'redirectUri'             => 'http://example.com/yourredirecturl/',
    'urlAuthorize'            => 'http://example.com/oauth2/authorize',
    'urlAccessToken'          => 'http://example.com/oauth2/token',
    'urlResourceOwnerDetails' => 'http://example.com/oauth2/resource'
]);

clientId and clientSecret, come from the dashboard of your registered app, in the picture below are App ID and App Secret.

redirectUri, is a public URL in your server where you will be redirected after oAuth server finish the authentication process (Facebook in our example)

The last three keys (urlAuthorize, urlAccessToken and urlResouceOwnerDetails) will change based on which service we are using. In the above block, we assume that the the oAuth server is placed in example.com, maybe our custom implementation.

Create new Service class

We will implements AuthenticationInterface that way we can inject it in our authenticate package thru autenticate.json config file we added previously.

In authentication section you will have to add a new entry in available_types array:

{
      "name": "oauth",
      "namespace": "app_services",
      "classname": "oAuthAuthenticator",
      "enabled": true
}

In the constructor method of this class we will create a provider instance for the client, but we will use the third package (oauth2-facebook) to simplify things:

namespace app\services;


use erdiko\authenticate\AuthenticationInterface;
use \League\OAuth2\Client\Provider\Facebook;

class oAuthAuthenticator  implements AuthenticationInterface
{
    protected $provider;

    public function __construct()
    {
        session_start();

        $this->provider = new Facebook([
            'clientId'          => '1925853064368417',
            'clientSecret'      => '55ea4c1a56ca6d1db485b954ZZZ',
            'redirectUri'       => 'https://example.com/login/setlogin',
            'graphApiVersion'   => 'v2.8',
        ]);
    }

    public function login($credentials)
    {
        if(!$this->checkLoggedUser()) {
           $authorizationUrl = $this->provider->getAuthorizationUrl();
           $_SESSION['oauth2state'] = $this->provider->getState();
           header('Location: ' . $authorizationUrl);
           return;
        }
    }

    protected function checkLoggedUser()
    {
       return (
            isset($_SESSION['code']) 
            && isset($_SESSION['oauth2state'])
       );
    }

    public function verify($credentials)
    {
       return true;
    }
}

 

As you can see in the login method, I’ve added a simplistic check for a logged user, if there’s no record in session will redirect to login popup. Now we’re delegating the authentication process to Facebook, and the result of this process will be finally handled by method getSetLogin in the login controller.

Use new service in a Login Controller

In this example we are using a Login Controller just to keep authentication logic isolated. This is a normal erdiko controller, where we will have three basic actions: getLogin – that will load a basic -authenticator and invoke the login method. This action will be loaded when you click on Login with Facebook buttons that you can find everywhere these days.

public function getLogin()
{
   $authenticator = new BasicAuthenticator(new User);
   
   $authenticator->login(array(),'oauth');
}

getSetLogin – a callback method – is responsible to manage Facebook response and storage user in SESSION.

public function getSetLogin()
{
    $authenticator = new BasicAuthenticator(new User());
    if (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {

        unset($_SESSION['oauth2state']);
        throw new \Exception('Invalid state.');
    }
    $token = $this->provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
    ]);
    try{
        $user = $this->provider->getResourceOwner($token);
        $authenticator->persistUser($user);
    } catch (\Exception $e) {
        throw new \Exception($e->getMessage());
    }
}

Finally, we have the getLogout action, that will destroy the SESSION and user won’t be longer authenticated.

public function getLogout()
{
   $authenticator = new BasicAuthenticator(new User());
   $authenticator->logout();
   \erdiko\core\helpers\FlashMessages::set("Good bye, ".$authenticator->currentUser()->getUsername(), "success");
   $this->getLogin();
}

Conclusion

It’s pretty easy to add oAuth features on your system as you can see. Delegating the authentication process to a trusted server, providing users with the ability to use existing trusted accounts is a clear win.

Hope you enjoy this small example! Thanks for reading and hope to see you in my next post!

Using Stubs and Mocks in Jasmine to test your Angular code

Setting up your environment and is a very important part of unit testing AngularJS code. We discuss some of the tools and methods under which we can provide the full workflow of a system under test in this post.

Intro

Unit tests allow us to automatically test our code under a variety of conditions to prove that it works and when it breaks it does so in expected ways. In order to predictably test code, we also need to completely control the setup and data provided to the code under test.

Thankfully, the test tools provided for Angular testing allow you to mimic your models and control how your code responds to code in a very precise way. Jasmine provides some easy way to create test doubles and even “spy” on their execution.

In this post we will discuss some of the best practices and tools we use to control the environment your code is working against.

Why do we need to fake stuff?

We need to control the entire environment and workflow to make sure we are testing the exact scenarios.

Messing around with the DB and creating fake records can be difficult at best, at worst it can create false positives. Even more common, some CI systems lack access to a DB at all

We also need the ability to re-create the conditions under which a bug has been created. sometimes this means we need to replicate some crazy conditions

There are two tools to make this happen: Test Stubs (also known as  Fakes, depending on who you ask) and Mock Objects:

  • Test stubs are a very simplified object or data structure designed specifically for the test scenario. These can be constructed at the beginning of the test or per test.
  • Mock objects are class instances that mimic an existing class to provide the same method interface and return specific values when a method call occurs.

Test Stubs in AngularJS & Jasmine

Test stubs are a simple data structure or model we rely on when running our tests. These can be as simple as a static array of data or a very lightweight object with publically scoped methods. To differentiate a stub from a mock, we typically only mimic the methods we are actually testing. This is quite useful during

More often than not a stub is created at the beginning of the test suites and made accessible to the suite’s tests. A good practice is to limit the modifications to the stubs to make sure you are always testing the same thing.

If you must make changes it is a good idea to make a local copy to isolates your modifications to a specific test.

Test Stub Examples

HeaderComponent

Below is an abridged version of the component code we are unit testing. The important thing to note: at the end of this method’s execution we make a call to the router service to navigate the user to the “login” route and we need to make sure this and only this method is executed.

/**
 * Simple component providing a navigation header.
 */
...
export class HeaderComponent implements OnInit {
    ...
    /**
     * clickLogout clears the user's creds but also 
     * takes the user to the Login route
     */
    clickLogout() {
        ...
        this.router.navigate(['/login']);
    }
    ...
}

Test Suite Code

Here is the abridged test suite where we create our test stub

...

/** 
 * beforeEach setup executes before each test suite test runs.
 *
 * This allows us to setup the stub before each test
 */
beforeEach(async(() => {

    ...
    
    TestBed.configureTestingModule({
        ...
        providers: [

        /**
         * Create a very basic stub object with one method:'navigate'
         *
         * Use Jasmine's createSpy to create a very basic function
         * which also allows us to "listen in" when it's called
         */
        {
            provide: Router,
            useClass: class { 
                navigate = jasmine.createSpy("navigate"); 
            }
        }
        ...
    ]})
    .compileComponents();

    ...

}));

/**
 * Here we test the method and make sure we actually navigate
 */
it('should navigate to /login when clickLogout is fired', () => {
   ...
   let router = fixture.debugElement.injector.get(Router);
   component.clickLogout();

   // "listen" to make sure that the navigate method has been 
   // called and it was called with the expected value
   expect(router.navigate).toHaveBeenCalledWith(["/login"]);
   ...
});

 

Mocks

A Mock object is a simulated object instance used to mimic a classes behavior using the same interface. In simpler terms, this is a fake class with the same method signature as the Real Thing.

A mock object can be composed of multiple objects (and sometimes multiple mock objects), but most often should be created as simply as possible to keep your tests easily maintained.

Mock Object Example

/**
 * Create a mock of an existing service
 * by simply extending it and overriding some 
 * of the methods you wish to use in your tests
 */
class MockAuthService extends AuthService {

    /**
     * This method is implemented in the AuthService
     * we extend, but we overload it to make sure we
     * return a value we wish to test against
     */
    isLoggedIn() {
        return false;
    }
}

...

beforeEach(async(() => {

    ...

    TestBed.configureTestingModule({

        ...

        providers: [

        /**
         * Inject our mocked service in place of AuthService
         */
        {
            provide: AuthService,
            useClass: MockAuthService
        },

        ...

    ]})
    .compileComponents();

    ...

}));


it('should navigate to /login when clickLogout is fired', () => {

   /**
    * Get the mocked service here from our fixture
    * and add a spyOn over-ride to pretend we have
    * a logged in user.
    */
   let service = fixture.debugElement.injector.get(AuthService);
   spyOn(service, 'isLoggedIn').and.returnValue(true);
   
});

Conclusion

Unit tests are only as good as the environment you can provide for your code under tests. It’s very important to be able to mimic and recreate the environment under which you have both positive and negative results for your code.

Unit Testing AngularJS Components & Services

Unit testing is a very important part of software development, and it is extremely important to Angular applications as they become increasingly more complex. We’ll explain how to set up your unit tests and describe what you can actually test with some examples.

Intro

Unit testing is a very important part of the software development process, especially as your applications become more and more complex. Making sure your code is robust and adaptable is an important aspect of being professional. This is no less true with your AngularJS application.

If you are reading this, you are most likely already sold on unit testing but here’s some benefits and reasons for writing and maintaining your unit tests:

  • The ability to quickly update your code and make sure you are able to regressively test your code.
  • Updating your unit tests to cover a fixed bug will prevent the bug from getting re-introduced!
  • Use a CI to make sure EVERYONE on your team is testing the code.

Angular CLI, Jasmine & KarmaJS

Here at Arroyo Labs we use the latest version of Angular CLI a lot. It’s a great way to start a project very quickly provides a great start for your application. It also gives you some boilerplate unit tests for each component and service you create using the CLI.

While we have explained Jasmine and KarmaJS in past blog articles, here is a quick overview explaining how these frameworks work together:

  • Jasmine
    • A very popular behavior driven Javascript testing framework with a very clean syntax.
  • KarmaJS
    • A framework that allows you to run your Jasmine tests on a device or headless browser. The test runner itself will provide a DOM with which your code is rendered and provides the API that Jasmine will interact with.

Setting up your tests

To create a unit test, you need to include a consistent environment in which to run your code under test and we need to control the required classes and variables that go into creating this environment. Thanks to the magic of dependency injection, we can mock up some classes used by our classes and code.

Let’s take a look at the ‘top’ portion of a unit test we use in our user-admin project (you can find the whole unit test in our repo):

/**
 * Import some basic testing classes and utilities from AngularJS's
 * core testing code. This is the minimum required code to create 
 * a basic unit test.
 */
import {
     async,
     getTestBed,
     TestBed
} from '@angular/core/testing';

/**
 * Import some specific test classes used to mock the 
 * http backend and connection classes
 */
import {
    MockBackend,
    MockConnection
} from '@angular/http/testing';

/**
 * Import the HTTP classes we use in our service
 */
import {
    BaseRequestOptions,
    Http,
    Response,
    ResponseOptions,
    XHRBackend
} from '@angular/http';

/**
 * Finally, we import the required custom classes we use in our service,
 * and the service we are testing as well.
 */
import { User }         from '../shared/models/user.model';
import { AuthService }  from './auth.service';

import { UsersService } from './users.service';

What should we test in a service?

To test a service, we have to understand the underlying concept they represent: isolating logic and code into a re-usable class. This means we have a class we can pass around in our application where we get and manipulate data in expected ways.

Keep in mind, we can really only test publically scoped variables and functions. The unit test itself is really only able to interact with your service in the same way that an application is able to.

So, we have these things to test:

  • What public variables get initialized when we create the service?
  • Do public variables update as we expect when we call public functions?

Example Service Unit Test: UserService

In our UserAdmin project, we have a service called UserService used to interact with and manipulate user data we get from the AJAX backend.

The service itself only has quite a few public methods (it’s a very important class!) so we will focus on just two of the suite’s tests of the same method `getUsers`:

getUsers should return an empty observable list when the ajax request is unsuccessful

This is a test to make sure we return an empty list of users if the AJAX response does not contain an encoded list of users. This is a negative test, we are making sure that we return an expected response even when the backend returns an error.

it('#getUsers should return an empty observable list when the ajax   request is unsuccessful', () => {

 // set up the mocked service to return an
 // unsuccessful response (no users, 500 status)
 // with a helper method
 usersBodyData.success = false;
 setupConnections(backend, {
     body: {
         body: usersBodyData // use the previously init'd var for consistent responses
     },
     status: 500
 });

 // set up our subscriptions to test results 
 // when we actually get a result returned
 service.users$.subscribe((res) => {
     if(res) {
         expect(res).toBeTruthy();
         expect(res.length).toEqual(0);
     }
 });

 service.total$.subscribe((res) => {
     if(res) {
         expect(res).toBeTruthy();
         expect(res).toEqual(0);
     }
 });

 // make the actual request!
 let res = service.getUsers();

});

getUsers should return an observable list of users and result total when the ajax request is successful

This test makes sure that we get an observable list of users if the AJAX response is successful. To make sure this happens, we mock the response as though we have a JSON encoded list of users.

it('#getUsers should return an observable list of users and result total when the ajax request is successful', () => {
 // set up the mocked service to return an
 // unsuccessful response (users, 200 status)
 // with a helper method
 setupConnections(backend, {
 body: {
 body: usersBodyData
 },
 status: 200
 });
 
 // set up our subscriptions to test results 
 // when we actually get a result returned
 service.users$.subscribe((res) => {
 if(res) {
 expect(res).toBeTruthy();
 expect(res.length).toEqual(2);
 }
 });
 
 service.total$.subscribe((res) => {
 if(res) {
 expect(res).toBeTruthy();
 expect(res).toEqual(2);
 }
 });
 
 // make the actual request, with some params to pass via query string
 // we will explore this in a future post
 let res = service.getUsers(42, 42, 'id', 'desc');
});

What should we test in a component?

A component, like a service, is also a re-usable piece of code but it also has a defined lifecycle from its parent class and a frontend element via it’s template and optional CSS.

So, here is what we have to test:

  • Does this component actually get constructed?
  • What public variables get initialized and what DOM elements get rendered when we create the component?
  • Do public variables update as we expect when we call public functions?

Like we have noted above when discussing testing a service, you can really only test things that have been scoped as public by the component itself. This does include rendered DOM elements and you should test that these elements appear and render as expected since these are made public by the component itself.

Example Component Unit Test: UserListComponent

Test that the component actually results in a rendered component

it('should create', () => {
   fixture.detectChanges();
   const compiled = fixture.debugElement.nativeElement;
   component.ngOnInit();
 
   component.users = [];
   component.total = 0;
 
   // do we have a component at all?
   expect(component).toBeTruthy();
 
   // create new user button
   expect(compiled.querySelector('.btn-info')).toBeTruthy();
 
   // do we have a table
   expect(compiled.querySelector('table')).toBeTruthy();
   expect(compiled.querySelectorAll('tr').length).toBe(2);
});

Test that we display a list of users with a mocked response

it('should display list of users', () => {
   fixture.detectChanges();
   const compiled = fixture.debugElement.nativeElement;
 
   setupConnections(backend, {
       body: {
           body: bodyData
       },
       status: 200
   });
 
   component.ngOnInit();
 
   // create new user button
   expect(compiled.querySelector('.btn-info')).toBeTruthy();
 
   fixture.detectChanges();
 
   // do we have a table with users?
   fixture.detectChanges();
   expect(compiled.querySelectorAll('tr').length).toBe(21);
 
   // do we see the expected page count
   expect(component.getPageCount()).toBe(2); 
});

Conclusion

Unit testing is a not a oft-celebrated portion of the software development cycle, but it is an important part of the process. Once you have good tests in place, you can pivot direction and update your code with an increased sense of security.