Skip to content

Commit d88978a

Browse files
author
Seth Davenport
committed
Get unit tests working
- move store initialization into the module level because as wirings stuff, it makes more sense there. This also makes the app component much easier to test by separating concerns better. - added many comments better explaining the wiring/store initialization.
1 parent 08b1e16 commit d88978a

21 files changed

+458
-235
lines changed

.angular-cli.json

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
33
"project": {
4-
"version": "1.0.0-beta.32.3",
54
"name": "example-app"
65
},
76
"apps": [
@@ -16,7 +15,8 @@
1615
"main": "main.ts",
1716
"polyfills": "polyfills.ts",
1817
"test": "test.ts",
19-
"tsconfig": "tsconfig.json",
18+
"tsconfig": "tsconfig.app.json",
19+
"testTsconfig": "tsconfig.spec.json",
2020
"prefix": "app",
2121
"styles": [
2222
"styles.css"
@@ -36,12 +36,13 @@
3636
},
3737
"lint": [
3838
{
39-
"files": "src/**/*.ts",
40-
"project": "src/tsconfig.json"
39+
"project": "src/tsconfig.app.json"
4140
},
4241
{
43-
"files": "e2e/**/*.ts",
44-
"project": "e2e/tsconfig.json"
42+
"project": "src/tsconfig.spec.json"
43+
},
44+
{
45+
"project": "e2e/tsconfig.e2e.json"
4546
}
4647
],
4748
"test": {

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ application.
1010
* [@angular-redux/form](https://github.com/angular-redux/form) Time travel with Angular forms
1111
* [Redux DevTools Chrome Extension](https://github.com/zalmoxisus/redux-devtools-extension)
1212

13-
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-beta.32.3.
13+
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-rc.0.
1414

1515
## Development server
16-
1716
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
1817

1918
## Code scaffolding

e2e/app.e2e-spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { ZooPage } from './app.po';
1+
import { ExampleAppPage } from './app.po';
22

3-
describe('zoo App', function() {
4-
let page: ZooPage;
3+
describe('example-app App', () => {
4+
let page: ExampleAppPage;
55

66
beforeEach(() => {
7-
page = new ZooPage();
7+
page = new ExampleAppPage();
88
});
99

1010
it('should display message saying app works', () => {

e2e/app.po.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { browser, element, by } from 'protractor';
22

3-
export class ZooPage {
3+
export class ExampleAppPage {
44
navigateTo() {
55
return browser.get('/');
66
}
77

88
getParagraphText() {
9-
return element(by.css('zoo-root h1')).getText();
9+
return element(by.css('app-root h1')).getText();
1010
}
1111
}

e2e/tsconfig.e2e.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"compilerOptions": {
3+
"sourceMap": true,
4+
"declaration": false,
5+
"moduleResolution": "node",
6+
"emitDecoratorMetadata": true,
7+
"experimentalDecorators": true,
8+
"lib": [
9+
"es2016"
10+
],
11+
"outDir": "../dist/out-tsc-e2e",
12+
"module": "commonjs",
13+
"target": "es6",
14+
"types":[
15+
"jasmine",
16+
"node"
17+
]
18+
}
19+
}

karma.conf.js

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ module.exports = function (config) {
2929
fixWebpackSourcePaths: true
3030
},
3131
angularCli: {
32-
config: './.angular-cli.json',
3332
environment: 'dev'
3433
},
3534
reporters: config.angularCli && config.angularCli.codeCoverage

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
"name": "example-app",
33
"version": "0.0.0",
44
"license": "MIT",
5-
"angular-cli": {},
65
"scripts": {
76
"ng": "ng",
87
"start": "ng serve",
8+
"build": "ng build",
99
"test": "ng test",
1010
"lint": "ng lint",
1111
"e2e": "ng e2e"
@@ -31,12 +31,12 @@
3131
"zone.js": "^0.7.6"
3232
},
3333
"devDependencies": {
34-
"@angular/cli": "1.0.0-beta.32.3",
34+
"@angular/cli": "1.0.0-rc.0",
3535
"@angular/compiler-cli": "^2.4.0",
3636
"@types/jasmine": "2.5.38",
3737
"@types/node": "~6.0.60",
3838
"@types/redux-logger": "^2.6.34",
39-
"codelyzer": "~2.0.0-beta.4",
39+
"codelyzer": "~2.0.0",
4040
"jasmine-core": "~2.5.2",
4141
"jasmine-spec-reporter": "~3.2.0",
4242
"karma": "~1.4.1",

protractor.conf.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Protractor configuration file, see link for more information
22
// https://github.com/angular/protractor/blob/master/lib/config.ts
33

4-
/*global jasmine */
54
const { SpecReporter } = require('jasmine-spec-reporter');
65

76
exports.config = {
@@ -22,7 +21,7 @@ exports.config = {
2221
},
2322
beforeLaunch: function() {
2423
require('ts-node').register({
25-
project: 'e2e'
24+
project: 'e2e/tsconfig.e2e.json'
2625
});
2726
},
2827
onPrepare() {

src/app/app.component.spec.ts

+29-21
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,42 @@
1-
/* tslint:disable:no-unused-variable */
2-
31
import { TestBed, async } from '@angular/core/testing';
2+
import { RouterTestingModule } from '@angular/router/testing';
3+
import { NgRedux, DevToolsExtension } from '@angular-redux/store';
44
import { AppComponent } from './app.component';
5+
import { AppActions } from './app.actions';
6+
7+
// I follow a minimal mocking approach:
8+
// Mock all dependencies with empty objects
9+
// and let each test specify the exact stub
10+
// or spy behaviour that it needs. This keeps
11+
// mocks simple and tests decoupled as they
12+
// should be.
13+
const mockRedux = {
14+
dispatch: function() {},
15+
};
16+
const mockDevTools = {};
517

618
describe('AppComponent', () => {
7-
beforeEach(() => {
19+
beforeEach(async(() => {
820
TestBed.configureTestingModule({
9-
declarations: [
10-
AppComponent
21+
declarations: [AppComponent],
22+
imports: [ RouterTestingModule ],
23+
providers: [
24+
{ provide: NgRedux, useValue: mockRedux },
25+
{ provide: DevToolsExtension, useValue: mockDevTools },
26+
AppActions,
1127
],
12-
});
13-
TestBed.compileComponents();
14-
});
28+
}).compileComponents();
29+
}));
1530

1631
it('should create the app', async(() => {
17-
let fixture = TestBed.createComponent(AppComponent);
18-
let app = fixture.debugElement.componentInstance;
32+
const fixture = TestBed.createComponent(AppComponent);
33+
const app = fixture.debugElement.componentInstance;
1934
expect(app).toBeTruthy();
2035
}));
2136

22-
it(`should have as title 'app works!'`, async(() => {
23-
let fixture = TestBed.createComponent(AppComponent);
24-
let app = fixture.debugElement.componentInstance;
25-
expect(app.title).toEqual('app works!');
26-
}));
27-
28-
it('should render title in a h1 tag', async(() => {
29-
let fixture = TestBed.createComponent(AppComponent);
30-
fixture.detectChanges();
31-
let compiled = fixture.debugElement.nativeElement;
32-
expect(compiled.querySelector('h1').textContent).toContain('app works!');
37+
it(`should have as title 'Welcome to the Zoo'`, async(() => {
38+
const fixture = TestBed.createComponent(AppComponent);
39+
const app = fixture.debugElement.componentInstance;
40+
expect(app.title).toEqual('Welcome to the Zoo');
3341
}));
3442
});

src/app/app.component.ts

+4-38
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,10 @@
11
import { Component } from '@angular/core';
2-
import { NgRedux, DevToolsExtension } from '@angular-redux/store';
3-
import { NgReduxRouter, routerReducer } from '@angular-redux/router';
4-
import { provideReduxForms, composeReducers, defaultFormReducer } from '@angular-redux/form';
5-
import { Action, combineReducers } from 'redux';
6-
import { createEpicMiddleware, combineEpics } from 'redux-observable';
7-
import * as createLogger from 'redux-logger';
2+
import { NgRedux } from '@angular-redux/store';
83

94
import { AppActions } from './app.actions';
10-
import { ElephantsEpics } from './elephants/elephants.epics';
11-
import { elephantsReducer } from './elephants/elephants.reducer';
12-
13-
import { LionsEpics } from './lions/lions.epics';
14-
import { lionsReducer } from './lions/lions.reducer';
155

166
@Component({
17-
selector: 'zoo-root',
7+
selector: 'app-root',
188
templateUrl: './app.component.html',
199
styleUrls: ['./app.component.css']
2010
})
@@ -24,33 +14,9 @@ export class AppComponent {
2414
constructor(
2515
private ngRedux: NgRedux<any>,
2616
private actions: AppActions,
27-
devTools: DevToolsExtension,
28-
ngReduxRouter: NgReduxRouter,
29-
elephantsEpics: ElephantsEpics,
30-
lionsEpics: LionsEpics
31-
) {
32-
const rootReducer = composeReducers(
33-
defaultFormReducer(),
34-
combineReducers({
35-
elephants: elephantsReducer,
36-
lions: lionsReducer,
37-
router: routerReducer,
38-
}));
39-
40-
ngRedux.configureStore(
41-
rootReducer,
42-
{},
43-
[
44-
createLogger(),
45-
createEpicMiddleware(combineEpics(...elephantsEpics.epics)),
46-
createEpicMiddleware(combineEpics(...lionsEpics.epics)),
47-
],
48-
devTools.isEnabled() ? [ devTools.enhancer() ] : []);
49-
ngReduxRouter.initialize();
50-
provideReduxForms(ngRedux);
51-
}
17+
) { }
5218

5319
ngOnInit() {
5420
this.ngRedux.dispatch(this.actions.loadData());
5521
}
56-
}
22+
}

src/app/app.module.ts

+69-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,45 @@
1+
// This is the application's top-level NgModule definition.
2+
//
3+
// Think of it as a wirings file: telling Angular where to
4+
// find our components and services, and telling Angular-redux
5+
// where to find our reducers, middleware, and epics.
6+
7+
// Basic Angular stuff.
18
import { BrowserModule } from '@angular/platform-browser';
29
import { NgModule } from '@angular/core';
310
import { FormsModule } from '@angular/forms';
411
import { RouterModule } from '@angular/router';
512
import { HttpModule } from '@angular/http';
6-
import { NgReduxModule } from '@angular-redux/store';
7-
import { NgReduxRouterModule } from '@angular-redux/router';
813

14+
// Angular-redux ecosystem stuff.
15+
// @angular-redux/form and @angular-redux/router are optional
16+
// extensions that sync form and route location state between
17+
// our store and Angular.
18+
import { NgReduxModule, NgRedux, DevToolsExtension } from '@angular-redux/store';
19+
import { NgReduxRouterModule, NgReduxRouter, routerReducer } from '@angular-redux/router';
20+
import { provideReduxForms, composeReducers, defaultFormReducer } from '@angular-redux/form';
21+
22+
// Redux ecosystem stuff.
23+
import { combineReducers } from 'redux';
24+
import * as createLogger from 'redux-logger';
25+
import { combineEpics, createEpicMiddleware } from 'redux-observable';
26+
27+
// Top-level app component constructs.
928
import { appRoutes } from './app.routes';
1029
import { AppComponent } from './app.component';
1130
import { AppActions } from './app.actions';
1231

32+
// Elephants module constructs.
1333
import { ElephantsModule } from './elephants/elephants.module';
34+
import { ElephantsEpics } from './elephants/elephants.epics';
35+
import { elephantsReducer } from './elephants/elephants.reducer';
36+
37+
// Lions module constructs.
1438
import { LionsModule } from './lions/lions.module';
39+
import { LionsEpics } from './lions/lions.epics';
40+
import { lionsReducer } from './lions/lions.reducer';
41+
42+
// Feedback module constructs.
1543
import { FeedbackModule } from './feedback/feedback.module';
1644

1745
@NgModule({
@@ -30,4 +58,42 @@ import { FeedbackModule } from './feedback/feedback.module';
3058
providers: [ AppActions ],
3159
bootstrap: [ AppComponent ]
3260
})
33-
export class AppModule {}
61+
export class AppModule {
62+
constructor(
63+
private ngRedux: NgRedux<any>,
64+
private actions: AppActions,
65+
devTools: DevToolsExtension,
66+
ngReduxRouter: NgReduxRouter,
67+
elephantsEpics: ElephantsEpics,
68+
lionsEpics: LionsEpics
69+
) {
70+
// Define the global store shape by combining our application's
71+
// reducers together into a given structure.
72+
const rootReducer = composeReducers(
73+
defaultFormReducer(),
74+
combineReducers({
75+
elephants: elephantsReducer,
76+
lions: lionsReducer,
77+
router: routerReducer,
78+
}));
79+
80+
// Tell Redux about our reducers and epics. If the Redux DevTools
81+
// chrome extension is available in the browser, tell Redux about
82+
// it too.
83+
ngRedux.configureStore(
84+
rootReducer,
85+
{},
86+
[
87+
createLogger(),
88+
createEpicMiddleware(combineEpics(...elephantsEpics.epics)),
89+
createEpicMiddleware(combineEpics(...lionsEpics.epics)),
90+
],
91+
devTools.isEnabled() ? [ devTools.enhancer() ] : []);
92+
93+
// Enable syncing of Angular router state with our Redux store.
94+
ngReduxRouter.initialize();
95+
96+
// Enable syncing of Angular form state with our Redux store.
97+
provideReduxForms(ngRedux);
98+
}
99+
}

src/app/app.routes.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { LionListComponent } from './lions/lion-list/lion-list.component';
33
import { FeedbackFormComponent } from './feedback/feedback-form/feedback-form.component';
44

55
export const appRoutes = [
6-
{ path: '', redirectTo: '/elephants', pathMatch: 'full' },
6+
{ path: '', redirectTo: '/elephants', pathMatch: 'full' },
77
{ path: 'elephants', component: ElephantListComponent },
88
{ path: 'lions', component: LionListComponent },
99
{ path: 'feedback', component: FeedbackFormComponent },

src/environments/environment.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// The file contents for the current environment will overwrite these during build.
22
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
33
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
4-
// The list of which env maps to which file can be found in `angular-cli.json`.
4+
// The list of which env maps to which file can be found in `.angular-cli.json`.
55

66
export const environment = {
77
production: false

src/index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
<html>
33
<head>
44
<meta charset="utf-8">
5-
<title>Zoo</title>
5+
<title>ExampleApp</title>
66
<base href="/">
77

88
<meta name="viewport" content="width=device-width, initial-scale=1">
99
<link rel="icon" type="image/x-icon" href="favicon.ico">
1010
</head>
1111
<body>
12-
<zoo-root>Loading...</zoo-root>
12+
<app-root>Loading...</app-root>
1313
</body>
1414
</html>

0 commit comments

Comments
 (0)