tests done except for sample and samples component

This commit is contained in:
VLE2FE 2020-06-22 10:22:45 +02:00
parent 0d77113704
commit 09598c4ba7
25 changed files with 474 additions and 267 deletions

View File

@ -3,6 +3,9 @@ import { AppComponent } from './app.component';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components'; import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
import {RouterTestingModule} from '@angular/router/testing'; import {RouterTestingModule} from '@angular/router/testing';
import {LoginService} from './services/login.service';
let loginServiceSpy: jasmine.SpyObj<LoginService>;
describe('AppComponent', () => { describe('AppComponent', () => {
let component: AppComponent; let component: AppComponent;
@ -10,13 +13,19 @@ describe('AppComponent', () => {
let css; // get native element by css selector let css; // get native element by css selector
beforeEach(async(() => { beforeEach(async(() => {
const loginSpy = jasmine.createSpyObj('LoginService', ['login', 'canActivate']);
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ AppComponent ], declarations: [ AppComponent ],
imports: [ imports: [
RbUiComponentsModule, RbUiComponentsModule,
RouterTestingModule RouterTestingModule
],
providers: [
{provide: LoginService, useValue: loginSpy}
] ]
}).compileComponents(); }).compileComponents();
loginServiceSpy = TestBed.inject(LoginService) as jasmine.SpyObj<LoginService>;
})); }));
beforeEach(() => { beforeEach(() => {

View File

@ -2,9 +2,10 @@ import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/t
import { LoginComponent } from './login.component'; import { LoginComponent } from './login.component';
import {LoginService} from '../services/login.service'; import {LoginService} from '../services/login.service';
import {ValidationService} from '../services/validation.service'; import {ValidationService} from '../services/validation.service';
import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
import {FormsModule} from '@angular/forms'; import {FormsModule} from '@angular/forms';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {ValidateDirective} from '../validate.directive';
import {RbUiComponentsModule} from '@inst-iot/bosch-angular-ui-components';
let validationServiceSpy: jasmine.SpyObj<ValidationService>; let validationServiceSpy: jasmine.SpyObj<ValidationService>;
let loginServiceSpy: jasmine.SpyObj<LoginService>; let loginServiceSpy: jasmine.SpyObj<LoginService>;
@ -20,7 +21,7 @@ describe('LoginComponent', () => {
const loginSpy = jasmine.createSpyObj('LoginService', ['login']); const loginSpy = jasmine.createSpyObj('LoginService', ['login']);
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ LoginComponent ], declarations: [ LoginComponent, ValidateDirective ],
imports: [ imports: [
RbUiComponentsModule, RbUiComponentsModule,
FormsModule FormsModule
@ -39,12 +40,15 @@ describe('LoginComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent); fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.ngOnInit();
fixture.detectChanges(); fixture.detectChanges();
cssd = (selector) => fixture.debugElement.query(By.css(selector)); cssd = (selector) => fixture.debugElement.query(By.css(selector));
css = (selector) => fixture.debugElement.query(By.css(selector)).nativeElement; css = (selector) => fixture.debugElement.query(By.css(selector)).nativeElement;
}); });
it('should create', () => { it('should create', () => {
validationServiceSpy.username.and.returnValue({ok: true, error: ''});
validationServiceSpy.password.and.returnValue({ok: true, error: ''});
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
@ -61,27 +65,45 @@ describe('LoginComponent', () => {
expect(css('.message').innerText).toBe(''); expect(css('.message').innerText).toBe('');
}); });
it('should have a login button', () => { it('should have a login button', async () => {
expect(css('.login-button')).toBeTruthy();
});
it('should display a message when a wrong username was entered', () => {
validationServiceSpy.username.and.returnValue({ok: false, error: 'username must only contain a-z0-9-_.'});
validationServiceSpy.password.and.returnValue({ok: true, error: ''});
cssd('.login-button').triggerEventHandler('click', null);
fixture.detectChanges();
expect(css('.error-messages > div').innerText).toBe('username must only contain a-z0-9-_.');
});
it('should display a message when a wrong password was entered', () => {
validationServiceSpy.username.and.returnValue({ok: true, error: ''}); validationServiceSpy.username.and.returnValue({ok: true, error: ''});
validationServiceSpy.password.and.returnValue({ok: true, error: ''});
await fixture.whenStable();
fixture.detectChanges();
expect(css('.login-button')).toBeTruthy();
expect(css('.login-button').disabled).toBeTruthy();
});
it('should reject a wrong username', async () => {
validationServiceSpy.username.and.returnValue({ok: false, error: 'username must only contain a-z0-9-_.'});
component.username = 'ab#';
fixture.detectChanges();
await fixture.whenRenderingDone();
expect(component.loginForm.controls.username.valid).toBeFalsy();
expect(validationServiceSpy.username).toHaveBeenCalledWith('ab#');
});
it('should reject a wrong password', async () => {
validationServiceSpy.password.and.returnValue({ok: false, error: 'password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'}); validationServiceSpy.password.and.returnValue({ok: false, error: 'password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'});
component.password = 'abc';
fixture.detectChanges();
await fixture.whenRenderingDone();
expect(component.loginForm.controls.password.valid).toBeFalsy();
expect(validationServiceSpy.password).toHaveBeenCalledWith('abc');
});
it('should enable the login button with valid credentials', async () => {
validationServiceSpy.username.and.returnValue({ok: true, error: ''});
validationServiceSpy.password.and.returnValue({ok: true, error: ''});
loginServiceSpy.login.and.returnValue(new Promise(r => r(true)));
fixture.detectChanges();
await fixture.whenRenderingDone();
cssd('.login-button').triggerEventHandler('click', null); cssd('.login-button').triggerEventHandler('click', null);
fixture.detectChanges(); expect(css('.login-button').disabled).toBeFalsy();
expect(css('.message').innerText).toBe('password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'); expect(loginServiceSpy.login.calls.count()).toBe(1);
expect(loginServiceSpy.login).not.toHaveBeenCalled();
}); });
it('should call the LoginService with valid credentials', () => { it('should call the LoginService with valid credentials', () => {

View File

@ -1,8 +1,7 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {ValidationService} from '../services/validation.service'; import {ValidationService} from '../services/validation.service';
import {LoginService} from '../services/login.service'; import {LoginService} from '../services/login.service';
// TODO: catch up with testing
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
@ -14,6 +13,7 @@ export class LoginComponent implements OnInit {
username = ''; // credentials username = ''; // credentials
password = ''; password = '';
message = ''; // message below login fields message = ''; // message below login fields
@ViewChild('loginForm') loginForm;
constructor( constructor(

View File

@ -0,0 +1,7 @@
import { BaseModel } from './base.model';
describe('BaseModel', () => {
it('should create an instance', () => {
expect(new BaseModel()).toBeTruthy();
});
});

View File

@ -0,0 +1,10 @@
export class BaseModel {
deserialize(input: any): this {
Object.assign(this, input);
return this;
}
sendFormat(): this {
return this;
}
}

View File

@ -1,13 +1,7 @@
import {Deserializable} from './deserializable.model'; import {BaseModel} from './base.model';
// TODO: put all deserialize methods in one place
export class CustomFieldsModel implements Deserializable{ export class CustomFieldsModel extends BaseModel {
name = ''; name = '';
qty = 0; qty = 0;
deserialize(input: any): this {
Object.assign(this, input);
return this;
}
} }

View File

@ -1,5 +0,0 @@
// import { DeserializableModel } from './deserializable.model';
//
// describe('DeserializableModel', () => {
//
// });

View File

@ -1,3 +0,0 @@
export interface Deserializable {
deserialize(input: any): this;
}

View File

@ -1,5 +0,0 @@
import { IdModel } from './id.model';
describe('IdModel', () => {
});

View File

@ -1,9 +1,8 @@
import _ from 'lodash'; import _ from 'lodash';
import {Deserializable} from './deserializable.model';
import {IdModel} from './id.model'; import {IdModel} from './id.model';
import {SendFormat} from './sendformat.model'; import {BaseModel} from './base.model';
export class MaterialModel implements Deserializable, SendFormat { export class MaterialModel extends BaseModel {
_id: IdModel = null; _id: IdModel = null;
name = ''; name = '';
supplier = ''; supplier = '';
@ -14,11 +13,6 @@ export class MaterialModel implements Deserializable, SendFormat {
private numberTemplate = {color: '', number: ''}; private numberTemplate = {color: '', number: ''};
numbers: {color: string, number: string}[] = [_.cloneDeep(this.numberTemplate)]; numbers: {color: string, number: string}[] = [_.cloneDeep(this.numberTemplate)];
deserialize(input: any): this {
Object.assign(this, input);
return this;
}
sendFormat() { sendFormat() {
return _.pick(this, ['name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers']); return _.pick(this, ['name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers']);
} }

View File

@ -1,15 +1,15 @@
import _ from 'lodash'; import _ from 'lodash';
import {IdModel} from './id.model'; import {IdModel} from './id.model';
import {SendFormat} from './sendformat.model'; import {BaseModel} from './base.model';
import {Deserializable} from './deserializable.model';
export class MeasurementModel implements Deserializable, SendFormat{ export class MeasurementModel extends BaseModel {
_id: IdModel = null; _id: IdModel = null;
sample_id: IdModel = null; sample_id: IdModel = null;
measurement_template: IdModel; measurement_template: IdModel;
values: {[prop: string]: any} = {}; values: {[prop: string]: any} = {};
constructor(measurementTemplate: IdModel = null) { constructor(measurementTemplate: IdModel = null) {
super();
this.measurement_template = measurementTemplate; this.measurement_template = measurementTemplate;
} }

View File

@ -1,11 +1,10 @@
import _ from 'lodash'; import _ from 'lodash';
import {Deserializable} from './deserializable.model';
import {IdModel} from './id.model'; import {IdModel} from './id.model';
import {SendFormat} from './sendformat.model';
import {MaterialModel} from './material.model'; import {MaterialModel} from './material.model';
import {MeasurementModel} from './measurement.model'; import {MeasurementModel} from './measurement.model';
import {BaseModel} from './base.model';
export class SampleModel implements Deserializable, SendFormat { export class SampleModel extends BaseModel {
_id: IdModel = null; _id: IdModel = null;
color = ''; color = '';
number = ''; number = '';

View File

@ -1,5 +0,0 @@
// import { SendformatModel } from './sendformat.model';
//
// describe('SendformatModel', () => {
//
// });

View File

@ -1,3 +0,0 @@
export interface SendFormat {
sendFormat(omit?: string[]): {[prop: string]: any};
}

View File

@ -1,14 +1,9 @@
import {Deserializable} from './deserializable.model';
import {IdModel} from './id.model'; import {IdModel} from './id.model';
import {BaseModel} from './base.model';
export class TemplateModel implements Deserializable{ export class TemplateModel extends BaseModel {
_id: IdModel = null; _id: IdModel = null;
name = ''; name = '';
version = 1; version = 1;
parameters: {name: string, range: {[prop: string]: any}}[] = []; parameters: {name: string, range: {[prop: string]: any}}[] = [];
deserialize(input: any): this {
Object.assign(this, input);
return this;
}
} }

View File

@ -1,3 +1,4 @@
<script src="rb-table.component.ts"></script>
<table> <table>
<ng-content></ng-content> <ng-content></ng-content>
</table> </table>

View File

@ -1,25 +1,27 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; // import { async, ComponentFixture, TestBed } from '@angular/core/testing';
//
import { SampleComponent } from './sample.component'; // import { SampleComponent } from './sample.component';
//
describe('SampleComponent', () => { // // TODO
let component: SampleComponent; //
let fixture: ComponentFixture<SampleComponent>; // describe('SampleComponent', () => {
// let component: SampleComponent;
beforeEach(async(() => { // let fixture: ComponentFixture<SampleComponent>;
TestBed.configureTestingModule({ //
declarations: [ SampleComponent ] // beforeEach(async(() => {
}) // TestBed.configureTestingModule({
.compileComponents(); // declarations: [ SampleComponent ]
})); // })
// .compileComponents();
beforeEach(() => { // }));
fixture = TestBed.createComponent(SampleComponent); //
component = fixture.componentInstance; // beforeEach(() => {
fixture.detectChanges(); // fixture = TestBed.createComponent(SampleComponent);
}); // component = fixture.componentInstance;
// fixture.detectChanges();
it('should create', () => { // });
expect(component).toBeTruthy(); //
}); // it('should create', () => {
}); // expect(component).toBeTruthy();
// });
// });

View File

@ -1,25 +1,27 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; // import { async, ComponentFixture, TestBed } from '@angular/core/testing';
//
import { SamplesComponent } from './samples.component'; // import { SamplesComponent } from './samples.component';
//
describe('SamplesComponent', () => { // // TODO
let component: SamplesComponent; //
let fixture: ComponentFixture<SamplesComponent>; // describe('SamplesComponent', () => {
// let component: SamplesComponent;
beforeEach(async(() => { // let fixture: ComponentFixture<SamplesComponent>;
TestBed.configureTestingModule({ //
declarations: [ SamplesComponent ] // beforeEach(async(() => {
}) // TestBed.configureTestingModule({
.compileComponents(); // declarations: [ SamplesComponent ]
})); // })
// .compileComponents();
beforeEach(() => { // }));
fixture = TestBed.createComponent(SamplesComponent); //
component = fixture.componentInstance; // beforeEach(() => {
fixture.detectChanges(); // fixture = TestBed.createComponent(SamplesComponent);
}); // component = fixture.componentInstance;
// fixture.detectChanges();
it('should create', () => { // });
expect(component).toBeTruthy(); //
}); // it('should create', () => {
}); // expect(component).toBeTruthy();
// });
// });

View File

@ -1,53 +1,136 @@
// import { TestBed } from '@angular/core/testing'; import {async, TestBed} from '@angular/core/testing';
// import { ApiService } from './api.service'; import { ApiService } from './api.service';
// import {HttpClient} from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
// import {LocalStorageService} from 'angular-2-local-storage'; import {LocalStorageService} from 'angular-2-local-storage';
// import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
// import {ModalService} from '@inst-iot/bosch-angular-ui-components';
// let apiService: ApiService;
// let httpClientSpy: jasmine.SpyObj<HttpClient>; let apiService: ApiService;
// let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>; let httpClientSpy: jasmine.SpyObj<HttpClient>;
// let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
// describe('ApiService', () => { let modalServiceSpy: jasmine.SpyObj<ModalService>;
// beforeEach(() => {
// const httpSpy = jasmine.createSpyObj('HttpClient', ['get']); // TODO: test options
// const localStorageSpy = jasmine.createSpyObj('LocalStorageService', ['get']);
// describe('ApiService', () => {
// TestBed.configureTestingModule({ beforeEach(() => {
// providers: [ const httpSpy = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']);
// ApiService, const localStorageSpy = jasmine.createSpyObj('LocalStorageService', ['get']);
// {provide: HttpClient, useValue: httpSpy}, const modalSpy = jasmine.createSpyObj('ModalService', ['openComponent']);
// {provide: LocalStorageService, useValue: localStorageSpy}
// ] TestBed.configureTestingModule({
// }); providers: [
// ApiService,
// apiService = TestBed.inject(ApiService); {provide: HttpClient, useValue: httpSpy},
// httpClientSpy = TestBed.inject(HttpClient) as jasmine.SpyObj<HttpClient>; {provide: LocalStorageService, useValue: localStorageSpy},
// localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj<LocalStorageService>; {provide: ModalService, useValue: modalSpy}
// }); ]
// });
// it('should be created', () => {
// expect(apiService).toBeTruthy(); apiService = TestBed.inject(ApiService);
// }); httpClientSpy = TestBed.inject(HttpClient) as jasmine.SpyObj<HttpClient>;
// localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj<LocalStorageService>;
// it('should do get requests without auth if not available', () => { modalServiceSpy = TestBed.inject(ModalService) as jasmine.SpyObj<ModalService>;
// const getReturn = new Observable(); });
// httpClientSpy.get.and.returnValue(getReturn);
// localStorageServiceSpy.get.and.returnValue(undefined); it('should be created', () => {
// expect(apiService).toBeTruthy();
// const result = apiService.get('/testurl'); });
// expect(result).toBe(getReturn);
// expect(httpClientSpy.get).toHaveBeenCalledWith('/testurl', {}); it('shows an error message when the request fails', () => {
// expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth'); const getReturn = new Observable(observer => {
// }); observer.error('error');
// it('should do get requests with basic auth if available', () => { });
// const getReturn = new Observable(); httpClientSpy.get.and.returnValue(getReturn);
// httpClientSpy.get.and.returnValue(getReturn); localStorageServiceSpy.get.and.returnValue(undefined);
// localStorageServiceSpy.get.and.returnValue('basicAuth'); modalServiceSpy.openComponent.and.returnValue({instance: {message: ''}} as any);
//
// const result = apiService.get('/testurl'); apiService.get('/testurl');
// expect(result).toBe(getReturn); expect(httpClientSpy.get).toHaveBeenCalledWith('/api/testurl', {});
// expect(httpClientSpy.get).toHaveBeenCalledWith('/testurl', jasmine.any(Object)); // could not test http headers better expect(modalServiceSpy.openComponent.calls.count()).toBe(1);
// expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth'); });
// });
// }); it('returns the error message if the callback function had an error parameter', () => {
const getReturn = new Observable(observer => {
observer.error('error');
});
httpClientSpy.get.and.returnValue(getReturn);
localStorageServiceSpy.get.and.returnValue(undefined);
modalServiceSpy.openComponent.and.returnValue({instance: {message: ''}} as any);
apiService.get('/testurl', (data, error) => {
expect(modalServiceSpy.openComponent.calls.count()).toBe(0);
expect(error).toBe('error');
});
});
it('should do get requests without auth if not available', async(() => {
const getReturn = new Observable(observer => {
observer.next('data');
});
httpClientSpy.get.and.returnValue(getReturn);
localStorageServiceSpy.get.and.returnValue(undefined);
apiService.get('/testurl', res => {
expect(res).toBe('data');
expect(httpClientSpy.get).toHaveBeenCalledWith('/api/testurl', {});
expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth');
});
}));
it('should do get requests with basic auth if available', async(() => {
const getReturn = new Observable(observer => {
observer.next('data');
});
httpClientSpy.get.and.returnValue(getReturn);
localStorageServiceSpy.get.and.returnValue('basicAuth');
apiService.get('/testurl', res => {
expect(res).toBe('data');
expect(httpClientSpy.get).toHaveBeenCalledWith('/api/testurl', jasmine.any(Object)); // could not test http headers better
expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth');
});
}));
it('should do post requests', async(() => {
const resReturn = new Observable(observer => {
observer.next('data');
});
httpClientSpy.post.and.returnValue(resReturn);
localStorageServiceSpy.get.and.returnValue('basicAuth');
apiService.post('/testurl', 'reqData', res => {
expect(res).toBe('data');
expect(httpClientSpy.post).toHaveBeenCalledWith('/api/testurl', 'reqData', jasmine.any(Object));
expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth');
});
}));
it('should do put requests', async(() => {
const resReturn = new Observable(observer => {
observer.next('data');
});
httpClientSpy.put.and.returnValue(resReturn);
localStorageServiceSpy.get.and.returnValue('basicAuth');
apiService.put('/testurl', 'reqData', res => {
expect(res).toBe('data');
expect(httpClientSpy.put).toHaveBeenCalledWith('/api/testurl', 'reqData', jasmine.any(Object));
expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth');
});
}));
it('should do delete requests', async(() => {
const resReturn = new Observable(observer => {
observer.next('data');
});
httpClientSpy.delete.and.returnValue(resReturn);
localStorageServiceSpy.get.and.returnValue('basicAuth');
apiService.delete('/testurl', res => {
expect(res).toBe('data');
expect(httpClientSpy.delete).toHaveBeenCalledWith('/api/testurl', jasmine.any(Object));
expect(localStorageServiceSpy.get).toHaveBeenCalledWith('basicAuth');
});
}));
});

View File

@ -5,6 +5,7 @@ import {Observable} from 'rxjs';
import {ErrorComponent} from '../error/error.component'; import {ErrorComponent} from '../error/error.component';
import {ModalService} from '@inst-iot/bosch-angular-ui-components'; import {ModalService} from '@inst-iot/bosch-angular-ui-components';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
@ -37,9 +38,14 @@ export class ApiService {
private requestErrorHandler<T>(observable: Observable<any>, f: (data?: T, err?) => void) { private requestErrorHandler<T>(observable: Observable<any>, f: (data?: T, err?) => void) {
observable.subscribe(data => { observable.subscribe(data => {
f(data, undefined); f(data, undefined);
}, () => { }, err => {
if (f.length === 2) {
f(undefined, err);
}
else {
const modalRef = this.modalService.openComponent(ErrorComponent); const modalRef = this.modalService.openComponent(ErrorComponent);
modalRef.instance.message = 'Network request failed!'; modalRef.instance.message = 'Network request failed!';
}
}); });
} }

View File

@ -2,15 +2,34 @@ import { TestBed } from '@angular/core/testing';
import { AutocompleteService } from './autocomplete.service'; import { AutocompleteService } from './autocomplete.service';
let autocompleteService: AutocompleteService;
describe('AutocompleteService', () => { describe('AutocompleteService', () => {
let service: AutocompleteService;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({}); TestBed.configureTestingModule({
service = TestBed.inject(AutocompleteService); providers: [AutocompleteService]
});
autocompleteService = TestBed.inject(AutocompleteService);
}); });
it('should be created', () => { it('should be created', () => {
expect(service).toBeTruthy(); expect(autocompleteService).toBeTruthy();
});
it('should should return a bind function', () => {
expect(autocompleteService.bind('a', ['b'])).toBeTruthy();
});
it('should return search results', () => {
autocompleteService.search(['aa', 'ab', 'bb'], 'a').subscribe(res => {
expect(res).toEqual(['aa', 'ab']);
});
});
it('should return an empty array if no result was found', () => {
autocompleteService.search(['aa', 'ab', 'bb'], 'c').subscribe(res => {
expect(res).toEqual([]);
});
}); });
}); });

View File

@ -9,11 +9,11 @@ export class AutocompleteService {
constructor() { } constructor() { }
bind(ref, list) { bind(ref, list: string[]) {
return this.search.bind(ref, list); return this.search.bind(ref, list);
} }
search(arr, str) { search(arr: string[], str: string) {
const qs = new QuickScore(arr); const qs = new QuickScore(arr);
return of(str === '' ? [] : qs.search(str).map(e => e.item)); return of(str === '' ? [] : qs.search(str).map(e => e.item));
} }

View File

@ -1,81 +1,87 @@
// import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
//
// import { LoginService } from './login.service'; import { LoginService } from './login.service';
// import {LocalStorageService} from 'angular-2-local-storage'; import {LocalStorageService} from 'angular-2-local-storage';
// import {ApiService} from './api.service'; import {ApiService} from './api.service';
// import {Observable} from 'rxjs';
// let loginService: LoginService;
// let loginService: LoginService; let apiServiceSpy: jasmine.SpyObj<ApiService>;
// let apiServiceSpy: jasmine.SpyObj<ApiService>; let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
// let localStorageServiceSpy: jasmine.SpyObj<LocalStorageService>;
// describe('LoginService', () => {
// describe('LoginService', () => { beforeEach(() => {
// beforeEach(() => { const apiSpy = jasmine.createSpyObj('ApiService', ['get']);
// const apiSpy = jasmine.createSpyObj('ApiService', ['get']); const localStorageSpy = jasmine.createSpyObj('LocalStorageService', ['set', 'remove']);
// const localStorageSpy = jasmine.createSpyObj('LocalStorageService', ['set', 'remove']);
// TestBed.configureTestingModule({
// TestBed.configureTestingModule({ providers: [
// providers: [ LoginService,
// LoginService, {provide: ApiService, useValue: apiSpy},
// {provide: ApiService, useValue: apiSpy}, {provide: LocalStorageService, useValue: localStorageSpy}
// {provide: LocalStorageService, useValue: localStorageSpy} ]
// ] });
// }); loginService = TestBed.inject(LoginService);
// loginService = TestBed.inject(LoginService); apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
// apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>; localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj<LocalStorageService>;
// localStorageServiceSpy = TestBed.inject(LocalStorageService) as jasmine.SpyObj<LocalStorageService>; });
// });
// it('should be created', () => {
// it('should be created', () => { expect(loginService).toBeTruthy();
// expect(loginService).toBeTruthy(); });
// });
// describe('login', () => {
// describe('login', () => { it('should store the basic auth', () => {
// it('should store the basic auth', () => { localStorageServiceSpy.set.and.returnValue(true);
// localStorageServiceSpy.set.and.returnValue(true); apiServiceSpy.get.and.callFake(() => {});
// apiServiceSpy.get.and.returnValue(new Observable()); loginService.login('username', 'password');
// loginService.login('username', 'password'); expect(localStorageServiceSpy.set).toHaveBeenCalledWith('basicAuth', 'dXNlcm5hbWU6cGFzc3dvcmQ=');
// expect(localStorageServiceSpy.set).toHaveBeenCalledWith('basicAuth', 'dXNlcm5hbWU6cGFzc3dvcmQ='); });
// });
// it('should remove the basic auth if login fails', () => {
// it('should remove the basic auth if login fails', () => { localStorageServiceSpy.set.and.returnValue(true);
// localStorageServiceSpy.set.and.returnValue(true); localStorageServiceSpy.remove.and.returnValue(true);
// localStorageServiceSpy.remove.and.returnValue(true); apiServiceSpy.get.and.callFake((a, b) => {b(undefined, 'error'); });
// apiServiceSpy.get.and.returnValue(new Observable(o => o.error())); loginService.login('username', 'password');
// loginService.login('username', 'password'); expect(localStorageServiceSpy.remove.calls.count()).toBe(1);
// expect(localStorageServiceSpy.remove.calls.count()).toBe(1); expect(localStorageServiceSpy.remove).toHaveBeenCalledWith('basicAuth');
// expect(localStorageServiceSpy.remove).toHaveBeenCalledWith('basicAuth'); });
// });
// it('should resolve true when login succeeds', async () => {
// it('should resolve true when login succeeds', async () => { localStorageServiceSpy.set.and.returnValue(true);
// localStorageServiceSpy.set.and.returnValue(true); apiServiceSpy.get.and.callFake((a, b) => {b({status: 'Authorization successful', method: 'basic'} as any, undefined); });
// apiServiceSpy.get.and.returnValue(new Observable(o => o.next({status: 'Authorization successful', method: 'basic'}))); expect(await loginService.login('username', 'password')).toBeTruthy();
// expect(await loginService.login('username', 'password')).toBeTruthy(); });
// });
// it('should resolve false when a wrong result comes in', async () => {
// it('should resolve false when a wrong result comes in', async () => { localStorageServiceSpy.set.and.returnValue(true);
// localStorageServiceSpy.set.and.returnValue(true); apiServiceSpy.get.and.callFake((a, b) => {b({status: 'xxx', method: 'basic'} as any, undefined); });
// apiServiceSpy.get.and.returnValue(new Observable(o => o.next({status: 'xxx', method: 'basic'}))); expect(await loginService.login('username', 'password')).toBeFalsy();
// expect(await loginService.login('username', 'password')).toBeFalsy(); });
// });
// it('should resolve false on an error', async () => {
// it('should resolve false on an error', async () => { localStorageServiceSpy.set.and.returnValue(true);
// localStorageServiceSpy.set.and.returnValue(true); apiServiceSpy.get.and.callFake((a, b) => {b(undefined, 'error'); });
// apiServiceSpy.get.and.returnValue(new Observable(o => o.error())); expect(await loginService.login('username', 'password')).toBeFalsy();
// expect(await loginService.login('username', 'password')).toBeFalsy(); });
// }); });
// });
// describe('canActivate', () => {
// describe('canActivate', () => { it('should return false at first', done => {
// it('should return false at first', () => { apiServiceSpy.get.and.callFake((a, b) => {b(undefined, 'error'); });
// expect(loginService.canActivate(null, null)).toBeFalsy(); loginService.canActivate(null, null).subscribe(res => {
// }); expect(res).toBeFalsy();
// done();
// it('returns true if login was successful', async () => { });
// localStorageServiceSpy.set.and.returnValue(true); });
// apiServiceSpy.get.and.returnValue(new Observable(o => o.next({status: 'Authorization successful', method: 'basic'})));
// await loginService.login('username', 'password'); it('returns true if login was successful', async done => {
// expect(loginService.canActivate(null, null)).toBeTruthy(); localStorageServiceSpy.set.and.returnValue(true);
// }); apiServiceSpy.get.and.callFake((a, b) => {b({status: 'Authorization successful', method: 'basic'} as any, undefined); });
// }); await loginService.login('username', 'password');
// }); loginService.canActivate(null, null).subscribe(res => {
expect(res).toBeTruthy();
done();
});
});
});
});

View File

@ -28,8 +28,87 @@ describe('ValidationService', () => {
expect(validationService.password('Abc123!#')).toEqual({ok: true, error: ''}); expect(validationService.password('Abc123!#')).toEqual({ok: true, error: ''});
}); });
it('should return an error on an incorrect password', () => { it('should return an error on a password too short', () => {
expect(validationService.password('Abc123')).toEqual({ok: false, error: 'password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'}); expect(validationService.password('Abc123')).toEqual({ok: false, error: 'password must have at least 8 characters'});
}); });
it('should return an error on a password without a lowercase letter', () => {
expect(validationService.password('ABC123!#')).toEqual({ok: false, error: 'password must have at least one lowercase character'});
});
it('should return an error on a password without an uppercase letter', () => {
expect(validationService.password('abc123!#')).toEqual({ok: false, error: 'password must have at least one uppercase character'});
});
it('should return an error on a password without a number', () => {
expect(validationService.password('Abcabc!#')).toEqual({ok: false, error: 'password must have at least one number'});
});
it('should return an error on a password without a special character', () => {
expect(validationService.password('Abc12345')).toEqual({ok: false, error: 'password must have at least one of the following characters !"#%&\'()*+,-.\\/:;<=>?@[]^_`{|}~'});
});
it('should return an error on a password with a character not allowed', () => {
expect(validationService.password('Abc123!€')).toEqual({ok: false, error: 'password must only contain a-zA-Z0-9!"#%&\'()*+,-./:;<=>?@[]^_`{|}~'});
});
it('should return true on a correct string', () => {
expect(validationService.string('Abc')).toEqual({ok: true, error: ''});
});
it('should return an error on a string too long', () => {
expect(validationService.string('abcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbabcabcabcbabcbabcabcabacbacab')).toEqual({ok: false, error: 'must contain max 128 characters'});
});
it('should return true on a string in the list', () => {
expect(validationService.stringOf('Abc', ['Abc', 'Def'])).toEqual({ok: true, error: ''});
});
it('should return an error on a string not in the list', () => {
expect(validationService.stringOf('abc', ['Abc', 'Def'])).toEqual({ok: false, error: 'must be one of Abc, Def'});
});
it('should return true on a string of correct length', () => {
expect(validationService.stringLength('Abc', 5)).toEqual({ok: true, error: ''});
});
it('should return an error on a string longer than specified', () => {
expect(validationService.stringLength('Abc', 2)).toEqual({ok: false, error: 'must contain max 2 characters'});
});
it('should return true on a number in the range', () => {
expect(validationService.minMax(2, -2, 2)).toEqual({ok: true, error: ''});
});
it('should return an error on a number below the range', () => {
expect(validationService.minMax(0, 1, 3)).toEqual({ok: false, error: 'must be between 1 and 3'});
});
it('should return an error on a number above the range', () => {
expect(validationService.minMax(3.1, 1, 3)).toEqual({ok: false, error: 'must be between 1 and 3'});
});
it('should return true on a number above min', () => {
expect(validationService.min(2, -2)).toEqual({ok: true, error: ''});
});
it('should return an error on a number below min', () => {
expect(validationService.min(0, 1)).toEqual({ok: false, error: 'must not be below 1'});
});
it('should return true on a number below max', () => {
expect(validationService.max(2, 2)).toEqual({ok: true, error: ''});
});
it('should return an error on a number above max', () => {
expect(validationService.max(2, 1)).toEqual({ok: false, error: 'must not be above 1'});
});
it('should return true on a string not in the list', () => {
expect(validationService.unique('Abc', ['Def', 'Ghi'])).toEqual({ok: true, error: ''});
});
it('should return an error on a string from the list', () => {
expect(validationService.unique('Abc', ['Abc', 'Def'])).toEqual({ok: false, error: 'values must be unique'});
});
}); });

View File

@ -107,7 +107,7 @@ export class ValidationService {
} }
max(data, max) { max(data, max) {
const {ignore, error} = Joi.number().allow('').min(max).validate(data); const {ignore, error} = Joi.number().allow('').max(max).validate(data);
if (error) { if (error) {
return {ok: false, error: `must not be above ${max}`}; return {ok: false, error: `must not be above ${max}`};
} }