Sunday, October 22, 2017

Nrwl!

Pronounced "narwall" and featuring a narwhale in its logo, Nrwl is a consultancy which helps others with Angular projects. At least two people work at this consultancy as Victor Savkin (left) and Jeff Cross (right) presented themselves and their company at the end of the Tuesday at the AngularMix conference. Their talk, which you may see here, was a refreshing break after a series of talks exclusively by Google's own employees and the first of only two talks that I saw at the conference which had two speakers. Savkin and Cross are themselves Google escapees and have built out a lot of Angular and AngularJS before spinning up a company of their in 2016. They have a product called Nx to address common problems such as race conditions. They decried a lack of standards in Angular apps and have a generator that calls ngRx calls in a predictable way. There is a generator that will try to migrate your existing AngularJS app to Angular. They are making a wrapper for fakeAsync in testing to make it easier to use. Annotations and decorations came up in this talk. This suggests that annotations are a language feature taking the shape of an array of metadata bolted onto an instance of class while decorators are functions developers might make themselves taking in instances of classes and passing them through while bolting metadata onto them.

Bazel was explained by Alex Eagle at AngularMix.

This holds a recording of the talk. Bazel itself is a build tool, good at understanding your packages and compiling. Hermetically, it is sealed airtight and you don't have to "clean" it between uses. You may build a build to chunks to be spread out amongst servers in a cloud.

The CDK was exhibited by Jeremy Elbourn at the AngularMix.

CDK stands for Component Dev Kit. You may read more about it here and Mr. Elbourn's talk, the best of the bunch from the AngularMix Tuesday, is given here. I don't believe this is quite out of development yet, but it is more or less stable and you may have at it as part of Angular Materials 2 here. Angular Materials are made up of CDK elements which are building blocks. Jeremy and his team tried to find functionality that came up as a need repeatedly and across commonly hand-rolled controls to make building blocks for such. The particular example that was on exposition in the talk was the challenge of a pane that appears popping out of another element upon interacting with the element. The list that appears when you click a dropdown would be an example. That is easy enough to make yourself, right? Well, in the CDK example that was shown there was emphasis on making the area that appears appear above the control if the control sits near the bottom of the browser so that one does not have to scroll down to see what appeared and below the control otherwise. What is more, if you move the scrollbar to move the downward sitting pane below the base of the browser it will auto-adjust to sit on top and when you scroll back up the thing on top will go below again, and so on. There is a lot more engineering to be done for this sort of puzzle than one might think of at an outside glance. I'm sure lots of devs have only realized hip deep into making their own controls what some of the challenges are. Other things mentioned included a11y which is an accessibility subpacket for screen readers, LTR/RTL reactionary capabilities (reading left-to-right versus right-to-left), and the utilization of SVG. The CDK is a set of engine parts to build up a rocket. Third parties rolling suites of controls themselves may utilize the CDK primitives. As you might imagine the CDK is going to have some dialogs, some list boxes, and yes, some tables in it. Tables seem to be the flagship of complexity and "doing too much" in any third party library such as DevExpress. Having bit into this challenge myself as suggested here I know that it isn't trivial to tackle this sort of thing. When I try to imagine myself writing something like the reactionary pop-out panes that either sit above or below a control I envision myself determining the height of the control and then figuring out how much screen real estate is left visible, etc. Hopefully the CDK will alleviate some of this heartache for a lot of people.

I saw Dan Wahlin speak on using Docker with Angular at the AngularMix.

This was one of those talks that had some going back in time nostalgia to it. Dan brought up WS_FTP in one of his slides and made me feel old. Apparently HotDog Professional was an old HTML editor. Macromedia HomeSite was also an older editor that was name dropped. MariaDB, in contrast, is a modern database platform. Anyways, not to get off topic... You may run an app in a Docker container and then move the container to any server. That was the thing to take away from this talk, the portability. Just prep your application to run in a container, not a server. That way the specific server may change. You may see/hear everything Mr. Wahlin said at this recording that was made. In terms of terms, think of an "image" as a blueprint like a class in C# and a "container" as an instance of the class. Docker Hub would be a good place to go to goof off with containers in getting started.

Saturday, October 21, 2017

A talk by Stephen Fluin at AngularMix was yet another talk I saw.

See the talk here.

Things said: ETag and Last-Modified are old school ways of caching. package-lock.json in an Angular app helps with locking down dependency versions and the use of Yarn for similar concerns was also encouraged. A polyfills.ts file in modern Angular CLI projects will govern what browsers you wish to support.

"Unit testing your Angular Applications" was a tech talk by Keith Stewart at ngHouston.

ngHouston is an Angular meetup group in Houston, Texas which met, the time I attended, at Improving's office. The talk I saw really was a good follow up to a full day workshop I attended ten days earlier at the AngularMix conference on October 9th which was spearheaded by Joe Eames. Keith Stewart works at CollabNet which owns Subversion and therein he is the lead UI developer for DevOps. A unit in a very basic form is one requirement or "the smallest thing you can get in an application" (Keith quote verbatim) and unit testing is distinct from both functional testing (unit tests in the browser) and also end-to-end testing which covers a large swath of functionality in browser-based tests. Protractor is for end-to-end testing though in the Protractor space the end-to-end tests, using the Selenium WebDriver, are confusingly referred to as functional tests in breaking with the definition that most expect. You go from the beginning to the end of a several step process in an end-to-end test. Karma and Protractor are made by the Angular team itself and Wallaby.js is a rival for Karma and Cypress.io a rival for Protractor. Wallaby is something you spin up to run in the background in an Electron shell all of the time you work and it meshes with your IDE (friendly with Visual Studio, Visual Studio Code, WebStorm, and Sublime Text) to put red, white, and green square dots by lines of code. White suggests code that is not covered by test, red a failing test, and green a passing test. Wallaby has metrics for test coverage. karma-coverage-istanbul-reporter was also recommended for test coverage. For all of the tools I have just mentioned, the talk basically focused on Karma/Jasmine tests. A good bit of this talk went over Jasmine matchers such as .toContain() to see if the copy inside of an HTML tag is what is expected in integration tests. .toEqual() and .toBe() are similar .toEqual() and .toBe() are similar with .toEqual() being akin to the == operator and .toBe() mimicking the === operator and matching with type as well as mere value too. .toMatch() is for regular expressions. .toHaveBeenCalled() and .toHaveBeenCalledWith() see if a function has been called and the later affirms certain arguments. In an example of both .toHaveBeenCalledWith() and a spy, Keith offered up this code:

gotoDetail(character: Character): void {
   const link = ['/detail', character.id];
   this.router.navigate(link);
}

 
 

Which was tested with spyon like so:

it('should navigate to the details page for the given character', () => {
   const spy spyOn(router, 'navigate');
   const character = new Character();
   character.id = 1;
   
   component.gotoDetail(character);
   expect(router.navigate).toHaveBeenCalledWith(['/detail', character.id]);
});

 
 

Keith had his own doctored-up version of the Tour of Heroes app around which he wrote some tests. Some code therein that was tested was:

getCharacters() {
   return this.http
      .get(this.charactersUrl)
      .toPromise()
      .then((response) => {
         return response.json().data as Character[];
      })
      .catch(this._handleError);
}

 
 

Alright, above we have an Observable that we just pop off to a promise (returning something once instead having ongoing listening) and then we cast off what we get back. The following test tests as much and it shows off .toEqual(), .toMatch(), and furthermore mocking.

it('should return characters', fakeAsync(() => {
   const character1 = new Character();
   const character2 = new Character();
   let result: Character[];
   
   service.getCharacters().then(characters => result = characters);
   lastConnection.mockRespond(new Response(new ResponseOptions({
      body: { data: [character1, character2] }
   })));
   tick();
   expect(lastConnection.request.url).toMatch(/app\/characters$/);
   expect(result.length).toEqual(2);
   expect(result[0]).toEqual(character1);
   expect(result[1]).toEqual(character2);
}));

 
 

Wow, what is lastConnection and how does it work its magic? Alright, here is all of the code upstream of the test above that is in the same file:

import { fakeAsync, inject, TestBed, tick } from '@angular/core/testing';
import {
   BaseRequestOptions,
   ConnectionBackend,
   Http,
   RequestMethod,
   RequestOptions,
   Response,
   ResponseOptions,
} from '@angular/http';
import { MockBackend, MockConnection } from '@angular/http/testing';
 
import { CharacterService } from './character.service';
import { Character } from './hero';
 
describe('CharacterService', () => {
   let service: CharacterService;
   let backend: MockBackend;
   let lastConnection: MockConnection;
   
   beforeEach(() => {
      TestBed.configureTestingModule({
         providers: [
            CharacterService,
            Http,
            { provide: ConnectionBackend, useClass: MockBackend },
            { provide: RequestOptions, useClass: BaseRequestOptions }
         ]
      });
   });
   
   beforeEach(() => {
      service = TestBed.get(CharacterService);
      backend = TestBed.get(ConnectionBackend);
      backend.connections.subscribe((connection: any) => lastConnection = connection);
   });
   
describe('#getCharacters', () => {
   it('should query the current service url', () => {
      service.getCharacters();
      expect(lastConnection).toBeDefined('no http service connection at all?');
      expect(lastConnection.request.url).toMatch(/app\/characters$/, 'url invalid');
   });

"Testing Angular Like a Boss!" was a daylong workshop by Joe Eames at AngularMix.

This was very insightful and a second tech talk on testing by a Keith Stewart at ngHouston back in Texas ten days later on October 19th really drove a lot of what I learned home and gave answers to questions I had. (I'll get to that too.) Joe went over the arrange, act, and assert approach to unit testing and put an emphasis on making tests DAMP (descriptive and meaningful phrases) instead of DRY (don't repeat yourself) in the name of making the tests readable (i.e. don't tuck too much logic up into a beforeEach). He encouraged using the Angular CLI, Karma, and Jasmine. By using the CLI (command line interface) I mean making a modern project friendly to both webpack and the Angular CLI. This would be the third version of an approach to an entry point and overarching wrapper of an application's architecture that has a consensus around it, the first being to use system.js, and the second being the use of webpack in a manual setup (you find a seed project online and you doctor it up) that jives poorly or not at all with the CLI. You should use the CLI from the beginning to prep your app including the webpack machinery. You may now do that with the CLI. That is new. ngdoc.io was suggested to be a good place to go for all sorts of documentation. Mr. Eames went over the concept of test dummies which he felt originally came from Kent Beck. He specified four varieties, those variations being mocks, spies, stubs, and dummies. Certainly I have used stubs and mocks in the C# space and have heard of spies therein too, but I found myself struggling to understand the strict definition of these concepts in the Jasmine/Karma testing paradigm, yet eventually it all made sense. The other tech talk I attended ten days later helped, and, again, I'll get to that. Spies take one of two shapes or, more likely, a hodgepodge of the two, either you are making a wrapper function around a function that acts as a passthrough taking in the same variables as the thing it wraps, handing those variables on, getting a response, and then handing the response back while also setting some state somewhere that may be tested for an affirmation that X happened, or you are stamping your own function over the top of a function that calls out to something complicated, perhaps an external dependency, in the name of making testing easier, appropriately isolated, and more predictable. Again, it is more likely a bit of both and I will have an example from the talk I saw ten days later to show off later. Stubs and mocks mirror their C# counterparts in that stubs are dummy objects full of convenience methods to use in lieu of what they might replace which might otherwise call out to external dependencies or do too much in some other way and mocks similarly provide convenience methods but not by the way of you merely hand-rolling an object to use in place of the object that would do something "bigger" in the proper workflows of the application. Just as mocking in C# brings in a bigger apparatus such as NSubstitute into play there too are similar scenarios in the Jasmine/Karma approach. I'll have an example when I give a blog posting on the Keith Stewart talk. The Joe Eames talk introduced dummies to me which are like empty stubs which only are used to fill in the requirement of an object that is demanded that yet doesn’t need to do anything. A nude JSON object that is made by opening curly braces and then immediately closing the curly braces is a good example of a dummy. Joe sees three kinds of tests, namely isolated tests, shallow integration tests, and deep integration tests. Isolated tests test merely a class and wall off other concerns with test doubles. Integration tests test components and their templates. The shallow variety tests just the immediate component and the deep variety lets tests reach into nested components within the component. Having said that, Joe does not encourage testing more than two levels deep. The convention I've seen before of putting a file holding a swath of tests immediately next to the thing that is being testing in the file tree of an application and moreover giving the file full of tests the same name as the file it tests save for the addition of adding "spec" just before ".ts" was maintained by Joe with a variant of also putting isolated, shallow, or deep into the name too. For example, he had a testing file in what I think was his variant of the Tour of Heroes app (a dummy app often used in tech talks as an example of a modern Angular application when showing off code) in some code he gave us which was named hero-detail.shallow.spec.ts and looked like so:

import { TestBed, fakeAsync, tick, async, ComponentFixture, inject } from
      '@angular/core/testing';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroService } from 'app/hero.service/hero.service';
import { ActivatedRoute } from '@angular/router';
import { FormsModule } from '@angular/forms';
 
describe('HeroDetailComponent (shallow)', () => {
   let fixture: ComponentFixture<HeroDetailComponent>;
   let component: HeroDetailComponent;
   let element;
   let heroes = [
      {id: 3, name: 'Magenta', strength: 4},
      {id: 4, name: 'Dyama', strength: 2}
   ];
   
   beforeEach(() => {
      const mockHeroService = {
         getHero: () => Promise.resolve(heroes[0]),
         update: () => Promise.resolve()
      };
   
      const mockActivatedRoute = {
         params: [{id: '3 '}]
      }
   
      TestBed.configureTestingModule({
         imports: [
            FormsModule
         ],
         declarations: [
            HeroDetailComponent
         ],
         providers: [
            {provide: HeroService, useValue: mockHeroService},
            {provide: ActivatedRoute, useValue: mockActivatedRoute}
         ]
      })
   
      fixture = TestBed.createComponent(HeroDetailComponent);
      component = fixture.componentInstance;
      element = fixture.nativeElement;
   });
   
   describe('ititial display', ()=> {
      it('should show the correct hero name & id', async(()=> {
         fixture.detectChanges();
         fixture.whenStable().then(() => {
            fixture.detectChanges();
            expect(element.querySelector('div').textContent).toContain('id: 3');
            expect(element.querySelector('div').textContent).toContain('Magenta');
         })
      }))
   })
   
   describe('ititial display fakeAsync', ()=> {
      it('should show the correct hero name & id', fakeAsync(()=> {
         fixture.detectChanges();
         tick();
         fixture.detectChanges();
         expect(component.hero).toBeDefined();
         expect(element.querySelector('div').textContent).toContain('id: 3');
         expect(element.querySelector('div').textContent).toContain('Magenta');
      }))
   })
})

 
 

The above shows off fakeAsync and tick which are vital concepts. The fakeAsync manages an asynchronous callout with test doubles (faking it) and then the line of code that has tick(); on it forces the pseudopromise to "come back" affecting state. There is also async instead of fakeAsync and flush instead of tick. async is another way to go about this with other syntax and is out of vogue compared to fakeAsync around which some embrace/consensus has developed. flush does what tick does but also carries back some reporting. You may want to create a directory of "matchers" which are helpers for things which come up over and over again in tests. Tour of Heros has a superhero feel to it and there is, in Joe's tests, a need to determine if an object is a hero and so a convenience matcher that checks to see if a JSON object holds three specific properties was written. Use the npm test command to run the tests at the command prompt. Mike Brocchi wrote the Angular CLI and Paul Irish refers to stamping a spy method overtop of a method in the very class you are testing as "duck punching" which Joe discouraged. If you have good separations of concerns and a distinction between components and services you shouldn't need to duck punch. An example for testing a service at a file dubbed hero.service.shallow.spec.ts was:

import { TestBed, inject, fakeAsync, tick } from '@angular/core/testing';
import { HeroService } from './hero.service';
import { Http, BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
describe('HeroService', ()=> {
   let connection;
   
   beforeEach(() => {
      TestBed.configureTestingModule({
         providers: [
            HeroService,
            MockBackend,
            BaseRequestOptions,
            {
               provide: Http,
               useFactory: (backend, defaultOptions) => new Http(backend, defaultOptions),
               deps: [MockBackend, BaseRequestOptions]
            }
         ]
      })
   });
   
   describe('getHero', () => {
      it('should return the correct hero when called with a valid id',
      fakeAsync(inject([HeroService, MockBackend], (service: HeroService, backend:
            MockBackend) => {
         let matchingHero;
         const heroes = [
            {id:2, name: 'Rubberman'},
            {id:4, name: 'Dynama'}
         ];
         let mockResponse = new Response(new ResponseOptions({body: {data: heroes},
               status:200}))
         backend.connections.subscribe(conn => connection = conn);
         service.getHero(4).then(hero => matchingHero = hero);
         connection.mockRespond(mockResponse);
         tick();
         expect(matchingHero.id).toBe(4);
      })))
   })
})