diff options
Diffstat (limited to 'Timeline/ClientApp/src/app/todo-list-page')
3 files changed, 120 insertions, 13 deletions
diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts index a74ce3e6..7fc4164d 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts @@ -1,16 +1,45 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed, tick } from '@angular/core/testing'; + +import { defer, Observable } from 'rxjs'; import { TodoListPageComponent } from './todo-list-page.component'; +import { TodoListService, WorkItem } from './todo-list.service'; +import { By } from '@angular/platform-browser'; + +@Component({ + selector: 'mat-progress-bar', + template: '' +}) +class MatProgressBarStubComponent { + +} + +function asyncData<T>(data: T): Observable<T> { + return defer(() => Promise.resolve(data)); +} describe('TodoListPageComponent', () => { let component: TodoListPageComponent; let fixture: ComponentFixture<TodoListPageComponent>; beforeEach(async(() => { + const todoListService: jasmine.SpyObj<TodoListService> = jasmine.createSpyObj('TodoListService', ['getWorkItemList']); + + todoListService.getWorkItemList.and.returnValue(asyncData(<WorkItem[]>[{ + id: 0, title: 'Test title 1', closed: true + }, { + id: 1, title: 'Test title 2', closed: false + }])); + TestBed.configureTestingModule({ - declarations: [ TodoListPageComponent ] + declarations: [TodoListPageComponent, MatProgressBarStubComponent], + providers: [ + { provide: TodoListService, useValue: todoListService } + ], + schemas: [NO_ERRORS_SCHEMA] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { @@ -22,4 +51,15 @@ describe('TodoListPageComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should show progress bar during loading', () => { + expect(fixture.debugElement.query(By.css('mat-progress-bar'))).toBeTruthy(); + }); + + it('should hide progress bar after loading', async(() => { + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('mat-progress-bar'))).toBeFalsy(); + }); + })); }); diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts index 529ba8cc..7e88ca52 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts @@ -1,12 +1,79 @@ import { TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +import { TodoListService, WorkItem, AzureDevOpsAccessInfo, WiqlResult, WiqlWorkItemResult, WorkItemResult } from './todo-list.service'; -import { TodoListService } from './todo-list.service'; describe('TodoListServiceService', () => { - beforeEach(() => TestBed.configureTestingModule({})); + beforeEach(() => TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + })); it('should be created', () => { + + const service: TodoListService = TestBed.get(TodoListService); + expect(service).toBeTruthy(); + }); + + it('should work well', () => { const service: TodoListService = TestBed.get(TodoListService); expect(service).toBeTruthy(); + + const mockWorkItems: WorkItem[] = [{ + id: 0, + title: 'Test work item 1', + closed: true + }, { + id: 1, + title: 'Test work item 2', + closed: false + }]; + + service.getWorkItemList().subscribe(data => { + expect(data).toEqual(mockWorkItems); + }); + + const httpController: HttpTestingController = TestBed.get(HttpTestingController); + + const mockAccessInfo: AzureDevOpsAccessInfo = { + username: 'testusername', + personalAccessToken: 'testtoken', + organization: 'testorganization', + project: 'testproject' + }; + + httpController.expectOne('/api/TodoPage/AzureDevOpsAccessInfo').flush(mockAccessInfo); + + const mockWiqlWorkItems: WiqlWorkItemResult[] = [{ + id: 0, + url: `https://dev.azure.com/${mockAccessInfo.organization}/${mockAccessInfo.project}/_apis/wit/workItems/0` + }, { + id: 1, + url: `https://dev.azure.com/${mockAccessInfo.organization}/${mockAccessInfo.project}/_apis/wit/workItems/1` + }]; + + const authorizationHeader = 'Basic ' + btoa(mockAccessInfo.username + ':' + mockAccessInfo.personalAccessToken); + + httpController.expectOne(req => + req.url === `https://dev.azure.com/${mockAccessInfo.organization}/${mockAccessInfo.project}/_apis/wit/wiql?api-version=5.0` && + req.headers.get('Authorization') === authorizationHeader + ).flush(<WiqlResult>{ workItems: mockWiqlWorkItems }); + + function mapWorkItemToResult(workItem: WorkItem): WorkItemResult { + return { + id: workItem.id, + fields: { + [TodoListService.titleFieldName]: workItem.title, + [TodoListService.stateFieldName]: (workItem.closed ? 'Closed' : 'Active') + } + }; + } + + for (let i = 0; i < mockWorkItems.length; i++) { + httpController.expectOne(req => + req.url === mockWiqlWorkItems[i].url && + req.headers.get('Authorization') === authorizationHeader + ).flush(mapWorkItemToResult(mockWorkItems[i])); + } }); }); diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts index 0718b64b..619e9a6b 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts @@ -3,23 +3,23 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; import { switchMap, concatMap, map, toArray } from 'rxjs/operators'; -interface AzureDevOpsAccessInfo { +export interface AzureDevOpsAccessInfo { username: string; personalAccessToken: string; organization: string; project: string; } -interface WiqlWorkItemResult { +export interface WiqlWorkItemResult { id: number; url: string; } -interface WiqlResult { +export interface WiqlResult { workItems: WiqlWorkItemResult[]; } -interface WorkItemResult { +export interface WorkItemResult { id: number; fields: { [name: string]: any }; } @@ -36,8 +36,8 @@ export interface WorkItem { }) export class TodoListService { - private titleFieldName = 'System.Title'; - private stateFieldName = 'System.State'; + public static titleFieldName = 'System.Title'; + public static stateFieldName = 'System.State'; constructor(private client: HttpClient) { } @@ -61,8 +61,8 @@ export class TodoListService { concatMap(result => this.client.get<WorkItemResult>(result.url, { headers: headers })), map(result => <WorkItem>{ id: result.id, - title: <string>result.fields[this.titleFieldName], - closed: ((<string>result.fields[this.stateFieldName]).toLowerCase() === 'closed') + title: <string>result.fields[TodoListService.titleFieldName], + closed: ((<string>result.fields[TodoListService.stateFieldName]).toLowerCase() === 'closed') }), toArray() ); |