Skip to content

Commit 4ebfb02

Browse files
author
David Sargent
committed
Improve unit tests
1 parent 37bec29 commit 4ebfb02

File tree

5 files changed

+80
-49
lines changed

5 files changed

+80
-49
lines changed

src/app/common/states/event-source.service.spec.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,32 @@ describe('EventSourceService', () => {
1313
providers: [EventSourceService]
1414
});
1515
eventSourceService = TestBed.get(EventSourceService);
16-
spyOn(eventSourceService, 'forUrl').and.returnValue(mockEventSource);
16+
spyOn(eventSourceService, '_forUrl').and.returnValue(mockEventSource);
1717
});
1818

1919
it('should be created', inject([EventSourceService], (service: EventSourceService) => {
2020
expect(service).toBeTruthy();
2121
}));
22+
23+
it('should properly called the error handler', (done => {
24+
eventSourceService.forUrl(uri, (eventSource) => {
25+
expect(eventSource).toBeTruthy();
26+
done();
27+
});
28+
sources[uri].emitError(null);
29+
}));
30+
31+
it('should properly ignore unspecified error handlers', (done => {
32+
eventSourceService.forUrl(uri, null);
33+
sources[uri].emitError(null);
34+
35+
setTimeout(() => {
36+
done();
37+
}, 3500);
38+
}));
39+
40+
it('should remember the connection after it is made', () => {
41+
eventSourceService.forUrl(uri, null);
42+
expect(eventSourceService['connections'][uri]).toBeTruthy();
43+
});
2244
});

src/app/common/states/event-source.service.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {isNullOrUndefined} from 'util';
44

55
@Injectable()
66
export class EventSourceService {
7+
readonly TIME_BETWEEN_RETRIES = 3;
78
private EventSource: any = window['EventSource'];
89
private connections: any = {};
910
constructor() { }
@@ -18,9 +19,13 @@ export class EventSourceService {
1819
return newCon.conn;
1920
}
2021

22+
_forUrl(url: string): EventSource {
23+
return new this.EventSource(url);
24+
}
25+
2126
private createEventStreamConnection(url: string, err: (EventSource) => void) {
2227
const newCon = {
23-
conn: new this.EventSource(url),
28+
conn: this._forUrl(url),
2429
errorHandler: err,
2530
errorHandlerCalled: false
2631
};
@@ -30,17 +35,20 @@ export class EventSourceService {
3035
return;
3136
}
3237
newCon.errorHandlerCalled = true;
33-
console.log('SSE Connection failed. Retrying in 5 seconds...');
38+
console.log(`SSE Connection failed. Retrying in ${this.TIME_BETWEEN_RETRIES} seconds...`);
3439
let connection = this.connections[url];
3540
let timeoutCalled = false;
3641
setTimeout(() => {
3742
if (connection != null && !timeoutCalled) {
3843
timeoutCalled = true;
3944
this.connections[url] = this.createEventStreamConnection(url, err);
40-
connection.errorHandler(this.connections[url]);
45+
if (typeof connection.errorHandler === 'function') {
46+
connection.errorHandler(this.connections[url]);
47+
}
48+
4149
connection = null;
4250
}
43-
}, 5000, this);
51+
}, this.TIME_BETWEEN_RETRIES * 1000, this);
4452
};
4553
return newCon;
4654
}

src/app/common/states/notification.service.spec.ts

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ import { TestBed, inject } from '@angular/core/testing';
22
import EventSourceMock, { sources } from 'eventsourcemock';
33
import { NotificationService } from './notification.service';
44
import {EventSourceService} from './event-source.service';
5-
import {StoreModule} from '@ngrx/store';
5+
import {Store, StoreModule} from '@ngrx/store';
66
import {reducers} from '../../action-reducer-map';
7+
import {UpdatePlannedRoute} from './actions/notification.action';
78

89
describe('NotificationService', () => {
10+
const DEFAULT_TIMEOUT = jasmine.DEFAULT_TIMEOUT_INTERVAL;
911
let uri: string;
1012

1113
beforeEach(() => {
14+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
1215
uri = 'http://localhost:1234/events';
1316
const mockEventSource = new EventSourceMock(uri);
1417

@@ -19,6 +22,8 @@ describe('NotificationService', () => {
1922
providers: [NotificationService, EventSourceService]
2023
});
2124
const eventSourceService = TestBed.get(EventSourceService);
25+
const store = TestBed.get(Store);
26+
spyOn(store, 'dispatch').and.callThrough();
2227
spyOn(eventSourceService, 'forUrl').and.returnValue(mockEventSource);
2328
});
2429

@@ -35,52 +40,50 @@ describe('NotificationService', () => {
3540
});
3641
}
3742

38-
it('should be able to update', (done) => {
39-
// Arrange
43+
it('should use the EventSourceService', () => {
44+
const eventSourceService = TestBed.get(EventSourceService);
4045
const service = TestBed.get(NotificationService);
41-
const source = sources[uri];
42-
const expectedCost = 1234.56;
43-
const expectedCostString = expectedCost.toLocaleString('en-US', { currency: 'USD', style: 'currency' });
44-
const message = mockNotificationEvent(NotificationService.ESTIMATED_PRICE, {
45-
cost: expectedCost
46-
});
4746

48-
// Act
49-
source.emitOpen();
50-
const observable = service.getCurrentPriceEstimate();
51-
observable.subscribe(val => {
52-
// Assert
53-
expect(val).toBe(expectedCostString);
54-
done();
55-
});
47+
service.onInit();
5648

57-
source.emitMessage(message);
49+
expect(eventSourceService.forUrl).toHaveBeenCalled();
5850
});
5951

60-
it('should use last available value', (done) => {
52+
it('should respond correctly to EventSource failing', () => {
53+
54+
const service = TestBed.get(NotificationService);
55+
const eventSourceService = TestBed.get(EventSourceService);
56+
spyOn(service, 'bindToNotificationEventSource').and.callThrough();
57+
//spyOn(eventSourceService, 'forUrl');
58+
59+
service.onInit();
60+
sources[uri].emitError(new Event(null, null));
61+
62+
expect(eventSourceService.forUrl).toHaveBeenCalledTimes(2);
63+
expect(service.bindToNotificationEventSource).toHaveBeenCalledTimes(1);
64+
});
65+
66+
it('should be able to update the app state', () => {
6167
// Arrange
68+
const store = TestBed.get(Store);
6269
const service = TestBed.get(NotificationService);
6370
const source = sources[uri];
64-
const expectedCost = 1248.16;
65-
const expectedCostString = expectedCost.toLocaleString('en-US', { currency: 'USD', style: 'currency' });
66-
const messageA = mockNotificationEvent(NotificationService.ESTIMATED_PRICE, {
67-
cost: 0.01
68-
});
69-
const messageB = mockNotificationEvent(NotificationService.ESTIMATED_PRICE, {
70-
cost: expectedCost
71-
});
71+
const expectedCost = 1234.56;
72+
let body = {
73+
cost: expectedCost,
74+
origin: null,
75+
destination: null,
76+
distance: 0,
77+
duration: 0
78+
};
79+
const message = mockNotificationEvent(NotificationService.ESTIMATED_PRICE, body);
7280

7381
// Act
7482
source.emitOpen();
75-
source.emitMessage(messageA);
76-
source.emitMessage(messageB);
77-
setTimeout(() => {
78-
const observable = service.getCurrentPriceEstimate();
79-
observable.subscribe(val => {
80-
// Assert
81-
expect(val).toBe(expectedCostString);
82-
done();
83-
});
84-
}, 1000);
83+
source.emitMessage(message);
84+
85+
// Assert
86+
expect(service._isActive).toBeTruthy();
87+
expect(store.dispatch).toHaveBeenCalledWith(new UpdatePlannedRoute(body));
8588
});
8689
});

src/app/common/states/notification.service.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export class NotificationService {
3535
private eventSourceService: EventSourceService,
3636
private zone: NgZone
3737
) {
38-
this.subject = new BehaviorSubject<any>({ RoutingKey: NotificationService.NOTHING, Data: null});
38+
this.subject = new BehaviorSubject<any>({ RoutingKey: NotificationService.NOTHING, Data: new Route() });
3939
this.onInit();
4040
}
4141

@@ -72,12 +72,9 @@ export class NotificationService {
7272

7373
listenForRouteUpdates() {
7474
this._subscription = this.newObservableForKey(NotificationService.ESTIMATED_PRICE).subscribe(next =>
75-
this.passengerStore.dispatch(new UpdatePlannedRoute(next as Route)));
76-
}
77-
78-
getCurrentPriceEstimate(): Observable<string> {
79-
return this.newObservableForKey(NotificationService.ESTIMATED_PRICE).map(val => {
80-
return val['cost'].toLocaleString('en-US', { style: 'currency', currency: 'USD' });
75+
{
76+
//console.log(next);
77+
this.passengerStore.dispatch(new UpdatePlannedRoute(next as Route))
8178
});
8279
}
8380

src/app/common/states/reducers/notification.reducer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ initialState.duration = 0;
99
export function notificationReducer(state: Route = initialState, action: PlannedRouteAction): Route {
1010
switch (action.type) {
1111
case 'UPDATE_ROUTE':
12+
console.log(action['data']);
1213
return (action as UpdatePlannedRoute).data;
1314

1415
default:

0 commit comments

Comments
 (0)