事件服务
为事件服务添加方法以支持事件的订阅/取消订阅功能。
目前,我们的仪表板仅显示用户自己创建的事件。在本章中,我们将为用户提供订阅其他用户创建事件的功能,这些事件也将被填充到仪表板的日历中。
我们将在事件查看页面中添加另一个模块,用于显示事件成员列表。除了成员列表外,我们还将添加一个按钮,允许用户订阅或取消订阅事件。
以下是更新后的代码。请使用此代码进行进一步修改。
No configuration found for ID: 4f5fd372c15923264d756085aeabbbc44573671b7ffee454e8bae60ad40a9801
我们将首先在 EventsService 中添加两个新的服务方法,包括 IsEventCreator() 和 Subscribe()。我们需要完成这个功能。
IsEventCreator()
isEventCreator() 服务方法用于判断当前用户是否是事件的创建者。该方法返回的布尔值将决定是否向用户显示订阅/取消订阅按钮。记住,事件创建者无法从自己的事件中取消订阅。
- 首先,在
EventsService的测试中为AuthService添加一个模拟对象。
1// src/app/services/events/events.service.spec.ts 2 3import { AuthService } from '../auth/auth.service'; 4 5class MockAuthService { 6 currentUser = jasmine.createSpy('currentUser').and.callFake(() => { 7 return { 8 'username': 'johndoe', 9 '_id': '58dab4f21342131b8c96787f' 10 }; 11 }); 12}
- 接下来,在
configureTestingModule中更新providers,提供AuthService,并用我们的MockAuthService覆盖其值。
1// src/app/services/events/events.service.spec.ts 2 3beforeEach(() => { 4 TestBed.configureTestingModule({ 5 imports: [HttpClientTestingModule], 6 providers: [ 7 EventsService, 8 { provide: AuthService, useClass: MockAuthService } 9 ] 10 }); 11 12 service = TestBed.get(EventsService); 13 http = TestBed.get(HttpTestingController); 14});
- 现在,为我们的新服务方法添加第一个测试。
1// src/app/services/events/events.service.spec.ts 2 3describe('isEventCreator', () => { 4 it('should return true if the event creator is the current user', () => { 5 const id = '58dab4f21342131b8c96787f'; 6 expect(service.isEventCreator(id)).toEqual(true); 7 }); 8});
- 设置一个
id变量,将其传递给我们的新服务方法,并添加断言:返回值应为true。
现在,在 EventsService 中实现 isEventCreator() 方法,如下所示:
- 导入
AuthService并将其注入服务的构造函数中。
1// src/app/services/events/events.service.ts 2 3import { AuthService } from '../auth/auth.service'; 4... 5 6constructor(private http: HttpClient, private authService: AuthService) { }
- 添加
isEventCreator()的实现。
1// src/app/services/events/events.service.ts 2 3isEventCreator(creatorId: string): boolean { 4 const user = this.authService.currentUser(); 5 return user._id === creatorId ? true : false; 6}
从 AuthService 中获取当前用户,然后将其 ID 与传入服务方法的 creatorId 进行比较。如果相等则返回 true,否则返回 false。
最后,再添加一个测试。
1// src/app/services/events/events.service.spec.ts 2 3describe('isEventCreator', () => { 4 it('should return true if the event creator is the current user', () => { 5 const id = '58dab4f21342131b8c96787f'; 6 expect(service.isEventCreator(id)).toEqual(true); 7 }); 8 9 it('should return false if the event creator is not the current user', () => { 10 const id = '12345'; 11 expect(service.isEventCreator(id)).toEqual(false); 12 }); 13});
将 id 更新为一个随机字符串,然后将断言改为:服务方法的返回值应为 false。
Subscribe()
接下来需要添加的服务方法是 subscribe() 方法,我们从测试开始。
-
首先声明三个变量:
eventId、subscriber和subscribeResponse。eventId变量是用户订阅的事件的 ID(即我们要更新的事件)。subscriber变量是一个对象,其属性设置为尝试订阅该事件的用户的 ID。subscribeResponse变量是我们期望从 API 接收到的响应。我们将从 API 文档中复制该内容。
-
调用新的服务方法,传入两个参数:
eventId和subscriber。 -
订阅该方法,并将响应赋值给本地的
response变量。 -
调用
.expectOne,传入服务方法应请求的 URL。然后,使用subscribeResponse响应进行刷新。
1// src/app/services/events/events.service.spec.ts 2 3describe('subscribe', () => { 4 it('should return an event with an updated members list', () => { 5 const eventId = '5a55135639fbc4ca3ee0ce5a'; 6 const subscriber = { user: '5a539449b689d341cccc4be7' }; 7 const subscribeResponse: Event = { 8 '_id': '5a55135639fbc4ca3ee0ce5a', 9 '_creator': '5a550ea739fbc4ca3ee0ce58', 10 'title': 'My first updated event', 11 'description': 'My first updated description', 12 'city': 'Miami', 13 'state': 'FL', 14 'startTime': '2018-01-09T19:00:00.000Z', 15 'endTime': '2018-01-09T20:00:00.000Z', 16 '__v': 1, 17 'suggestLocations': true, 18 'members': [ 19 { 20 '_id': '5a550ea739fbc4ca3ee0ce58', 21 'username': 'newUser', 22 '__v': 0, 23 'dietPreferences': [] 24 }, 25 { 26 '_id': '5a539449b689d341cccc4be7', 27 'username': 'adam', 28 '__v': 0, 29 'dietPreferences': [] 30 } 31 ] 32 }; 33 let response; 34 35 service.subscribe(eventId, subscriber).subscribe(res => { 36 response = res; 37 }); 38 39 http 40 .expectOne('{{EDUCATIVE_LIVE_VM_URL}}:3000/api/events/' + eventId + '/subscribe') 41 .flush(subscribeResponse); 42 expect(response).toEqual(subscribeResponse); 43 http.verify(); 44 }); 45});
现在我们可以实现 subscribe() 方法。
subscribe()方法接收eventId和user参数。- 调用
http.patch(),传入文档中指定的端点。确保将eventId拼接到请求 URL 中。 - 在 URL 之后,将第二个参数
user对象作为请求体传给.patch()。
1//src/app/services/events/events.service.ts 2 3subscribe(eventId: string, user: object): Observable<Event> { 4 return this.http.patch<Event>('{{EDUCATIVE_LIVE_VM_URL}}:3000/api/events/' + 5 eventId + '/subscribe', user); 6}
最后,再添加一个测试,用于验证服务方法返回错误的情况。
-
保持
eventId和subscriber变量不变,仅将响应更新为包含文档中列出错误信息的新error变量。 -
调用服务方法,订阅响应并将错误对象赋值给本地的
errorResponse变量。 -
设置服务应请求的预期 URL,这次使用错误响应进行刷新。
1// src/app/services/events/events.service.spec.ts 2 3describe('subscribe', () => { 4 it('should return an event with an updated members list', () => { 5 ... 6 }); 7 8 it('should return an error if a user cannot be subscribed to an event', () => { 9 const eventId = '5a55135639fbc4ca3ee0ce5a'; 10 const subscriber = { user: '5a539449b689d341cccc4be7' }; 11 const error = 'Something went wrong. Try again.'; 12 let errorResponse; 13 14 service.subscribe(eventId, subscriber).subscribe(res => {}, err => { 15 errorResponse = err; 16 }); 17 18 http 19 .expectOne('{{EDUCATIVE_LIVE_VM_URL}}:3000/api/events/' + eventId + '/subscribe') 20 .flush({message: error}, {status: 500, statusText: 'Server Error'}); 21 expect(errorResponse.error.message).toEqual(error); 22 http.verify(); 23 }); 24});
完成这些更改后,应有 68 个测试通过,还有一个测试被跳过。我们的代码应如下所示:
No configuration found for ID: 862ef4aff252fd50a6b57142bb64f39230f9b84c886c658e79cfdcd22e79c3b9