Skip to content

Commit 73fc18d

Browse files
committed
github service tests
1 parent 5f0b4b9 commit 73fc18d

1 file changed

Lines changed: 131 additions & 14 deletions

File tree

src/specs/service.github.spec.ts

Lines changed: 131 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ Unit tests for the GithubService service. We need to test...
1313
import * as sinon from 'sinon';
1414

1515
const fakeHttpService = {
16-
get: sinon.stub()
16+
get: sinon.stub().callsFake(() => new EventEmitter())
1717
};
1818

1919
const fakeUrlService = {
20-
urlToUser: sinon.stub(),
21-
urlToUserRepoListPage: sinon.stub()
20+
urlToUser: sinon.stub().callsFake(() => Symbol(`generated URL to user`)),
21+
urlToRepoList: sinon.stub().callsFake(() => Symbol(`generated URL to repos`))
2222
};
2323

2424
// --------------- Test config ---------------
@@ -28,11 +28,16 @@ import { UrlService } from '../services/urlservice';
2828
import { GithubService } from '../services/githubservice';
2929

3030
const testModuleConfig = {
31-
providers: [GithubService, {provide: HttpClient, useValue: fakeHttpService}, {provide: UrlService, useValue: fakeUrlService}]
31+
providers: [
32+
GithubService,
33+
{provide: HttpClient, useValue: fakeHttpService},
34+
{provide: UrlService, useValue: fakeUrlService}
35+
]
3236
}
3337

3438
// --------------- Test suite ---------------
3539

40+
import { EventEmitter } from '@angular/core';
3641
import { TestBed, getTestBed } from '@angular/core/testing';
3742
import { expect } from 'chai';
3843

@@ -44,7 +49,7 @@ describe('GithubService', () => {
4449

4550
beforeEach(() => {
4651
sinon.resetHistory();
47-
sinon.resetBehavior();
52+
fakeHttpService.get.callsFake(() => new EventEmitter())
4853
service = TestBed.get(GithubService);
4954
});
5055

@@ -54,27 +59,139 @@ describe('GithubService', () => {
5459

5560
describe('the getUser method', () => {
5661
const fakeUserId = Math.random().toString();
57-
const fakeUserUrl = Math.random().toString();
58-
const fakeGetObservable = Symbol();
62+
const resultListener = sinon.stub();
63+
5964
beforeEach(() => {
60-
fakeUrlService.urlToUser.returns(fakeUserUrl);
61-
fakeHttpService.get.returns(fakeGetObservable);
65+
service.getUser(fakeUserId).subscribe(resultListener);
6266
});
6367

6468
it('should call url service with id to get url to user', () => {
65-
service.getUser(fakeUserId);
6669
expect(fakeUrlService.urlToUser.called).to.be.true;
6770
expect(fakeUrlService.urlToUser.lastCall.args[0]).to.equal(fakeUserId);
6871
});
6972

7073
it('should pass the user url to .get method of the http service', () => {
71-
service.getUser(fakeUserId);
7274
expect(fakeHttpService.get.called).to.be.true;
73-
expect(fakeHttpService.get.lastCall.args[0]).to.equal(fakeUserUrl);
75+
expect(fakeHttpService.get.lastCall.args[0]).to.equal(fakeUrlService.urlToUser.lastCall.returnValue);
76+
});
77+
78+
it('should return an observable which emits the .get reply', () => {
79+
const fakeData = Symbol('some data');
80+
fakeHttpService.get.lastCall.returnValue.emit(fakeData);
81+
expect(resultListener.called).to.be.true;
82+
expect(resultListener.lastCall.args[0]).to.equal(fakeData);
83+
});
84+
});
85+
86+
describe('the getRepos method', () => {
87+
const fakeUserId = Symbol('some user ID');
88+
const resultListener = sinon.stub();
89+
90+
beforeEach(() => {
91+
service.getRepos(fakeUserId).subscribe(resultListener);
92+
});
93+
94+
it('should call url service with id to get url to first page of repo list', () => {
95+
expect(fakeUrlService.urlToRepoList.called).to.be.true;
96+
expect(fakeUrlService.urlToRepoList.lastCall.args[0]).to.equal(fakeUserId);
97+
expect(fakeUrlService.urlToRepoList.lastCall.args[1]).to.equal(1);
98+
});
99+
100+
it('should pass the repo list url to .get method of the http service', () => {
101+
expect(fakeHttpService.get.called).to.be.true;
102+
expect(fakeHttpService.get.lastCall.args[0]).to.equal(fakeUrlService.urlToRepoList.lastCall.returnValue);
103+
});
104+
105+
it('should not emit anything to returned stream before get stream emits', () => {
106+
expect(resultListener.called).to.be.false;
107+
});
108+
109+
describe('single page result', () => {
110+
const singlePageReply = {
111+
body: ['foo', 'bar'],
112+
headers: {
113+
get: sinon.stub().returns('') // if link string doesnt contain rel="next/last", then it is the last page
114+
}
115+
}
116+
beforeEach(() => {
117+
fakeHttpService.get.firstCall.returnValue.emit(singlePageReply);
118+
});
119+
it('should query the "link" header', () => {
120+
expect(singlePageReply.headers.get.callCount).to.equal(1);
121+
expect(singlePageReply.headers.get.firstCall.args[0]).to.equal("link");
122+
});
123+
it('should emit the body with the repos prop to the returned stream', () => {
124+
expect(resultListener.called).to.be.true;
125+
expect(resultListener.lastCall.args[0]).to.equal(singlePageReply.body);
126+
});
127+
it('should only have made a single get request', () => {
128+
expect(fakeHttpService.get.callCount).to.equal(1);
129+
});
74130
});
75131

76-
it('should return the return value from the get method', () => {
77-
expect(service.getUser(fakeUserId)).to.equal(fakeGetObservable);
132+
describe('multi page result, getting page 1/3', () => {
133+
const firstPage = {
134+
body: [1,2,3],
135+
headers: { get: () => 'rel="last" rel="next"' },
136+
};
137+
beforeEach(() => {
138+
fakeHttpService.get.firstCall.returnValue.emit(firstPage);
139+
});
140+
141+
it('should not emit anything', () => {
142+
expect(resultListener.called).to.be.false;
143+
});
144+
145+
it('should ask for the url to the second page', () => {
146+
expect(fakeUrlService.urlToRepoList.callCount).to.equal(2);
147+
expect(fakeUrlService.urlToRepoList.lastCall.args[0]).to.equal(fakeUserId);
148+
expect(fakeUrlService.urlToRepoList.lastCall.args[1]).to.equal(2);
149+
});
150+
151+
it('should make a get request for the second page', () => {
152+
expect(fakeHttpService.get.callCount).to.equal(2);
153+
expect(fakeHttpService.get.lastCall.args[0]).to.equal(fakeUrlService.urlToRepoList.lastCall.returnValue);
154+
});
155+
156+
describe('getting page 2/3', () => {
157+
const secondPage = {
158+
body: [4,5,6],
159+
headers: { get: () => 'rel="last" rel="next"' },
160+
};
161+
beforeEach(() => {
162+
fakeHttpService.get.secondCall.returnValue.emit(secondPage);
163+
});
164+
165+
it('should not emit anything', () => {
166+
expect(resultListener.called).to.be.false;
167+
});
168+
169+
it('should ask for the url to the third page', () => {
170+
expect(fakeUrlService.urlToRepoList.callCount).to.equal(3);
171+
expect(fakeUrlService.urlToRepoList.lastCall.args[0]).to.equal(fakeUserId);
172+
expect(fakeUrlService.urlToRepoList.lastCall.args[1]).to.equal(3);
173+
});
174+
175+
it('should make a get request for the third page', () => {
176+
expect(fakeHttpService.get.callCount).to.equal(3);
177+
expect(fakeHttpService.get.lastCall.args[0]).to.equal(fakeUrlService.urlToRepoList.lastCall.returnValue);
178+
});
179+
180+
describe('getting page 3/3', () => {
181+
const thirdPage = {
182+
body: [7,8,9],
183+
headers: { get: () => '' },
184+
};
185+
beforeEach(() => {
186+
fakeHttpService.get.thirdCall.returnValue.emit(thirdPage);
187+
});
188+
189+
it('should emit list of all repos to return stream', () => {
190+
expect(resultListener.called).to.be.true;
191+
expect(resultListener.lastCall.args[0]).to.eql([...firstPage.body, ...secondPage.body, ...thirdPage.body]);
192+
});
193+
});
194+
});
78195
});
79196
});
80197
});

0 commit comments

Comments
 (0)