TDD in Angular 6. Experiments in TDD
Basic project to experiment with TDD in Angular 6.
Project Setup
Bash History of Commandsng new TestFirst --routing
ng add @angular/material
git commit -m initial commit
AppComponent
should create the app
should have as title 'app'
should render title in a h1 tag
ng generate @angular/material:material-nav --name=SideNavigation
AppComponent
should create the app
should have as title 'app'
should render title in a h1 tag
SideNavigationComponent
should compile
Let’s at least our pile of nothing testing right, right?
should render title in a h1 tag
was stupid. I deleted it. 3 specs, 1 failture<router-outlet></router-outlet>
lets unfuck the fuckery of the ‘should compile of the SideNavigationComponent
checked the app module, it’s all being importing in there. let’s try an ng build?
there it is, ERROR in src/app/app.module.ts(7,32): error TS2307: Cannot find module './my-nav/my-nav.component'.
, I built the side nav and then deleted it. Looks like I forgot the reference. Yup, it’s still in the app import and the declartions of the app module.
ng build
builds correctlyng serve
and everything works. All test fail now. 3 specs, 3 test, 3 failures.AppComponent
`should create the app`
`should have as title 'app'`
SideNavigationComponent
`should compile`
`MatToolbarModule`
`MatButtonModule`
`MatSidenavModule`
`MatIconModule`
`MatListModule`
`BrowserAnimationsModule`
- it would make more sense to just import the app module here, since they are already in. We'll get back to that. lets get this guy running first
SideNavigationComponent
`should compile`
duplicating the imports in all this is going to be a pain in the ass.
ng g module shared
ng test
Snap 4 specs, 0 fails. At least this schmatic didn’t generate it’s own failing test? or is starting with a failing test the right thing to do? BrowserAnimationsModule,
LayoutModule,
MatToolbarModule,
MatButtonModule,
MatSidenavModule,
MatIconModule,
MatListModule
ng build
still worksng e2e
1 test and 1 failure. hold up, we’ll get back to that. ng serve
bulid runs, white screen. Dev tools gives [] me the same error the failing tests gave me before I fixed them. noted, exports: [
BrowserAnimationsModule,
LayoutModule,
MatToolbarModule,
MatButtonModule,
MatSidenavModule,
MatIconModule,
MatListModule
],
return element(by.css('body > app-root > app-side-navigation > mat-sidenav-container > mat-sidenav-content > mat-toolbar > span')).getText();
expect(page.getAppTitle()).toEqual('TestFirst');
ng e2e
runs now and my lonely header test passes. ng serve
works and serves the pageng test
runs and passes all tests, but the page doesn’t render properly in the Kara Test browser page. So lets take a step back here. The original goal was to do a tutorial and some experimentation w/ Angular 6 & Materual design. But, It’s broken out of the fucking box. My google fu has either turned to complete shit, I’m a worthless hack, or I’m just doing something wrong. I’m not finding much on this tool chain ( the built-in , I must add) but it DOES look like the folks at angular material have their shit together but they aren’t using the standard Karma config and are manually importing a bunch of crap. Honestly, I need to sit and analyze it all further, I’m 99% sure that it’s something not getting bootstrapped into Karma/ Jasmine / Whatever, but I’m on a plane with no internet access and want to keep this ball rolling. soooooo, let’s test some shit.
WTF is Aerobiz? I played the hell out of this when it came out for the SNES and it’s awesome and you’re not for not playing it. From the manual:
Aerobiz Supersonic is a unique business simulation which lets you take part in the chllenging world of global travel. The challenge extends from early airline history into the coming supersonic era beyond the year 2000. The game features over 50 airplanes, including supersonic jets, and 89 worldwide cities for your air network.
So really, you’re the CEO of this airline and want to whore your capitalist ass out and take over the industry. Let’s look at the manual some more .
Game Flow
Really that’s the gist of it. so from the a quick look we’re gonna need some planes and place to land and take off. we’ll dive into the simulation later. The manual has enough information to probably get most of this up and going.
Like I said before, unit testing with Material and Angular is wonky at best right now. it works but isn’t quite what it should be. i’m going to get back to that later. totally promise, just need to be figure out Karma / Jasmine’s config and find what it’s missing.
After all that long winded crap. let’s get back into TDD with Angular, caveats noted.
We need planes. Looking at the manual, there’s a table of planes in the appendix. Planes are have the following attributes ( in the manual)
Plane
start of production - year - the year it started production. Depending on what year you start your game in defines what planes are available.
Something that they don’t mention is that you can choose where you by planes from, so if you are America or Russia during the cold war you can’t by eastern or western block planes during that time.
The gives us a pretty good start on what our base plane model should look like, so lets generate the model and have Angualr create it’s default spec for us.ng generate class models/plane --spec
We there , we got a spec and a class in a new models directory
tested and yes it compiles. so joyous day. let’s start building this plane.
Starting with a model
From here on out I'm just going to leave `ng test` running and we'll hack this fucking plane together. From my little table up there, we can see what attributes that we should have available to us. I'll be doing hidden properties with getter and setters methods for everything. So let's try this 'TDD / Test first now that we've got a project going.
I'm diving right into the plane.spec.ts file. First we're going to write up some broken ass tests.
it gave us a simple test 'it should create' , I concur, so I'm not changing that, but I am curious how that's going to work with inheritance later. we'll see when we get there.
- So we can use our base test to define a new test. Looking at this we can see that we are describing the object, creating a lambda that's return is boolean ( `expect(new Plane().toBeTruthy());`) pretty simple.
- I created a simple test case, that should fail :
` describe('Plane', () => {`
`it('should create plane named DC-10', () => {`
` expect(new Plane().name = 'DC-10').toEqual('DC-10');`
`});`
` });`
let plane: Plane;
describe('before & after', function () {
beforeEach(function () {
`plane = new Plane();`
});
afterEach(function () {
// clean up
});
});
describe('Plane', () => {
it('should create an instance', () => {
`expect(new Plane()).toBeTruthy();`
});
});
describe('Plane', () => {
it('should create plane named DC-10', () => {
expect(new Plane().name = 'DC-10').toEqual('DC-10');
});
});
Okay, so there’s a test and a test model now. I’m going to plug through the Aerobiz manual and fill out the rest of the tests for this.
expect(plane).toBeTruthy();
I expected to work since in the setup, i’m creating a new Plane() and assigning to plane. turns out that this isn’t working. It turns out that this is scoped to the current describe block, so I’ve left this intact BUT i’ve changed my global to let plane: Plane = new Plane();
While this gets one object set up and then runs it’s tests, I probably should have one test to check for the base plane object creation and have it’s set up and tear down inside of it. So I undid that change to create the global and then moved all the test cases into the main create plane describe block as such:
describe('Create Plane', () => {
let plane: Plane;
beforeAll(function () {
plane = new Plane();
});
it('should create an instance', () => {
expect(plane).toBeTruthy();
});
it('should create plane named DC-10', () => {
expect(plane.name = 'DC-10').toEqual('DC-10');
});
it('should create plane with manufacturer Boeing', () => {
expect(plane.manufacturer = 'Boeing').toEqual('Boeing');
});
it('should create plane with 10 seats', () => {
expect(plane.seats = 10).toEqual(10);
});
it('should create plane with a range of 1000 miles', () => {
expect(plane.range = 1000).toEqual(1000);
});
it('should create plane with a fuel efficiency of 0', () => {
expect(plane.fuelEfficiency = 0).toEqual(0);
});
it('should create plane with a maintenance rating of 0', () => {
expect(plane.maintenance = 0).toEqual(0);
});
it('should create plane with a production year of 1980', () => {
expect(plane.productionYear = '1980').toEqual('1980');
});
it('should create plane with a price > 1.00', () => {
expect(plane.price = 2).toBeGreaterThan(1.00);
});
});
So now it's all packed together with a single setup for the plane and then tests the base properties inside the plane. whew, starting to look cleaner.