Showing posts with label HTML5. Show all posts
Showing posts with label HTML5. Show all posts

Sunday, June 25, 2017

Dirty secrets on dependency injection and Angular - part 2

In the previous post "Dirty secrets on dependency injection and Angular - part 1", you've explored how DI at component level, can produce different instances of a service. Then you've experienced DI at module level. Once a service is declared using one token in the AppModule, the same instance is shared across all the modules and components of the app.

In this article, let's revisit DI in the context of lazy-loading modules. You'll see the feature modules dynamically loaded have a different behaviour.

Let's get started...

Tour of hero app


Let's reuse the tour of heroes app that you should be familiar with from our previous post. All source code could be find on github.

As a reminder, in our Tour of heroes, the app displays a Dashboard page and a Heroes page. We've added a RecentHeroCompoent that displays the recently selected heroes in both pages. This component uses the ContextService to store the recently added heroes.

In the previous blog, you've worked your way to refactor the app and introduced a SharedModule that contains RecentHeroCompoent and use the ContextService. Let's refactor the app to break it into more feature modules:
  • DashboardModule to contain the HeroSearchComponent and HeroDetailComponent
  • HeroesModule to contain the HeroesComponent


Features module


Here is a schema of what you have in the lazy.loading.routing.shared github branch:


DashboardModule is as below:
@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    DashboardRoutingModule, // [1]
    HeroDetailModule,
    SharedModule            // [2]
  ],
  declarations: [
    DashboardComponent,
    HeroSearchComponent
  ],
  exports: [],
  providers: [
    HeroService,
    HeroSearchService
  ]
})
export class DashboardModule { }

In [1] you define DashboardRoutingModule.

In [2] you import SharedModule which defines common components like SpinnerComponent, RecentHeroesComponent.

HeroModule is as below:
@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    HeroDetailModule,
    SharedModule,  // [1]
    HeroesRoutingModule
  ],
  declarations: [ HeroesComponent ],
  exports: [
    HeroesComponent,
    HeroDetailComponent
  ],
  providers: [ HeroService ] // [2]
})
export class HeroesModule { }

In [1] you import SharedModule which defines common components like SpinnerComponent, RecentHeroesComponent.
Note in [2] that HeroService is defined as provider in both modules. It could be a candidate to be provided by SharedModule. This service is stateless however. Having multiple instances won't bother us as much as a stateful service.

Last, let's look at AppModule:
@NgModule({
  declarations: [ AppComponent ], // [1]
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    SharedModule,     // [2]
    InMemoryWebApiModule.forRoot(InMemoryDataService),
    AppRoutingModule  // [3]
  ],
  providers: [],      // [4]
  bootstrap: [ AppComponent ],
  schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}

In [1], the declarations section is really lean as most components are declared either in the features module or in the shared module.

In [2], you now import the SharedModule form AppModule. SharedModule is also imported in the feature modules. From our previous post we know, in statically loaded module the last declared token for a shared service wins. There is eventually only one instance defined. Is it the same for lazy-loading?

In [3] we defined the module for lazy loading, more in next section.

In [4], providers section is lean similar to declarations as most providers are defined at module level.

Lazy loading modules


AppRoutingModule is as below:
const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'dashboard',  loadChildren: './dashboard/dashboard.module#DashboardModule' }, // [1]
  { path: 'detail/:id', loadChildren: './dashboard/dashboard.module#DashboardModule' },
  { path: 'heroes',     loadChildren: './heroes/heroes.module#HeroesModule' }
]

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}

In [1], you'll define lazy load DashboardModule with loadChildren routing mechanism.

Running the app, you can observe the same syndrom as when we define ContextService at component level: DashboardModule has a different instance of ContextService than HeroesModule. This is easily observable with 2 different lists of recently added heroes.

Checking angular.io module FAQ, you can get an explanation for that behaviour:

Angular adds @NgModule.providers to the application root injector, unless the module is lazy loaded. For a lazy-loaded module, Angular creates a child injector and adds the module's providers to the child injector.

Why doesn't Angular add lazy-loaded providers to the app root injector as it does for eagerly loaded modules?
The answer is grounded in a fundamental characteristic of the Angular dependency-injection system. An injector can add providers until it's first used. Once an injector starts creating and delivering services, its provider list is frozen; no new providers are allowed.


What about if you what a singleton shared across all your app for ContextService? There is a way...

Recycle provider with forRoot


Similar to what RouterModule uses: forRoot. Here is a schema of what you have in the lazy.loading.routing.forRoot github branch:



In SharedModule:
@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [
    SpinnerComponent,
    RecentHeroComponent
  ],
  exports: [
    SpinnerComponent,
    RecentHeroComponent
  ],
  //providers: [ContextService], // [1]
  schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA]
})
export class SharedModule {

  static forRoot() {            // [2]
    return {
      ngModule: SharedModule,
      providers: [ ContextService ]
    }
  }
 }

In [1] remove ContextService as a providers. Define in [2] a forRoot method (the naming is an broadly accepted convention) that returns a ModuleWithProviders interface. This interface define a Module with a given list of providers. SharedModule will reuse defined ContextService provider defined at AppModule level.

In all feature modules, imports SharedModule.

In AppModule:
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    //SharedModule, // [1]
    SharedModule.forRoot(), // [2]
    InMemoryWebApiModule.forRoot(InMemoryDataService),
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [
    AppComponent
  ],
  schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {
}

In [1] and [2], replace the SharedModule imports by SharedModule.forRoot(). You should only call forRoot at highest level ie: AppModule level otherwise you will run in multiple instances.

To see the source code, take a look at lazy.loading.routing.forRoot github branch:

Where to go from there


In this blog post you've seen how providers on lazy-loaded modules behaves differently that in an app with eagerly loaded modules.

Dynamic routing brings its lot of complexity and can introduce difficult-to-track bugs in your app. Specially if you refactor from statically loaded modules to lazy loaded ones. Watch out your shared module specially if they provide services.

The Angular team even recommends to avoid providing services in shared modules. If you go that route, you still have the forRoot alternative.

Happy coding!

Friday, June 16, 2017

Dirty secrets on dependency injection and Angular - part 1

Let's talk about Dependency Injection (DI) in Angular. I'd like to take a different approach and tell you the stuff that surprise me when I've first learned them using Angular on larger apps...

Key feature from Angular even since AngularJS (ie: Angular 1.X), DI is a pure treasure from Angular, but injector hierarchy can be difficult to grasp at first. Add routing and dynamic load of modules and all could go wild... Services get created multiple times and if stateful (yes functional lovers, you sometimes need states) the global states (even worse 😅) is out of sync in some parts of your app.
To get back in control of the singleton instances created for your app singleton, you need to be aware of a few things.

Let's get started...

Tour of hero app


Let's reuse the tour of heroes app that you should be familiar with from when you first started at angular.io. Thansk to LarsKumbier for adapting it to webpack, I've forked the repo and adjust it to my demo's needs. All source code could be find on github.

In this version of Tour of heroes, the app displays a Dashboard page and a Heroes page. I've added a RecentHeroCompoent that displays the recently selected heroes in both pages. This component uses the ContextService to store the recently added heroes.


See AppModule in master branch.

Provider at Component level


Let's go to HeroSearchComponent in src/app/hero-search/hero-search.component.ts file and change the @Component decorator:
@Component({
  selector: 'hero-search',
  templateUrl: './hero-search.component.html',
  styleUrls: ['./hero-search.component.css'],
  providers: [ContextService] // [1]
})
export class HeroSearchComponent implements OnInit {

if you add line [1], you get something like this drawing:



Run the app again.
What do you observe?
The heroes page is working fine listing below the recently visited heroes. However going to Dashboard/SearchHeroComponent, the recently visited heroes list is empty!!

The recently added heroes is empty in HeroSeachComponent because you've got a different instance of ServiceContext. Dependency injection in Angular relies on hierarchical injectors that are linked to the tree of components. This means that you can configure providers at different levels:
  • for the whole application when bootstrapping it in the AppModule. All services defined in providers will share the same instance.
  • for a specific component and its sub components. Same as before but for à specific component. so if you redefine providers at Component level, you got a different instance. You've overriden global AppModule providers.

Tip: don't have app-scoped services defined at component level. Very rare use-cases where you actually want


Provider at Module level


What about providers at module level, if we do something like:



Let's first refactor the code, to introduce a SharedModule as defined in angular.io guide. In your SharedModule, we put the SpinnerComponent, the RecentHeroComponent and the ContextService. Creating the SharedModule, you can clean up the imports for AppModule which now looks like:

@NgModule({
  declarations: [
    AppComponent,
    HeroDetailComponent,
    HeroesComponent,
    DashboardComponent,
    HeroSearchComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    SharedModule,
    InMemoryWebApiModule.forRoot(InMemoryDataService),
    AppRoutingModule
  ],
  providers: [
    HeroSearchService,
    HeroService,
    ContextService
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule {}

Full source code in github here. Notice RecentHeroComponent and SpinnerComponent has been removed from declarations. Intentionally the ContextService appears twice at SharedModule and AppModule level. Are we going to have duplicate instances?

Nope.
A Module does not have a specific injector (as opposed to Component which gets their own injector). Therefore when AppModule provides a service for token ContextService and imports a SharedModule that also provides a service for token ContextService, then AppModule's service definition "wins". This is clearly stated in AppModule angular.io FAQ.

Where to go from there


In this blog post you've seen how providers on component plays an important role on how singleton get created. Modules are a different story, they do not provide encapsulation as component.
Next blog posts, you will see how DI and dynamically loaded modules plays together. Stay tuned.

Tuesday, May 30, 2017

Going Headless without headache

You're done with a first beta of your angular 4 app.
Thanks to Test Your Angular Services and Test your Angular component, you get a good test suite 🤗. It runs ok with a npm test on your local dev environment. Now, is time to automate it and have it run against a CI server: be Travis, Jenkins, choose your weapon. But most probably you will need to run you test headlessly.

Until recently the only way to go is to use PhantomJS, a "headless" browser that can be run via a command line and is primarily used to test websites without the need to completely render a page.

Since Chrome 59 (still in beta), you can now use Chrome headless! In this post we'll see how to go headless: the classical way with PhamtomJS and then we'll peek a boo into Chrome Headless. You may want to wait for official release of 59 (it should be expected to roll out very soon in May/June this year).

Getting started with angular-cli


Let's use angular-cli latest release (v1.0.6 at the time of writing), make sure you have install it in [1].
npm install -g @angular/cli  // [1]
ng new MyHeadlessProject // [2]
cd MyHeadlessProject
npm test // [3]
In [2], create a new project, let's call it MyHeadlessProject.
In [3], run your test. You can see by default the test run in watch mode. If you explore karma.conf.js:
module.exports = function (config) {
  config.set({
    ...
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],  // [1]
    singleRun: false       // [2]
  });
If you switch [2] to false, you can go for a single run.
To be headless you would have had to change Chrome for PhantomJS.

Go headless with PhamtomJS


First, install the phantomjs browser and its karma launcher with:
npm i phantomjs karma-phantomjs-launcher --save-dev
Next step is to change the the karma configuration:
browsers: ['PhantomJS', 'PhantomJS_custom'],
customLaunchers: {
 'PhantomJS_custom': {
    base: 'PhantomJS',
    options: {
      windowName: 'my-window',
      settings: {
        webSecurityEnabled: false
      },
    },
    flags: ['--load-images=true'],
    debug: true
  }
},
phantomjsLauncher: {
  exitOnResourceError: true
},
singleRun: true
and don't forgot to import them at the beginning of the file:
plugins: [
  require('karma-jasmine'),
  require('karma-phantomjs-launcher'),
],
Running it you got the error:
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
  TypeError: undefined is not an object (evaluating '((Object)).assign.apply')
  at webpack:///~/@angular/common/@angular/common.es5.js:3091:0 <- src/test.ts:23952
As per this angular-cli issue, go to polyfills.js and uncomment
import 'core-js/es6/object';
import 'core-js/es6/array';
Rerun, tada !
It works!
... Until you run into a next polyfill error. PhantomJS is not the latest, even worse, it's getting deprecated. Even PhantomJS main maintainer Vitali is stepping down as a maintainer recommending to switch to chrome headless. It's always cumbersome to have a polyfilll need just for your automated test suite, let's peek a boo into Headless Chrome.

Chrome headless


First of all, you either need to have Chrome beta installed or have ChromeCanary.
On Mac:
brew cask install google-chrome-canary
Next step is to change the the karma configuration:
browsers: ['ChromeNoSandboxHeadless'],
customLaunchers: {
  ChromeNoSandboxHeadless: {
    base: 'ChromeCanary',
    flags: [
      '--no-sandbox',
      // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
      '--headless',
      '--disable-gpu',
      // Without a remote debugging port, Google Chrome exits immediately.
      ' --remote-debugging-port=9222',
    ],
  },
},
and don't forgot to import them at the beginning of the file:
plugins: [
  ...
  require('karma-chrome-launcher'),
],
Rerun, tada! No need to have any polyfill.

What's next?


In this post you saw how to run your test suite headlessly to fit your test automation CI needs. You can get the full source code in github for PhantomJs in this branch, and for Chrome Headless with Canary in this branch. Have fun and try it on your project!

Friday, May 19, 2017

Test your Angular component

In my previous post "Testing your Services with Angular", we saw how to unit test your Services using DI (Dependency Injection) to inject mock classes into the test module (TestBed). Let's go one step further and see how to unit test your components.

With component testing, you can:
  • either test at unit test level ie: testing all public methods. You merely test your javascript component, mocking service and rendering layers.
  • or test at component level, ie: testing the component and its template together and interacting with Html element.
I tend to use both methods whenever it makes the more sense: if my component has large template, do more component testing.

Another complexity introduced by component testing is that most of the time you have to deal with the async nature of html rendering. But let's dig in...

Setting up tests


I'll use the code base of openshift.io to illustrate this post. It's a big enough project to go beyond the getting started apps. Code source could be found in: https://github.com/fabric8io/fabric8-ui/. To run the test, use npm run test:unit.

Component test: DI, Mock and shallow rendering


In the previous article "Testing your Services with Angular", you saw how to mock service through the use of DI. Same story here, in TestBed.configureTestingModule you define your testing NgModule with the providers. The providers injected at NgModule are available to the components of this module.

For example, let's add a component test for CodebasesAddComponent a wizard style component to add a github repository in the list of available codebases. First, you enter the repository name and hit "sync" button to check (via github API) if the repo exists. Upon success, some repo details are displayed and a final "associate" button add the repo to the list of codebases.

To test it, let's create the TestBed module, we need to inject all the dependencies in the providers. Check the constructor of the CodebasesAddComponent, there are 7 dependencies injected!

Let's write TestBed.configureTestingModule and inject 7 fake services:
beforeEach(() => {
  broadcasterMock = jasmine.createSpyObj('Broadcaster', ['broadcast']);
  codebasesServiceMock = jasmine.createSpyObj('CodebasesService', ['getCodebases', 'addCodebase']);
  authServiceMock = jasmine.createSpy('AuthenticationService');
  contextsMock = jasmine.createSpy('Contexts');
  gitHubServiceMock = jasmine.createSpyObj('GitHubService', ['getRepoDetailsByFullName', 'getRepoLicenseByUrl']);
  notificationMock = jasmine.createSpyObj('Notifications', ['message']);
  routerMock = jasmine.createSpy('Router');
  routeMock = jasmine.createSpy('ActivatedRoute');
  userServiceMock = jasmine.createSpy('UserService');

  TestBed.configureTestingModule({
    imports: [FormsModule, HttpModule],
    declarations: [CodebasesAddComponent], // [1]
    providers: [
      {
        provide: Broadcaster, useValue: broadcasterMock // [2]
      },
      {
        provide: CodebasesService, useValue: codebasesServiceMock
      },
      {
        provide: Contexts, useClass: ContextsMock // [3]
      },
      {
        provide: GitHubService, useValue: gitHubServiceMock
      },
      {
        provide: Notifications, useValue: notificationMock
      },
      {
        provide: Router, useValue: routerMock
      },
      {
        provide: ActivatedRoute, useValue: routeMock
      }
    ],
    // Tells the compiler not to error on unknown elements and attributes
    schemas: [NO_ERRORS_SCHEMA] // [4]
  });
  fixture = TestBed.createComponent(CodebasesAddComponent);
 });

In line [2], you use useValue to inject a value (created via dynamic mock with jasmine) or use a had crafted class in [3] to mock your data. Whatever is convenient!

In line [4], you use NO_ERRORS_SCHEMA and in line [1] we declare only one component. This is where shallow rendering comes in. You've stubbed services (quite straightforward thanks to Dependency Injection in Angular). Now is the time to stub child components.

Shallow testing your component means you test your UI component in isolation. Your browser will display only the DOM part that directly belongs to the component under test. For example, if we look at the template we have another component element like alm-slide-out-panel. Since you declare in [1] only your component under test, Angular will give you error for unknown DOM element: therefore tell the framework it can just ignore those with NO_ERRORS_SCHEMA.

Note: To compile or not to compile TestComponent? In most Angular tutorials, you will see the Testbed.compileComponents, but as specified in the docs this is not needed when you're using webpack.

Async testing with async and whenStable


Let's write your first test to validate the first part of the wizard creation, click on "sync" button, display second part of the wizard. See full code in here.
fit('Display github repo details after sync button pressed', async(() => { // [1]
  // given
  gitHubServiceMock.getRepoDetailsByFullName.and.returnValue(Observable.of(expectedGitHubRepoDetails));
  gitHubServiceMock.getRepoLicenseByUrl.and.returnValue(Observable.of(expectedGitHubRepoLicense)); // [2]
  const debug = fixture.debugElement;
  const inputSpace = debug.query(By.css('#spacePath'));
  const inputGitHubRepo = debug.query(By.css('#gitHubRepo')); // [3]
  const syncButton = debug.query(By.css('#syncButton'));
  const form = debug.query(By.css('form'));
  fixture.detectChanges(); // [4]

  fixture.whenStable().then(() => { // [5]
    // when github repos added and sync button clicked
    inputGitHubRepo.nativeElement.value = 'TestSpace/toto';
    inputGitHubRepo.nativeElement.dispatchEvent(new Event('input'));
    fixture.detectChanges(); // [6]
  }).then(() => {
    syncButton.nativeElement.click();
    fixture.detectChanges(); // [7]
  }).then(() => {
    expect(form.nativeElement.querySelector('#created').value).toBeTruthy(); // [8]
    expect(form.nativeElement.querySelector('#license').value).toEqual('Apache License 2.0');
  });
}));

In [1] you see the it from jasmine BDD has been prefixed with a f to focus on this test (good tip to only run the test you're working on).

In [2] you set the expected result for stubbed service call. Notice the service return an Observable, we use Observable.of to wrap a result into an Observable stream and start it.

In [3], you get the DOM element, but not quite. Actually since you use debugElement you get a helper node, you can always call nativeElement on it to get real DOM object. As a reminder:
abstract class ComponentFixture {
  debugElement;       // test helper 
  componentInstance;  // access properties and methods
  nativeElement;      // access DOM
  detectChanges();    // trigger component change detection
}

In [4] and [5], you trigger an event for the component to be initialized. As the the HTML rendering is asynchronous per nature, you need to write asynchronous test. In Jasmine, you used to write async test using done() callback that need to be called once you've done with async call. With angular framework you can wrap you test inside an async.

In [6] you notify the component a change happened: user entered a repo name, some validation is going on in the component. Once the validation is successful, you trigger another event and notify the component a change happened in [7]. Because the flow is synchronous you need to chain your promises.

Eventually in [8] following given-when-then approach of testing you can verify your expectation.

Async testing with fakeAsync and tick


Replace async by fakeAsync and whenStable / then by tick and voilà! In here no promises in sight, plain synchronous style.
fit('Display github repo details after sync button pressed', fakeAsync(() => {
  gitHubServiceMock.getRepoDetailsByFullName.and.returnValue(Observable.of(expectedGitHubRepoDetails));
  gitHubServiceMock.getRepoLicenseByUrl.and.returnValue(Observable.of(expectedGitHubRepoLicense));
  const debug = fixture.debugElement;
  const inputGitHubRepo = debug.query(By.css('#gitHubRepo'));
  const syncButton = debug.query(By.css('#syncButton'));
  const form = debug.query(By.css('form'));
  fixture.detectChanges();
  tick();
  inputGitHubRepo.nativeElement.value = 'TestSpace/toto';
  inputGitHubRepo.nativeElement.dispatchEvent(new Event('input'));
  fixture.detectChanges();
  tick();
  syncButton.nativeElement.click();
  fixture.detectChanges();
  tick();
  expect(form.nativeElement.querySelector('#created').value).toBeTruthy();
  expect(form.nativeElement.querySelector('#license').value).toEqual('Apache License 2.0');
}));


When DI get tricky


While writing those tests, I hit the issue of a component defining its own providers. When your component define its own providers it means it get its own injector ie: a new instance of the service is created at your component level. Is it really what is expected? In my case this was an error in the code. Get more details on how dependency injection in hierarchy of component work read this great article.

What's next?


In this post you saw how to test a angular component in isolation, how to test asynchronously and delve a bit in DI. You can get the full source code in github.
Next post, I'll like to test about testing headlessly for your CI/CD integration. Stay tuned. Happy testing!

Tuesday, May 9, 2017

Testing your Services with Angular

Have you ever joined a project to find out it is missing unit tests?
So as the enthusiastic new comer, you've decided to roll your sleeves 💪 and you're up to add more unit tests. In this article, I'd like to share the fun of seeing the code coverage percentage increased 📊 📈 in your angular application.

I love angular.io documentation. Really great content and since it is part of angular repo it's well maintained an kept up-to-date. To start with I recommend you reading Testing Advanced cookbook.

When starting testing a #UnitTestLackingApplication, I think tackling Angular Services are easier to start with. Why? Some services might be self contained object without dependencies, or (more frequently the only dependencies might be with http module) and for sure, there is no DOM testing needed as opposed to component testing.

Setting up tests


I'll use the code base of openshift.io to illustrate this post. It's a big enough project to go beyond the getting started apps. Code source could be found in: https://github.com/fabric8io/fabric8-ui/

From my previous post "Debug your Karma", you know how to run unit test and collect code coverage from Istanbul set-up. Simply run:
npm test // to run all test
npm run test:unit // to run only unit test (the one we'll focus on)
npm run test:debug // to debug unit test 

When starting a test you'll need:
  • to have an entry point, similar to having a main.ts which will call TestBed.initTestEnvironment, this is done once for all your test suite. See spec-bundle.js for a app generated using AngularClass starter.
  • you also need a "root" module similar (called testing module) to a root module for your application. You'll do it by using TestBed.configureTestingModule. This is something to do for each test suite dependent on what you want to test.
Let's delve into more details and talk about dependency injection:

Dependency Injection


The DI in Angular consists of:
  • Injector - The injector object that exposes APIs to us to create instances of dependencies. In your case we'll use TestBest which inherits from Injector.
  • Provider - A provider takes a token and maps that to a factory function that creates an object.
  • Dependency - A dependency is the type of which an object should be created.
Let's add unit test for Codebases service. The service Add/Retrieve list of code source. First we need to know all the dependencies the service uses so that for each dependencies we define a provider. Looking at the constructor we got the information:
@Injectable()
export class CodebasesService {
  ...
  constructor(
      private http: Http,
      private logger: Logger,
      private auth: AuthenticationService,
      private userService: UserService,
      @Inject(WIT_API_URL) apiUrl: string) {
      ...
      }

The service depends on 4 services and one configuration string which is injected. As we want to test in isolation the service we're going to mock most of them.

How to inject mock TestBed.configureTestingModule


I choose to use Logger (no mock) as the service is really simple, I mock Http service (more on that later) and I mock AuthenticationService and UserService using Jasmine spy. Eventually I also inject the service under test CodebasesService.
beforeEach(() => {
      mockAuthService = jasmine.createSpyObj('AuthenticationService', ['getToken']);
      mockUserService = jasmine.createSpy('UserService');

      TestBed.configureTestingModule({
        providers: [
        Logger,
        BaseRequestOptions,
        MockBackend,
          {
            provide: Http,
            useFactory: (backend: MockBackend,
              options: BaseRequestOptions) => new Http(backend, options),
            deps: [MockBackend, BaseRequestOptions]
          },
          {
            provide: AuthenticationService,
            useValue: mockAuthService
          },
          {
            provide: UserService,
            useValue: mockUserService
          },
          {
            provide: WIT_API_URL,
            useValue: "http://example.com"
          },
          CodebasesService
        ]
      });
    });

One thing important to know is that with DI you are not in control of the singleton object created by the framework. This is the Hollywood concept: don't call me, I'll call you. That's why to get the singleton instance created for CodebasesService and MockBackend, you need to get it from the injector either using inject as below:
beforeEach(inject(
  [CodebasesService, MockBackend],
  (service: CodebasesService, mock: MockBackend) => {
    codebasesService = service;
    mockService = mock;
  }));

or using TestBed.get:

 beforeEach(() => {
   codebasesService = TestBed.get(CodebasesService);
   mockService = TestBed.get(MockBackend);
});

To be or not to be


Notice how you get the instance created for you from the injector TestBed. What about the mock instance you provided with useValue? Is it the same object instance that is being used? Interesting enough if your write a test like:
it('To be or not to be', () => {
   let mockAuthServiceFromDI = TestBed.get(AuthenticationService);
   expect(mockAuthService).toBe(mockAuthServiceFromDI); // [1]
   expect(mockAuthService).toEqual(mockAuthServiceFromDI); // [2]
 });

line 1 will fail whereas line 2 will succeed. Jasmine uses toBe to compare object instance whereas toEqual to compare object's values. As noted in Angular documentation, the instances created by the injector are not the ones you used for the provider factory method. Always, get your instance from the injector ie: TestBed.

Mocking Http module to write your test


Using HttpModule in TestBed


Let's revisit our TestBed's configuration to use HttpModule:
beforeEach(() => {
      mockLog = jasmine.createSpyObj('Logger', ['error']);
      mockAuthService = jasmine.createSpyObj('AuthenticationService', ['getToken']);
      mockUserService = jasmine.createSpy('UserService');

      TestBed.configureTestingModule({
        imports: [HttpModule], // line [1]
        providers: [
          Logger,
          {
            provide: XHRBackend, useClass: MockBackend // line [2]
          },
          {
            provide: AuthenticationService,
            useValue: mockAuthService
          },
          {
            provide: UserService,
            useValue: mockUserService
          },
          {
            provide: WIT_API_URL,
            useValue: "http://example.com"
          },
          CodebasesService
        ]
      });
      codebasesService = TestBed.get(CodebasesService);
      mockService = TestBed.get(XHRBackend);
    });

By adding an HttpModule to our testing module in line [1], the providers for Http, RequestOptions is already configured. However, using an NgModule’s providers property, you can still override providers (line 2) even though it has being introduced by other imported NgModules. With this second approach we can simply override XHRBackend.

Mock http response


Using Jasmine DBB style, let's test the addCodebase method:
it('Add codebase', () => {
      // given
      const expectedResponse = {"data": githubData};
      mockService.connections.subscribe((connection: any) => {
        connection.mockRespond(new Response(
          new ResponseOptions({
            body: JSON.stringify(expectedResponse),
            status: 200
          })
        ));
      });
      // when
      codebasesService.addCodebase("mySpace", codebase).subscribe((data: any) => {
        // then
        expect(data.id).toEqual(expectedResponse.data.id);
        expect(data.attributes.type).toEqual(expectedResponse.data.attributes.type);
        expect(data.attributes.url).toEqual(expectedResponse.data.attributes.url);
      });
  });

Let's do our testing using the well-know given, when, then paradigm.

We start with given: Angular’s http module comes with a testing class MockBackend. No http request is sent and you have an API to mock your call. Using connection.mockResponse we can mock the response of any http call. We can also mock failure (a must-have to get a 100% code coverage 😉) with connection.mockError.

The when is simply about calling our addCodebase method.

The then is about verifying the expected versus the actual result. Because http call return RxJS Observable, very often service's method that use async REST call will use Observable too. Here our addCodebase method return a Observable. To be able to unwrap the Observable use the subscribe method. Inside it you can access the Codebase object and compare its result.


What's next?


In this post you saw how to test a angular service using http module. You can get the full source code in github.
You've seen how to set-up a test with Dependency Injection, how to mock http layer and how to write your jasmine test. Next blog post, we'll focus on UI layer and how to test angular component.

Thursday, April 27, 2017

Debug my Karma

I've just started getting my fingers in Angular. I've worked briefly with AngularJS in the past.
Although, I'm doubtless - you know the saying: testing is doubting 😁
I've always started looking at new framework with unit testing in mind. In this post, I'll use Google team term Angular stands for post 2.0, in there I'll use the latest release ie: 4.0.

When writing test, it is sometimes useful to debug the test using devtools (come on... no console log, vintage time is over 👾👾👾). Let's see how to debug your test suite with Karma... It all depends on how your started your project: Let's see how to get a comfortable environment...

With angular2-webpack-starter


Follow README instructions:

git clone --depth 1 https://github.com/angularclass/angular2-webpack-starter.git
cd angular2-webpack-starter
npm install
npm test

When you run it you can see a blinking browser opening, running the test and closing. To be able to debug, open package.json and add:

{
  "name": "angular2-webpack-starter",
   ...
  "scripts": {
  "test:debug": "karma start --no-single-run --browsers Chrome",
  }
}

Now just run npm run test:debug. Karma is now in single mode therefore Chrome stays opened!
Easy to debug simply cmd + alt + I to open devtools.
Also, note that the coverage report is ran and now visible!

With angular-cli project


Let's open a shell, you'll need node 6.5+ / npm 3+, install angular-cli globally:

npm install -g @angular/cli

Create a project with angular cli and run the test:

ng new ngx-unit-test
cd ngx-unit-test
ng test

NOTE: npm test is an alias to ng test (as most projects nowadays use npm script. Very handy as you don't need to globally install ng-cli!)

ng test will bring chrome as per default. Easy to debug simply cmd + alt + I to open devtools. Open your favourite editor, change the code. The tests are re-run. Easy-peasy, not much to do. What about if you want to run the coverage tool?
From angular-cli wiki:

ng test --code-coverage --single-run

karma.conf.js the source of truth


In the end, it all boils down to karma.conf.js configuration file. Wether by default you're running continuously in watch mode (dev friendly) or your test run with PhantomJS (CI/CD friendly), this is up to Karma configuration. It is however always good to have a build command to override and offer dev and CI friendly build.

Happy coding! Happy testing!

Tuesday, March 14, 2017

Sharing the fun of DevNexus 2017

1 day of workshop, 2 days of conference sessions and so many tracks to choose from.
This is DevNexus 2017 in Atlanta!
A fun conference to be on 🤗
This year I had the pleasure to be invited as a speaker for my talk: the trials and tribulations of a polyglot cross-patform mobile developer.
I also took the opportunities to attend as many conferences as possible. My theme this year was reactive programming.

Here is some miscellaneous notes, mumblings and souvenirs from this edition.

Wednesday was workshop day. I've picked Venkat's workshop on Building reactive applications. As I always said: Venkat is always a good value, you never get disappointed, there is always something to learn. In this workshop, Venkat tells us what functional programming is all about: function composition and lazy evaluation. I did all the exercice with RxJS, the other guys around me used RxJava, it was funny to see how concise is the JavaScript version 😜

Thursday morning starts with Venkat's keynote on Don't walk away from Complexity, Run. It was a very inspirational keynote, one of my favourite quote is: Coding is not a work, coding is an addiction. 👍 👍🏽 👍🏾 👍🏿
I've been addicted for 20 years and I can't get over it 😜
The next sessions I've attended:
  • Introducing TypeScript 2.0 by James Sturtevant: Great new addition to TypeScript 2.0 is non-nullable type, you can activate the check by adding --strictNullChecks flag to tsc command lien. To read more about non-nullable type, visit this blog post. I like the notion of union type and the easy sugar syntax Type? for optional type (converted to union type) that reminds me Swift syntax. When used with dot operator, the optional type will need to be unwrapped.
  • Promises and Generators in ES6 by Jennifer Bland. I really like Jennifer's biography, a senior developer who was part of Lotus Domino on the AS/400 and is reconverted into JavaScript development. Our job as a developer is a continuous learning exercise.
  • Gradle Worst Practices: Common anti-patterns in Gradle builds by Gary Hale where you learn 10 anti patterns for performance, maintenance, correctness and usability. Useful tip I'll keep in mind: make your build immutable by using use @Input / @outputDirectory annotation rather than using variables.
  • Overview of Webpack, a module bundler by Pavan Podila: one of my favourite presentation for the rich content. I've learnt a lot, I followed Pavan as he went through his step by step github example. Thanks Paven to have added the lazy loading step upon my request! I will write a separate blog post on the topic. If you work with angular2 or ReactJS, you've used webpack, you might use angular-cli or react-create-app that hides its configuration away but getting your way with plain webpack will come handy.


Friday morning keynote was all about dancing with elephants with Burr:

Keynote was followed by my ✨ presentation ✨ the trials and tribulations of a polyglot cross-patform mobile developer. I have great time delivering the presentation, this one was slightly different than the one I used to give: less technical but full of anecdotes and feelings. You can see my hand-crafted slides here. Better than thousand words, it can be all sum up with these drawings:


This is the process a developer as an early adopter goes through ^^^
It's all about about emotions 😭 😥 😱 😂 😉 😍
I have no doubts that sharing your feelings with you peer developers at work will make you a better communicator. As been very often the only female developer in a team, I used to think, I’d rather not show I’m a sensitive person. It could be interpreted as a weakness. But looking around me, I see developers (like you), people who can troll flame war on crucial subjects like tabs vs spaces in your IDE and they do it with passion and emotions. In fact, I’ve recently ran into this article from Jim Whitehurst, our Red Hat CEO, where he said that “showing emotion at work is simply a reflection of a person's passion”. I couldn’t agree more with that quote.

Afternoon I've attended Rx.js cleans up the async JavaScript mess by @codefoster where we deep dive the github examples v4 on RxJS and we explore the v5 RxJS repo. Timeflies is my favourite animation. I loves the cool effect and it reminds me Brian Leathem's DevNation talk. In the end, it was a great complement from Venkat's workshop and a good entry point for examples to look at. I might contribute to port those samples to version 5.

Time flies when you have fun, DevNexus 2017 was a fantastic edition, too many tracks and great subjects to choose from. I'll have to come back next year, that's for sure.

Friday, May 23, 2014

Mobile and lightening talks at JSSophia

Last JSSophia event was hosted at CrossKnowledge (big thank you to Matthieu and Stephane). We had a guest speaker Erik, coming from Switzerland to talk about Cordova. Live demo, always comes with surprise specially when not run on your computer ;)

As always in JSSophia meet-up, a very interactive session where you ask, participate, give your view and share with the speaker and the audience. It was really fun to have you Erik :)

Second part was lightening talks, starring:
Mathieu for a 5 minutes, fast paced introduction on Browserify: Bertrand to carry on with noderjs: Sebastien with the wifi back on time, talking about Firefox OS app: Bertrand show us how to debug on Cordova Android: Fred on MEAN: and last but not least, Yacine on Ionic (trolling on jqm): See you at next JSSophia, stay tuned!

Tuesday, May 7, 2013

Reading about AngularJS - part 1

AngularJS, Google last breed MV* framework, is getting a really good momentum. Proof is this spring,  several books are coming out.

And, this is great news!

I remembered getting my hands on AngularJS for the first time, a couple of months ago. I started with the online documentation and with the mailing list. I also went a few time on IRC chanel, which is fun and the ultimate interactive approach :) One thing I particularly like is the usage of jsFiddle and  plunker for describing an issue in the mailing list or giving examples in the online documentation. What's better than thousand words? Code of course ;-)

Even though mailing list  and getting your hands into code is a great way to learn, I like getting my tablet in the evening and reading about the subjet. It gives a general understanding of the philosophy behing a framework, it also opens your mind by teasing you with paths to explore, different ways of doing stuff.... My blog post is actually not about AngularJS but more about AngularJS' books!

Available books

More recently, googling "angularjs books", to my pleasure gives me choices; at the time of writing this article:

- AngularJS - O'Reilly - Brad Green and Shyam Seshadri, completed book.
- Recipes with Angular.js - LeanPub - Frederik Dietz, RAW mode.
- Instant AngularJS Starter - Packt Publishing - Dan Menard, completed book.
- AngularJS Web Application Development - Packt Publishing - Pawel Kozlowski and Peter Bacon Darwin, RAW mode.
- AngularJS in Action - Manning - Brian Ford and Lukas Ruebbelke - to be available in Fall 2013,.

So I picked a couple of them, here is the ones I've read or I'm still reading for RAW mode ones:

AngularJS by Brad Green and Shyam Seshadri

One of the first book to be available on its completed form, written by 2 engineers from Googles Inc., I like the book, specially if you're completely new to AngularJS.

It's an 200 pages book with a nice step by steps approach. You should read it from start to end. With an amazing fast first chapter, giving you all the vocabulary to work with Angular, from templating, to data binding to dependency injection....

Chapter 2 get deeper and introduce AngularJS life cycle and how two-ways binding is achieved. In this chapter you've got AngularJS in a nutshell. I like the offline talk about unobtrusive JavaScript because that was exactly one of the point that bothers me when starting with the framework, I'm best practices addicted:)

Chapter 3 talks about the tooling which could have been interesting but to me it's the part of the book I like the least because it's going fast on Batarang, Yeoman, IDE and it's developing "Integrating AngularJS with RequireJS" which, to me, is not so much required.

Chapter 4, we're building GutHub application, all source code being in GitHub. Nope guys I didn't misspell, it's GutHub we're buiding  :)
Great intro to promises implementation in AngularJS with chapter 5 and directives look so simple to implement in chapter 6. Chapters 7 gives miscellious tips. Chapter 8 gives different sample apps, to be honest, I've skipped that one. 


Recipes with Angular.js by Frederik Dietz


As the title says it all: it's a recipe book, man. And indeed, if you look for a AngularJS concept you'll find a couple of examples about it. Source code is available in github which is great. Being published online, I wish we could have HTML links for code snippets, but fine enough once you've got github link all examples are ordered by recipe number. I like also clear proble/solution/discussion pattern. I wish it was a bit more verbose from time to time.

This book is not intended at giving an introduction on the framework. It's more a book you use by index.


At the time of writing the book is still on RAW mode with 100 pages. I expect more recipes to come. It's the diversity and broad coverage of recipes that makes the book rich and useful. Keep up with the good work Frederik.





AngularJS Web Application Development by Pawel Kozlowski and Peter Bacon Darwin

So far I've read only half of it. The book being still in RAW format, I've read chapter 8 before chapter 5. But I found the book quite promising. Once I've got the final version, I'll go over it again but in the right order, just for the pleasure :)

Chapter 1 is brillant, it gives you the philosophy behind the framework: declarative template view vs imperative controller logic paragraph is really worth reading. Crash course talking about 2-ways data binding, hierarchy of scopes: great! The discussing on Dependency Injection which gives a list of the different ways of achieving it with AngularJs is already advanced.

Chapter 2 is really about best practices in web application development and how they apply to AngularJS. Best part, being about Karma (still named Testacular in the book), this book just not speaks about test driven development,  it applies it! All book samples start showing the expected behaviour and then the code sample. To my surprise, the book sample angular-app is not following directory structure generated by Yeoman, with a bit of research I find the explanation in this thread on "by features" layout.

Chapter 3 is a bit off topic with CORS topic although nice to read but when it comes to promises, it is a real pleasure, it really goes deep in the explanation. Chapter goes on about $http and $resource services.

Chapter 5 makes routes and views clear to me which was one of the subject I was looking after. Delving into history API and HTML5 push state, you can understand how views can be routed using $routeProvider object so that you can achieve deep-link (navigable URLs) either using hashbang or HTML5 mode. To bing us to Angular routing service, the authors take a experimental approach coding a hand-crafted navigation bar using $location and ngInclude directive, and then later switch to $routeProvider and ngView. So you can truly understand the benefits of it. Paragraph on limitations of routes services is worth reading. It gives the starting point for the new AngularUI project ui-routes.

Chapter 8 on forms is full of details recipes directly available online. With this chapter you delve into details (such as validation) which gives the feeling to the reader: the book can also be used as “reference”. I like the details code snippets: you learn small tips and tricks. Very geek.

I'm still reading Chapter 9 and 10 about directives. This is the part where you teach your browser tricks. It's Angular way of taking the web from a different angle. Approach those chapters with a "read, play with it and read again" pattern.

As core comitters to AngularUI, I wish Pawel and Peter had written a full chapter on it. But maybe it's for a future project: write another book on AngularUI :-)

On conclusion, if you you want a book to have a general overview go for AngularJS from Brad Green and Shyam Seshadri. Interesting in "how to" style, google and use jsfiddle examples or go for Frederik Dietz's Recipes book. For a more deeper delve into AngularJS I would definitively go for AngularJS Web Application Development's book from Pawel Kozlowski and Peter Bacon Darwin. But...

For fall 2013, we'll have AngularJS in Action. I am looking forward to reading this one. this is the reason why I put in my article title: part 1. Stay tune for a "Reading about AngularJS - part 2" blog post!

Wednesday, March 13, 2013

DevFestW with Paris Duchess & GDG Paris

Female speakers only on Tuesday 11th March at DevFestW Paris.
Full-room but not only female developers. Proof that gender diversity is important not only to female professionals.
See by yourself:


+Ludwine Probst gave a quick introduction on Duchess France and the event went live. Ludwine did a great job choosing presentations that evening. The 3 talks fit pretty well together: doing a clone of Foursquare using MongoDB and Google Maps, having Katia delving into MongoDB and Kasia on Google Maps.

I start my talk on "Hybrid Mobile App in minutes" introducing 3musket33rs. As I said it's fun to do open source at night, it's even more fun to do it with a bunch of friends ;-)
Live coding part went smooth, as Sebastien always says: "Demo Gods" were clement.
You can get my presentation http://corinnekrych.github.com/devfest/ where you get all the links for 3musket33rs plugins.









+Katia Aresti spoke about her experience working with +MongoDB. Such a lively talk you could feel the project, full of concrete exemples. You get the atmosphere of an agile team. "Emerging Architecture" was a new term to me; Out of the talk I'm also convinced to use Jongo for my Java/Groovy query.











Kasia Derc-Fenske shows us how Google Maps rocks. The introduction on JavaScript and its pitfalls was funny. I'd like when she says be aware there will be lots of JavaScript. It's a crazy language but I love it.

I feel the same when I say I'm taking Grails on a wild side, I'm using HTML5 (and BTW, HTML5 is also about JS). Interesting paths to explore for 3muket33rs MapService in JS. Thks Kasia!

The event was organised by Paris Duchess & GDG Paris. Thank you both, that was a great event and see you next year.

Friday, February 22, 2013

KissingTurtles makes the show at JSSophia

As +Fabrice Matrat said it all in his blog post, we had a great time at +JSSophia / RivieraGUG (as always I would say).
It's like meeting friends. I was also happy to meet new faces. I hope you'll spread the word: it's fun to be there, people are cool etc...

I just want to add a couple of links:



Obviously KissingTurtles is an project for fun. Your contribution is welcome. I want to make the DSL more rich to present it for Gr8Conf.

See you all the 23rd March.

Thursday, January 31, 2013

Greach 2013 in Madrid

Back home, I missed the great Greach atmosphere. It makes you feel like I want to be next year for the next Greach edition! Being there, with a bunch of geek friends (ie: the 3musket33rs), seeing known faces, chatting geek jokes, I really feel home in the Groovy & Grails community.

I presented 2 conferences and a hands-on session, here's my feedback on those:

Hybrid Mobile App live code presentation was very smooth. Demo gods were gentle with us. To illustrate mobile needs, we choose  to build a clone of Fousquare with a client Mr Very-very-rich you. He is the guy guiding our demo flow. As always, he comes with intial requirements and as we go along, keep adding to the backlog. As he's on the phone, he goes under a tunel and we talk about offline mode etc...I like the usage of  a metaphor, I think it makes your point clearer. It's a practice from my XP time. Being the 3 musket33rs together, despite the problems of microphone, was reeeeeally fun!

With Building a groovy DSL with user interaction, Mr very-very-rich is back again, with new requirements. Guess what? He's not on mobile business anymore but wants to make money in the survey industry. Writing a survey script that reads as plain old English. A survey that run on server side (potentially interacting with data from central knowledge database) but that interacts with user. With the dialogue between Sebastien and I, we chat about he code, even sometimes making mistakes (almost on purpose) to make sure you follow us. I hope even the AST transformation was fun to talk about. Here, we presented some drawings.

HTML5 games workshop with Mathieu Bruyen was out first hands-on session.This is the part that requires most preparation, but we had fun presenting KissingTurtles, a project that was born during Grails48 hackathon. With Mathieu, we enjoyed it so much that, taking your feedback into account, we're going to re-do the session the 21th February at RivieraGUG & JS Sophia.

Greach is over, but Greach will be back!
++
Corinne