Commit 4fe9ab3e authored by Vitali Stupin's avatar Vitali Stupin

Loading configuration from assets

parent f0462062
import { Injectable } from '@angular/core';
import { AppConfig } from './app.config';
@Injectable()
export class AppConfigMock extends AppConfig {
private configMock: any = {
MAX_LIMIT: 1000000,
DEFAULT_LIMIT: 10,
INSTANCES: {
EE: 'https://www.x-tee.ee/catalogue/EE/wsdls/',
'ee-test': 'https://www.x-tee.ee/catalogue/ee-test/wsdls/',
'ee-dev': 'https://www.x-tee.ee/catalogue/ee-dev/wsdls/'
},
API_SERVICE: 'index.json',
LANGUAGES: {
EST: 'est',
ENG: 'eng'
},
PREVIEW_SIZE: 5,
FILTER_DEBOUNCE: 200
};
public getConfig(key: any) {
return this.configMock[key];
}
}
import { AppConfig } from './app.config';
import { of } from 'rxjs';
describe('AppConfig', () => {
let config: AppConfig;
let httpClientSpy: { get: jasmine.Spy };
beforeEach(() => {
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
config = new AppConfig(httpClientSpy as any);
});
it('should be created', () => {
expect(config).toBeTruthy();
});
it('should load configuration', async () => {
httpClientSpy.get.and.returnValue(of({TEST: 'OK'}));
await config.load();
expect(httpClientSpy.get).toHaveBeenCalledWith('./assets/config.json');
});
it('getConfig should work', async () => {
httpClientSpy.get.and.returnValue(of({TEST: 'OK'}));
await config.load();
expect(config.getConfig('TEST')).toBe('OK');
});
});
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class AppConfig {
private config: any = null;
constructor(private http: HttpClient) { }
/**
* Use to get the data found in the config file
*/
public getConfig(key: any) {
return this.config[key];
}
/**
* This method loads "config.json" to get all configuration variables
*/
public load() {
return new Promise(resolve => {
// Not handling errors. App cannot work without valid configuration
this.http.get<any>('./assets/config.json')
.subscribe(responseData => {
this.config = responseData;
resolve(true);
});
});
}
}
import { AppModule, HttpLoaderFactory } from './app.module';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { AppConfig } from './app.config';
import { TestBed } from '@angular/core/testing';
import { HttpClient } from 'selenium-webdriver/http';
describe('AppModule', () => {
let module: AppModule;
let appModule: AppModule;
let httpClientSpy: { get: jasmine.Spy };
beforeEach(() => {
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
module = new AppModule();
appModule = new AppModule();
});
it('should be created', () => {
expect(module).toBeTruthy();
expect(appModule).toBeTruthy();
});
it('HttpLoaderFactory should work', () => {
expect(HttpLoaderFactory(httpClientSpy as any) instanceof TranslateHttpLoader).toBeTruthy();
});
it('AppConfig should be initialized', async () => {
TestBed.configureTestingModule({
imports: [ AppModule ],
providers: [
{ provide: HttpClient, useValue: httpClientSpy }
]
});
expect(TestBed.get(AppConfig)).toBeTruthy();
});
});
......@@ -11,6 +11,8 @@ import { SubsystemItemComponent } from './subsystem-list/subsystem-item/subsyste
import { AppRoutingModule } from './app-routing.module';
import { SubsystemComponent } from './subsystem/subsystem.component';
import { HeaderComponent } from './header/header.component';
import { APP_INITIALIZER } from '@angular/core';
import { AppConfig } from './app.config';
@NgModule({
declarations: [
......@@ -34,7 +36,10 @@ import { HeaderComponent } from './header/header.component';
}
})
],
providers: [],
providers: [
AppConfig,
{ provide: APP_INITIALIZER, useFactory: (config: AppConfig) => () => config.load(), deps: [AppConfig], multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
......
export const MAX_LIMIT = 1000000;
export const DEFAULT_LIMIT = 10;
export const INSTANCES = {
EE: 'https://www.x-tee.ee/catalogue/EE/wsdls/',
'ee-test': 'https://www.x-tee.ee/catalogue/ee-test/wsdls/',
'ee-dev': 'https://www.x-tee.ee/catalogue/ee-dev/wsdls/'
};
export const API_SERVICE = 'index.json';
export const LANGUAGES = {
EST: 'est',
ENG: 'eng'
};
export const PREVIEW_SIZE = 5;
export const FILTER_DEBOUNCE = 200;
......@@ -3,6 +3,8 @@ import { TranslateModule } from '@ngx-translate/core';
import { HeaderComponent } from './header.component';
import { HttpClientModule } from '@angular/common/http';
import { LanguagesService } from '../languages.service';
import { AppConfigMock } from 'src/app/app.config-mock';
import { AppConfig } from 'src/app/app.config';
describe('HeaderComponent', () => {
let component: HeaderComponent;
......@@ -14,6 +16,9 @@ describe('HeaderComponent', () => {
imports: [
TranslateModule.forRoot(),
HttpClientModule
],
providers: [
{ provide: AppConfig, useClass: AppConfigMock }
]
})
.compileComponents();
......
import { TestBed } from '@angular/core/testing';
import { LanguagesService } from './languages.service';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { AppConfigMock } from 'src/app/app.config-mock';
import { AppConfig } from 'src/app/app.config';
import { HttpClientModule } from '@angular/common/http';
describe('LanguagesService', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot()
TranslateModule.forRoot(),
HttpClientModule
],
providers: [
{ provide: AppConfig, useClass: AppConfigMock }
]
}));
......
......@@ -3,7 +3,7 @@ import {TranslateService} from '@ngx-translate/core';
import { Title } from '@angular/platform-browser';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { LANGUAGES } from './config';
import { AppConfig } from './app.config';
@Injectable({
providedIn: 'root'
......@@ -14,10 +14,11 @@ export class LanguagesService {
constructor(
private translate: TranslateService,
private title: Title
private title: Title,
private config: AppConfig
) {
this.selectedLang = this.getDefaultLang();
translate.setDefaultLang(LANGUAGES[this.selectedLang]);
translate.setDefaultLang(this.config.getConfig('LANGUAGES')[this.selectedLang]);
this.updateTitle();
}
......@@ -34,11 +35,11 @@ export class LanguagesService {
if (window && window.localStorage && window.localStorage.getItem('lang')) {
return window.localStorage.getItem('lang');
}
return Object.keys(LANGUAGES)[0];
return Object.keys(this.config.getConfig('LANGUAGES'))[0];
}
getLangs(): string[] {
return Object.keys(LANGUAGES);
return Object.keys(this.config.getConfig('LANGUAGES'));
}
getLang(): string {
......@@ -50,7 +51,7 @@ export class LanguagesService {
if (window && window.localStorage) {
window.localStorage.setItem('lang', this.selectedLang);
}
this.translate.use(LANGUAGES[this.selectedLang]);
this.translate.use(this.config.getConfig('LANGUAGES')[this.selectedLang]);
this.updateTitle();
}
}
......@@ -4,6 +4,8 @@ import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { SearchComponent } from './search.component';
import { SubsystemsService } from 'src/app/subsystems.service';
import { AppConfigMock } from 'src/app/app.config-mock';
import { AppConfig } from 'src/app/app.config';
describe('SearchComponent', () => {
let component: SearchComponent;
......@@ -17,6 +19,9 @@ describe('SearchComponent', () => {
FormsModule,
TranslateModule.forRoot(),
HttpClientModule
],
providers: [
{ provide: AppConfig, useClass: AppConfigMock }
]
})
.compileComponents();
......
......@@ -5,8 +5,11 @@ import { SubsystemItemComponent } from './subsystem-item.component';
import { RouterTestingModule } from '@angular/router/testing';
import { SubsystemsService } from 'src/app/subsystems.service';
import { Router } from '@angular/router';
import { PREVIEW_SIZE } from '../../config';
import { Method } from 'src/app/method';
import { AppConfigMock } from 'src/app/app.config-mock';
import { AppConfig } from 'src/app/app.config';
const PREVIEW_SIZE = 5;
describe('SubsystemItemComponent', () => {
let component: SubsystemItemComponent;
......@@ -26,9 +29,9 @@ describe('SubsystemItemComponent', () => {
providers: [
{ provide: Router, useValue: {
navigateByUrl: jasmine.createSpy('navigateByUrl')
}}
}},
{ provide: AppConfig, useClass: AppConfigMock }
]
})
.compileComponents();
}));
......
......@@ -3,7 +3,7 @@ import { Subsystem } from '../../subsystem';
import { Method } from '../../method';
import { SubsystemsService } from '../../subsystems.service';
import { Router } from '@angular/router';
import { PREVIEW_SIZE } from '../../config';
import { AppConfig } from '../../app.config';
@Component({
selector: 'app-subsystem-item',
......@@ -15,7 +15,8 @@ export class SubsystemItemComponent implements OnInit {
constructor(
private subsystemsService: SubsystemsService,
private router: Router
private router: Router,
private config: AppConfig
) { }
getApiUrlBase(): string {
......@@ -23,14 +24,14 @@ export class SubsystemItemComponent implements OnInit {
}
getMethodsPreview(): Method[] {
return this.subsystem.methods.length ? this.subsystem.methods.slice(0, PREVIEW_SIZE) : [];
return this.subsystem.methods.length ? this.subsystem.methods.slice(0, this.config.getConfig('PREVIEW_SIZE')) : [];
}
getNotInPreview(): number {
if (this.subsystem.methods.length - PREVIEW_SIZE < 0) {
if (this.subsystem.methods.length - this.config.getConfig('PREVIEW_SIZE') < 0) {
return 0;
}
return this.subsystem.methods.length - PREVIEW_SIZE;
return this.subsystem.methods.length - this.config.getConfig('PREVIEW_SIZE');
}
showDetail() {
......
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { HttpClientModule } from '@angular/common/http';
import { RouterTestingModule } from '@angular/router/testing';
import { SubsystemListComponent } from './subsystem-list.component';
import { Component, Input } from '@angular/core';
import { Subsystem } from '../subsystem';
......@@ -9,6 +8,8 @@ import { ActivatedRoute, Router, Scroll } from '@angular/router';
import { of } from 'rxjs';
import { SubsystemsService } from '../subsystems.service';
import { ViewportScroller } from '@angular/common';
import { AppConfigMock } from 'src/app/app.config-mock';
import { AppConfig } from 'src/app/app.config';
@Component({selector: 'app-header', template: ''})
class HeaderStubComponent {}
......@@ -47,7 +48,8 @@ describe('SubsystemListComponent', () => {
{ provide: Router, useValue: {
events: of(new Scroll(null, [11, 12], null)),
navigateByUrl: jasmine.createSpy('navigateByUrl')
}}
}},
{ provide: AppConfig, useClass: AppConfigMock }
]
})
.compileComponents();
......
......@@ -7,6 +7,8 @@ import { Router, ActivatedRoute, Scroll } from '@angular/router';
import { of, BehaviorSubject } from 'rxjs';
import { SubsystemsService } from '../subsystems.service';
import { ViewportScroller } from '@angular/common';
import { AppConfigMock } from 'src/app/app.config-mock';
import { AppConfig } from 'src/app/app.config';
@Component({selector: 'app-header', template: ''})
class HeaderStubComponent {}
......@@ -40,7 +42,8 @@ describe('SubsystemComponent', () => {
{ provide: Router, useValue: {
events: of(new Scroll(null, [11, 12], null)),
navigateByUrl: jasmine.createSpy('navigateByUrl')
}}
}},
{ provide: AppConfig, useClass: AppConfigMock }
]
})
.compileComponents();
......
......@@ -4,15 +4,17 @@ import { Subsystem } from './subsystem';
import { Method } from './method';
import { HttpErrorResponse } from '@angular/common/http';
import { tick, fakeAsync } from '@angular/core/testing';
import { FILTER_DEBOUNCE, DEFAULT_LIMIT, INSTANCES } from './config';
import { AppConfigMock } from './app.config-mock';
describe('SubsystemsService', () => {
let httpClientSpy: { get: jasmine.Spy };
let service: SubsystemsService;
let config: AppConfigMock;
beforeEach(() => {
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
service = new SubsystemsService(httpClientSpy as any);
config = new AppConfigMock(httpClientSpy as any);
service = new SubsystemsService(httpClientSpy as any, config);
});
it('should be created', () => {
......@@ -206,18 +208,18 @@ describe('SubsystemsService', () => {
// Search member without methods
service.setFilter('MEMBER2');
// Waiting for a debounce time to apply filter
tick(FILTER_DEBOUNCE);
tick(config.getConfig('FILTER_DEBOUNCE'));
expect(service.filteredSubsystemsSubject.value).toEqual(expectedSubsystems1);
// Search member with multiple methods
service.setFilter('SERVICE2');
// Waiting for a debounce time to apply filter
tick(FILTER_DEBOUNCE);
tick(config.getConfig('FILTER_DEBOUNCE'));
expect(service.filteredSubsystemsSubject.value).toEqual(expectedSubsystems2);
// Search with limit
const sourceSubsystems2 = [];
for (let i = 0; i < DEFAULT_LIMIT + 1; i++) {
for (let i = 0; i < config.getConfig('DEFAULT_LIMIT') + 1; i++) {
sourceSubsystems2.push(
{
memberClass: 'CLASS',
......@@ -233,8 +235,8 @@ describe('SubsystemsService', () => {
service.subsystemsSubject.next(sourceSubsystems2);
service.setFilter('MEMBER');
// Waiting for a debounce time to apply filter
tick(FILTER_DEBOUNCE);
expect(service.filteredSubsystemsSubject.value.length).toEqual(DEFAULT_LIMIT);
tick(config.getConfig('FILTER_DEBOUNCE'));
expect(service.filteredSubsystemsSubject.value.length).toEqual(config.getConfig('DEFAULT_LIMIT'));
}));
it('should set limit', () => {
......@@ -268,18 +270,18 @@ describe('SubsystemsService', () => {
});
it('getLimit should work', () => {
expect(service.getLimit()).toEqual(DEFAULT_LIMIT.toString());
expect(service.getLimit()).toEqual(config.getConfig('DEFAULT_LIMIT').toString());
service.setLimit('all');
expect(service.getLimit()).toEqual('all');
});
it('getInstances should work', () => {
expect(service.getInstances()).toEqual(Object.keys(INSTANCES));
expect(service.getInstances()).toEqual(Object.keys(config.getConfig('INSTANCES')));
});
it('getDefaultInstance should work', () => {
expect(service.getDefaultInstance()).toEqual(Object.keys(INSTANCES)[0]);
expect(service.getDefaultInstance()).toEqual(Object.keys(config.getConfig('INSTANCES'))[0]);
});
it('getInstance should work', () => {
......
......@@ -4,14 +4,14 @@ import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
import { catchError, debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { Subsystem } from './subsystem';
import { Method } from './method';
import { MAX_LIMIT, DEFAULT_LIMIT, INSTANCES, API_SERVICE, FILTER_DEBOUNCE } from './config';
import { AppConfig } from './app.config';
@Injectable({
providedIn: 'root'
})
export class SubsystemsService {
private apiUrlBase = '';
private limit: number = DEFAULT_LIMIT;
private limit: number = this.config.getConfig('DEFAULT_LIMIT');
private nonEmpty = false;
private filter = '';
private instance = '';
......@@ -21,10 +21,13 @@ export class SubsystemsService {
warnings: EventEmitter<string> = new EventEmitter();
constructor(private http: HttpClient) {
constructor(
private http: HttpClient,
private config: AppConfig
) {
// Debouncing update of filter
this.updateFilter.pipe(
debounceTime(FILTER_DEBOUNCE),
debounceTime(this.config.getConfig('FILTER_DEBOUNCE')),
distinctUntilChanged()
).subscribe(() => {
this.updateFiltered();
......@@ -111,11 +114,11 @@ export class SubsystemsService {
}
getDefaultInstance(): string {
return Object.keys(INSTANCES)[0];
return Object.keys(this.config.getConfig('INSTANCES'))[0];
}
getInstances(): string[] {
return Object.keys(INSTANCES);
return Object.keys(this.config.getConfig('INSTANCES'));
}
getInstance(): string {
......@@ -124,13 +127,13 @@ export class SubsystemsService {
setInstance(instance: string) {
this.instance = instance;
this.apiUrlBase = INSTANCES[instance];
this.apiUrlBase = this.config.getConfig('INSTANCES')[instance];
// Reset only if has values (less refreshes)
if (this.subsystemsSubject.value.length) {
this.subsystemsSubject.next([]);
}
this.http.get<Subsystem[]>(this.apiUrlBase + API_SERVICE)
this.http.get<Subsystem[]>(this.apiUrlBase + this.config.getConfig('API_SERVICE'))
.pipe(
catchError(this.handleError([]))
).subscribe(subsystems => {
......@@ -144,11 +147,11 @@ export class SubsystemsService {
}
getApiUrl(): string {
return this.apiUrlBase + API_SERVICE;
return this.apiUrlBase + this.config.getConfig('API_SERVICE');
}
getLimit(): string {
if (this.limit === MAX_LIMIT) {
if (this.limit === this.config.getConfig('MAX_LIMIT')) {
return 'all';
}
return this.limit.toString();
......@@ -163,7 +166,7 @@ export class SubsystemsService {
this.limit = 50;
break;
case 'all':
this.limit = MAX_LIMIT;
this.limit = this.config.getConfig('MAX_LIMIT');
break;
default:
this.limit = 10;
......
{
"MAX_LIMIT": 1000000,
"DEFAULT_LIMIT": 10,
"INSTANCES": {
"EE": "https://www.x-tee.ee/catalogue/EE/wsdls/",
"ee-test": "https://www.x-tee.ee/catalogue/ee-test/wsdls/",
"ee-dev": "https://www.x-tee.ee/catalogue/ee-dev/wsdls/"
},
"API_SERVICE": "index.json",
"LANGUAGES": {
"EST": "est",
"ENG": "eng"
},
"PREVIEW_SIZE": 5,
"FILTER_DEBOUNCE": 200
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment