55143: fixed all tests

This commit is contained in:
lotte
2018-10-11 12:02:40 +02:00
parent 7c16ccafd3
commit 3a8f7754fa
56 changed files with 1389 additions and 1256 deletions

View File

@@ -41,8 +41,8 @@
"server:watch": "nodemon dist/server.js",
"server:watch:debug": "nodemon --debug dist/server.js",
"webpack:watch": "webpack -w --mode development",
"watch": "yarn run build && npm-run-all -p webpack:watch server:watch --mode development",
"watch:debug": "yarn run build && npm-run-all -p webpack:watch server:watch:debug --mode development",
"watch": "yarn run build && npm-run-all -p webpack:watch server:watch",
"watch:debug": "yarn run build && npm-run-all -p webpack:watch server:watch:debug",
"predebug": "yarn run build",
"predebug:server": "yarn run build",
"debug": "node --debug-brk dist/server.js",

View File

@@ -14,7 +14,6 @@ import { PaginationComponent } from '../../../shared/pagination/pagination.compo
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
import { HostWindowService } from '../../../shared/host-window.service';
describe('MetadataRegistryComponent', () => {
let comp: MetadataRegistryComponent;
let fixture: ComponentFixture<MetadataRegistryComponent>;
@@ -68,5 +67,4 @@ describe('MetadataRegistryComponent', () => {
const mockName: HTMLElement = fixture.debugElement.query(By.css('#metadata-schemas tr:nth-child(2) td:nth-child(3)')).nativeElement;
expect(mockName.textContent).toBe('mock');
});
});

View File

@@ -1,8 +1,9 @@
import {combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs';
import { Component, OnInit } from '@angular/core';
import { RemoteData } from '../../core/data/remote-data';
import { PaginatedList } from '../../core/data/paginated-list';
import { ItemDataService } from '../../core/data/item-data.service';
import { Observable, Subscription } from 'rxjs';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { ActivatedRoute } from '@angular/router';
@@ -45,7 +46,7 @@ export class BrowseByAuthorPageComponent implements OnInit {
sort: this.sortConfig
});
this.subs.push(
Observable.combineLatest(
observableCombineLatest(
this.route.params,
this.route.queryParams,
(params, queryParams, ) => {

View File

@@ -1,9 +1,10 @@
import {combineLatest as observableCombineLatest, Observable , Subscription } from 'rxjs';
import { Component, OnInit } from '@angular/core';
import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { PaginatedList } from '../../core/data/paginated-list';
import { ItemDataService } from '../../core/data/item-data.service';
import { Observable , Subscription } from 'rxjs';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { Item } from '../../core/shared/item.model';
@@ -44,7 +45,7 @@ export class BrowseByTitlePageComponent implements OnInit {
sort: this.sortConfig
});
this.subs.push(
Observable.combineLatest(
observableCombineLatest(
this.route.params,
this.route.queryParams,
(params, queryParams, ) => {

View File

@@ -159,7 +159,7 @@ export class SearchConfigurationService implements OnDestroy {
Object.keys(filterParams).forEach((key) => {
if (key.endsWith('.min') || key.endsWith('.max')) {
const realKey = key.slice(0, -4);
if (hasNoValue(filters.find((filter) => filter.key === realKey))) {
if (hasNoValue(filters.find((f) => f.key === realKey))) {
const min = filterParams[realKey + '.min'] ? filterParams[realKey + '.min'][0] : '*';
const max = filterParams[realKey + '.max'] ? filterParams[realKey + '.max'][0] : '*';
filters.push(new SearchFilter(realKey, ['[' + min + ' TO ' + max + ']']));

View File

@@ -1,5 +1,4 @@
import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs';
import { distinctUntilChanged, filter, map, mergeMap, tap } from 'rxjs/operators';
import { Inject, Injectable } from '@angular/core';
import { HALEndpointService } from '../shared/hal-endpoint.service';

View File

@@ -2,20 +2,18 @@ import { AuthStatusResponse } from '../cache/response-cache.models';
import { ObjectCacheService } from '../cache/object-cache.service';
import { GlobalConfig } from '../../../config/global-config.interface';
import { Store } from '@ngrx/store';
import { CoreState } from '../core.reducers';
import { AuthStatus } from './models/auth-status.model';
import { AuthResponseParsingService } from './auth-response-parsing.service';
import { AuthGetRequest, AuthPostRequest } from '../data/request.models';
import { getMockStore } from '../../shared/mocks/mock-store';
import { MockStore } from '../../shared/testing/mock-store';
import { ObjectCacheState } from '../cache/object-cache.reducer';
describe('AuthResponseParsingService', () => {
let service: AuthResponseParsingService;
const EnvConfig = { cache: { msToLive: 1000 } } as GlobalConfig;
const store = getMockStore() as Store<CoreState>;
const objectCacheService = new ObjectCacheService(store);
const store = new MockStore<ObjectCacheState>({});
const objectCacheService = new ObjectCacheService(store as any);
beforeEach(() => {
service = new AuthResponseParsingService(EnvConfig, objectCacheService);

View File

@@ -4,8 +4,7 @@ import { provideMockActions } from '@ngrx/effects/testing';
import { Store } from '@ngrx/store';
import { cold, hot } from 'jasmine-marbles';
import { Observable } from 'rxjs';
import { of as observableOf, throwError as observableThrow } from 'rxjs';
import { Observable, of as observableOf, throwError as observableThrow } from 'rxjs';
import { AuthEffects } from './auth.effects';
import {
@@ -30,16 +29,21 @@ import { EPersonMock } from '../../shared/testing/eperson-mock';
describe('AuthEffects', () => {
let authEffects: AuthEffects;
let actions: Observable<any>;
const authServiceStub = new AuthServiceStub();
let authServiceStub;
const store: Store<TruncatablesState> = jasmine.createSpyObj('store', {
/* tslint:disable:no-empty */
dispatch: {},
/* tslint:enable:no-empty */
select: observableOf(true)
});
const token = authServiceStub.getToken();
let token;
function init() {
authServiceStub = new AuthServiceStub();
token = authServiceStub.getToken();
}
beforeEach(() => {
init();
TestBed.configureTestingModule({
providers: [
AuthEffects,
@@ -138,7 +142,7 @@ describe('AuthEffects', () => {
describe('when check token failed', () => {
it('should return a CHECK_AUTHENTICATION_TOKEN_ERROR action in response to a CHECK_AUTHENTICATION_TOKEN action', () => {
spyOn((authEffects as any).authService, 'hasValidAuthenticationToken').and.returnValue(Observable.throw(''));
spyOn((authEffects as any).authService, 'hasValidAuthenticationToken').and.returnValue(observableThrow(''));
actions = hot('--a-', {a: {type: AuthActionTypes.CHECK_AUTHENTICATION_TOKEN, payload: token}});

View File

@@ -1,4 +1,4 @@
import { of as observableOf, throwError as observableThrowError , Observable } from 'rxjs';
import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs';
import { catchError, filter, map } from 'rxjs/operators';
import { Injectable, Injector } from '@angular/core';
@@ -11,8 +11,6 @@ import {
HttpResponse,
HttpResponseBase
} from '@angular/common/http';
import { find } from 'lodash';
import { AppState } from '../../app.reducer';

View File

@@ -31,24 +31,36 @@ describe('AuthService test', () => {
pipe: observableOf(true)
});
let authService: AuthService;
const authRequest = new AuthRequestServiceStub();
let authRequest;
const window = new NativeWindowRef();
const routerStub = new RouterStub();
const routeStub = new ActivatedRouteStub();
let routeStub;
let storage: CookieService;
const token: AuthTokenInfo = new AuthTokenInfo('test_token');
let token: AuthTokenInfo;
let authenticatedState;
const rdbService = getMockRemoteDataBuildService();
function init() {
token = new AuthTokenInfo('test_token');
token.expires = Date.now() + (1000 * 60 * 60);
let authenticatedState = {
authenticatedState = {
authenticated: true,
loaded: true,
loading: false,
authToken: token,
user: EPersonMock
};
const rdbService = getMockRemoteDataBuildService();
describe('', () => {
authRequest = new AuthRequestServiceStub();
routeStub = new ActivatedRouteStub();
}
beforeEach(() => {
init();
});
describe('', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
CommonModule,
@@ -115,6 +127,7 @@ describe('AuthService test', () => {
describe('', () => {
beforeEach(async(() => {
init();
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({ authReducer })

View File

@@ -1,13 +1,14 @@
import { of as observableOf, Observable , Observable } from 'rxjs';
import { Observable, of as observableOf } from 'rxjs';
import {
take,
filter,
startWith,
first,
distinctUntilChanged,
filter,
first,
map,
startWith,
switchMap,
take,
withLatestFrom
, map, switchMap, withLatestFrom } from 'rxjs/operators';
} from 'rxjs/operators';
import { Inject, Injectable } from '@angular/core';
import { PRIMARY_OUTLET, Router, UrlSegmentGroup, UrlTree } from '@angular/router';
import { HttpHeaders } from '@angular/common/http';

View File

@@ -140,7 +140,7 @@ export class ErrorResponse extends RestResponse {
constructor(error: RequestError) {
super(false, error.statusText);
console.error(error);
// console.error(error);
this.errorMessage = error.message;
}
}

View File

@@ -10,11 +10,18 @@ describe('BrowseResponseParsingService', () => {
beforeEach(() => {
service = new BrowseResponseParsingService();
});
let validRequest;
let validResponse;
let invalidResponse1;
let invalidResponse2;
let invalidResponse3;
let definitions;
describe('parse', () => {
const validRequest = new BrowseEndpointRequest('client/b186e8ce-e99c-4183-bc9a-42b4821bdb78', 'https://rest.api/discover/browses');
beforeEach(() => {
validRequest = new BrowseEndpointRequest('client/b186e8ce-e99c-4183-bc9a-42b4821bdb78', 'https://rest.api/discover/browses');
const validResponse = {
validResponse = {
payload: {
_embedded: {
browses: [{
@@ -51,7 +58,7 @@ describe('BrowseResponseParsingService', () => {
}, statusCode: '200'
} as DSpaceRESTV2Response;
const invalidResponse1 = {
invalidResponse1 = {
payload: {
_embedded: {
browse: {
@@ -74,21 +81,21 @@ describe('BrowseResponseParsingService', () => {
}, statusCode: '200'
} as DSpaceRESTV2Response;
const invalidResponse2 = {
invalidResponse2 = {
payload: {
_links: { self: { href: 'https://rest.api/discover/browses' } },
page: { size: 20, totalElements: 2, totalPages: 1, number: 0 }
}, statusCode: '200'
} as DSpaceRESTV2Response;
const invalidResponse3 = {
invalidResponse3 = {
payload: {
_links: { self: { href: 'https://rest.api/discover/browses' } },
page: { size: 20, totalElements: 2, totalPages: 1, number: 0 }
}, statusCode: '500'
} as DSpaceRESTV2Response;
const definitions = [
definitions = [
Object.assign(new BrowseDefinition(), {
metadataBrowse: false,
sortOptions: [
@@ -110,7 +117,10 @@ describe('BrowseResponseParsingService', () => {
metadataKeys: [
'dc.date.issued'
],
_links: { }
_links: {
self: 'https://rest.api/discover/browses/dateissued',
items: 'https://rest.api/discover/browses/dateissued/items'
}
}),
Object.assign(new BrowseDefinition(), {
metadataBrowse: true,
@@ -134,10 +144,14 @@ describe('BrowseResponseParsingService', () => {
'dc.contributor.*',
'dc.creator'
],
_links: { }
_links: {
self: 'https://rest.api/discover/browses/author',
entries: 'https://rest.api/discover/browses/author/entries',
items: 'https://rest.api/discover/browses/author/items'
}
})
];
});
it('should return a GenericSuccessResponse if data contains a valid browse endpoint response', () => {
const response = service.parse(validRequest, validResponse);
expect(response.constructor).toBe(GenericSuccessResponse);

View File

@@ -1,5 +1,5 @@
import { Observable, throwError as observableThrowError, merge as observableMerge } from 'rxjs';
import { distinctUntilChanged, filter, first, map, mergeMap, tap } from 'rxjs/operators';
import { distinctUntilChanged, filter, map, mergeMap, take, tap } from 'rxjs/operators';
import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs';
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
import { NormalizedCommunity } from '../cache/models/normalized-community.model';
import { ObjectCacheService } from '../cache/object-cache.service';
@@ -10,7 +10,6 @@ import { DataService } from './data.service';
import { FindAllOptions, FindByIDRequest } from './request.models';
import { NormalizedObject } from '../cache/models/normalized-object.model';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { DSOSuccessResponse } from '../cache/response-cache.models';
export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> {
protected abstract cds: CommunityDataService;
@@ -31,14 +30,14 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
if (isEmpty(options.scopeID)) {
return this.halService.getEndpoint(this.linkPath);
} else {
const scopeCommunityHrefObs = this.cds.getEndpoint()
.flatMap((endpoint: string) => this.cds.getFindByIDHref(endpoint, options.scopeID))
.filter((href: string) => isNotEmpty(href))
.take(1)
.do((href: string) => {
const scopeCommunityHrefObs = this.cds.getEndpoint().pipe(
mergeMap((endpoint: string) => this.cds.getFindByIDHref(endpoint, options.scopeID)),
filter((href: string) => isNotEmpty(href)),
take(1),
tap((href: string) => {
const request = new FindByIDRequest(this.requestService.generateRequestId(), href, options.scopeID);
this.requestService.configure(request);
});
}),);
// return scopeCommunityHrefObs.pipe(
// mergeMap((href: string) => this.responseCache.get(href)),

View File

@@ -41,7 +41,7 @@ export class CommunityDataService extends ComColDataService<NormalizedCommunity,
findTop(options: FindAllOptions = {}): Observable<RemoteData<PaginatedList<Community>>> {
const hrefObs = this.halService.getEndpoint(this.topLinkPath).pipe(filter((href: string) => isNotEmpty(href)),
mergeMap((endpoint: string) => this.getFindAllHref(endpoint, options)),);
mergeMap((endpoint: string) => this.getFindAllHref(options)),);
hrefObs.pipe(
filter((href: string) => hasValue(href)),

View File

@@ -9,6 +9,7 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
import { Observable } from 'rxjs';
import { FindAllOptions } from './request.models';
import { SortOptions, SortDirection } from '../cache/models/sort-options.model';
import { of as observableOf } from 'rxjs';
const endpoint = 'https://rest.api/core';
@@ -29,7 +30,7 @@ class TestService extends DataService<NormalizedTestObject, any> {
}
public getBrowseEndpoint(options: FindAllOptions): Observable<string> {
return Observable.of(endpoint);
return observableOf(endpoint);
}
}

View File

@@ -1,4 +1,4 @@
import { filter, take, first } from 'rxjs/operators';
import { distinctUntilChanged, filter, take, first, map } from 'rxjs/operators';
import { of as observableOf, Observable } from 'rxjs';
import { Store } from '@ngrx/store';
import { hasValue, isNotEmpty } from '../../shared/empty.util';
@@ -12,8 +12,6 @@ import { RemoteData } from './remote-data';
import { FindAllOptions, FindAllRequest, FindByIDRequest, GetRequest } from './request.models';
import { RequestService } from './request.service';
import { NormalizedObject } from '../cache/models/normalized-object.model';
import { promise } from 'selenium-webdriver';
import map = promise.map;
export abstract class DataService<TNormalized extends NormalizedObject, TDomain> {
protected abstract responseCache: ResponseCacheService;
@@ -29,7 +27,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
let result: Observable<string>;
const args = [];
result = this.getBrowseEndpoint(options).distinctUntilChanged();
result = this.getBrowseEndpoint(options).pipe(distinctUntilChanged());
if (hasValue(options.currentPage) && typeof options.currentPage === 'number') {
/* TODO: this is a temporary fix for the pagination start index (0 or 1) discrepancy between the rest and the frontend respectively */

View File

@@ -1,3 +1,5 @@
import {distinctUntilChanged, map, filter} from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
@@ -40,10 +42,10 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
if (options.sort && options.sort.field) {
field = options.sort.field;
}
return this.bs.getBrowseURLFor(field, this.linkPath)
.filter((href: string) => isNotEmpty(href))
.map((href: string) => new URLCombiner(href, `?scope=${options.scopeID}`).toString())
.distinctUntilChanged();
return this.bs.getBrowseURLFor(field, this.linkPath).pipe(
filter((href: string) => isNotEmpty(href)),
map((href: string) => new URLCombiner(href, `?scope=${options.scopeID}`).toString()),
distinctUntilChanged(),);
}
}

View File

@@ -1,37 +0,0 @@
import { select } from '@ngrx/store';
import * as ngrx from '@ngrx/store';
import { cold, hot } from 'jasmine-marbles';
import { Observable } from 'rxjs';
import { count, take } from 'rxjs/operators';
class TestClass {
selectSomething(input$: Observable<any>) {
return input$.pipe(
select('something'),
take(1)
)
}
}
describe('mockSelect', () => {
let testClass;
beforeEach(() => {
spyOnProperty(ngrx, 'select').and.callFake(() => {
return () => {
return () => cold('a', { a: 'bingo!' });
};
});
testClass = new TestClass();
});
it('should mock select', () => {
const input$ = hot('a', { a: '' });
const expected$ = hot('(b|)', { b: 'bingo!' });
const result$ = testClass.selectSomething(input$);
result$.pipe(count()).subscribe((t) => console.log('resykts', t));
expected$.pipe(count()).subscribe((t) => console.log('expected', t));
result$.subscribe((v) => console.log('result$', v));
expected$.subscribe((v) => console.log('expected$', v));
expect(result$).toBeObservable(expected$)
});
})

View File

@@ -1,16 +1,6 @@
import {distinctUntilKeyChanged, map, filter, first, take} from 'rxjs/operators';
import { distinctUntilKeyChanged, filter, first, map, take } from 'rxjs/operators';
import { Inject, Injectable } from '@angular/core';
import {
ActivatedRoute,
Event,
NavigationEnd,
Params,
Router
} from '@angular/router';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Meta, MetaDefinition, Title } from '@angular/platform-browser';
@@ -23,7 +13,6 @@ import { Bitstream } from '../shared/bitstream.model';
import { CacheableObject } from '../cache/object-cache.reducer';
import { DSpaceObject } from '../shared/dspace-object.model';
import { Item } from '../shared/item.model';
import { Metadatum } from '../shared/metadatum.model';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { BitstreamFormat } from '../shared/bitstream-format.model';

View File

@@ -22,23 +22,28 @@ describe('AuthNavMenuComponent', () => {
let deNavMenuItem: DebugElement;
let fixture: ComponentFixture<AuthNavMenuComponent>;
const notAuthState: AuthState = {
let notAuthState: AuthState;
let authState: AuthState;
let routerState = {
url: '/home'
};
function init() {
notAuthState = {
authenticated: false,
loaded: false,
loading: false
};
const authState: AuthState = {
authState = {
authenticated: true,
loaded: true,
loading: false,
authToken: new AuthTokenInfo('test_token'),
user: EPersonMock
};
let routerState = {
url: '/home'
};
}
describe('when is a not mobile view', () => {
beforeEach(async(() => {
const window = new HostWindowServiceStub(800);
@@ -54,7 +59,12 @@ describe('AuthNavMenuComponent', () => {
],
providers: [
{ provide: HostWindowService, useValue: window },
{provide: AuthService, useValue: {setRedirectUrl: () => { /*empty*/ }}}
{
provide: AuthService, useValue: {
setRedirectUrl: () => { /*empty*/
}
}
}
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
@@ -64,11 +74,14 @@ describe('AuthNavMenuComponent', () => {
}));
beforeEach(() => {
init();
});
describe('when route is /login and user is not authenticated', () => {
beforeEach(inject([Store], (store: Store<AppState>) => {
routerState = {
url: '/login'
};
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).router = Object.create({});
@@ -91,7 +104,9 @@ describe('AuthNavMenuComponent', () => {
const navMenuItemSelector = 'li';
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
afterEach(() => {
fixture.destroy();
});
it('should not render', () => {
expect(component).toBeTruthy();
expect(deNavMenu.nativeElement).toBeDefined();
@@ -101,10 +116,10 @@ describe('AuthNavMenuComponent', () => {
});
describe('when route is /logout and user is authenticated', () => {
beforeEach(inject([Store], (store: Store<AppState>) => {
routerState = {
url: '/logout'
};
beforeEach(inject([Store], (store: Store<AppState>) => {
store
.subscribe((state) => {
(state as any).router = Object.create({});
@@ -128,6 +143,10 @@ describe('AuthNavMenuComponent', () => {
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
afterEach(() => {
fixture.destroy();
});
it('should not render', () => {
expect(component).toBeTruthy();
expect(deNavMenu.nativeElement).toBeDefined();
@@ -166,6 +185,11 @@ describe('AuthNavMenuComponent', () => {
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
afterEach(() => {
fixture.destroy();
component = null;
});
it('should render login dropdown menu', () => {
const loginDropdownMenu = deNavMenuItem.query(By.css('div[id=loginDropdownMenu]'));
expect(loginDropdownMenu.nativeElement).toBeDefined();
@@ -200,6 +224,10 @@ describe('AuthNavMenuComponent', () => {
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
afterEach(() => {
fixture.destroy();
component = null;
});
it('should render logout dropdown menu', () => {
const logoutDropdownMenu = deNavMenuItem.query(By.css('div[id=logoutDropdownMenu]'));
expect(logoutDropdownMenu.nativeElement).toBeDefined();
@@ -224,7 +252,12 @@ describe('AuthNavMenuComponent', () => {
],
providers: [
{ provide: HostWindowService, useValue: window },
{provide: AuthService, useValue: {setRedirectUrl: () => { /*empty*/ }}}
{
provide: AuthService, useValue: {
setRedirectUrl: () => { /*empty*/
}
}
}
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
@@ -234,6 +267,9 @@ describe('AuthNavMenuComponent', () => {
}));
beforeEach(() => {
init();
});
describe('when user is not authenticated', () => {
beforeEach(inject([Store], (store: Store<AppState>) => {
@@ -260,6 +296,11 @@ describe('AuthNavMenuComponent', () => {
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
afterEach(() => {
fixture.destroy();
component = null;
});
it('should render login link', () => {
const loginDropdownMenu = deNavMenuItem.query(By.css('a[id=loginLink]'));
expect(loginDropdownMenu.nativeElement).toBeDefined();
@@ -291,6 +332,11 @@ describe('AuthNavMenuComponent', () => {
deNavMenuItem = deNavMenu.query(By.css(navMenuItemSelector));
}));
afterEach(() => {
fixture.destroy();
component = null;
});
it('should render logout link', inject([Store], (store: Store<AppState>) => {
const logoutDropdownMenu = deNavMenuItem.query(By.css('a[id=logoutLink]'));
expect(logoutDropdownMenu.nativeElement).toBeDefined();

View File

@@ -60,15 +60,17 @@ export class AuthNavMenuComponent implements OnInit {
this.user = this.store.pipe(select(getAuthenticatedUser));
this.showAuth = this.store.select(routerStateSelector)
.filter((router: RouterReducerState) => isNotUndefined(router) && isNotUndefined(router.state))
.map((router: RouterReducerState) => {
this.showAuth = this.store.pipe(
select(routerStateSelector),
filter((router: RouterReducerState) => isNotUndefined(router) && isNotUndefined(router.state)),
map((router: RouterReducerState) => {
const url = router.state.url;
const show = !router.state.url.startsWith(LOGIN_ROUTE) && !router.state.url.startsWith(LOGOUT_ROUTE);
if (show) {
this.authService.setRedirectUrl(url);
}
return show;
});
})
);
}
}

View File

@@ -3,7 +3,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { By } from '@angular/platform-browser';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { of as observableOf } from 'rxjs';
import { SharedModule } from '../shared.module';
describe('BrowseByComponent', () => {
@@ -30,7 +30,7 @@ describe('BrowseByComponent', () => {
});
it('should display results when objects is not empty', () => {
(comp as any).objects = Observable.of({
(comp as any).objects = observableOf({
payload: {
page: {
length: 1

View File

@@ -1,8 +1,8 @@
<div [class.form-group]="(type !== 6 && asBootstrapFormGroup) || getClass('element', 'container').includes('form-group')"
<div [class.form-group]="(model.type !== 'GROUP' && asBootstrapFormGroup) || getClass('element', 'container').includes('form-group')"
[formGroup]="group"
[ngClass]="[getClass('element', 'container'), getClass('grid', 'container')]">
<label *ngIf="type !== 3 && model.label"
<label *ngIf="model.type !== 'CHECKBOX' && model.label"
[for]="model.id"
[innerHTML]="(model.required && model.label) ? (model.label | translate) + ' *' : (model.label | translate)"
[ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]"></label>

View File

@@ -172,7 +172,6 @@ describe('DsDynamicFormControlComponent test suite', () => {
});
fixture.detectChanges();
console.log(fixture.componentInstance.componentViewContainerRef);
testElement = debugElement.query(By.css(`input[id='${testModel.id}']`));
}));

View File

@@ -20,7 +20,6 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement
@Input() bindId = true;
@Input() group: FormGroup;
@Input() model: DynamicDsDatePickerModel;
// @Input() showErrorMessages = false;
// @Input()
// minDate;
// @Input()

View File

@@ -6,16 +6,16 @@ import {
import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './tag/dynamic-tag.model';
export interface DynamicRowArrayModelConfig extends DynamicFormArrayModelConfig {
notRepeteable: boolean;
notRepeatable: boolean;
}
export class DynamicRowArrayModel extends DynamicFormArrayModel {
@serializable() notRepeteable = false;
@serializable() notRepeatable = false;
isRowArray = true;
constructor(config: DynamicRowArrayModelConfig, layout?: DynamicFormControlLayout) {
super(config, layout);
this.notRepeteable = config.notRepeteable;
this.notRepeatable = config.notRepeatable;
}
}

View File

@@ -4,7 +4,6 @@ import { async, ComponentFixture, inject, TestBed, } from '@angular/core/testing
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DsDynamicGroupComponent } from './dynamic-group.components';
@@ -23,12 +22,19 @@ import { Chips } from '../../../../../chips/models/chips.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { DsDynamicInputModel } from '../ds-dynamic-input.model';
import { createTestComponent } from '../../../../../testing/utils';
import { getMockFormBuilderService } from '../../../../../mocks/mock-form-builder-service';
import { getMockFormService } from '../../../../../mocks/mock-form-service';
import { MockComponent } from 'ng-mocks';
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { MockStore } from '../../../../../testing/mock-store';
import { Store } from '@ngrx/store';
import { AppState } from '../../../../../../app.reducer';
export const FORM_GROUP_TEST_MODEL_CONFIG = {
export let FORM_GROUP_TEST_MODEL_CONFIG;
export let FORM_GROUP_TEST_GROUP;
let config;
function init() {
FORM_GROUP_TEST_MODEL_CONFIG = {
disabled: false,
errorMessages: { required: 'You must specify at least one author.' },
formConfiguration: [{
@@ -74,12 +80,11 @@ export const FORM_GROUP_TEST_MODEL_CONFIG = {
validators: { required: null }
} as DynamicGroupModelConfig;
export const FORM_GROUP_TEST_GROUP = new FormGroup({
FORM_GROUP_TEST_GROUP = new FormGroup({
dc_contributor_author: new FormControl(),
});
describe('DsDynamicGroupComponent test suite', () => {
const config = {
config = {
form: {
validatorMap: {
required: 'required',
@@ -87,11 +92,15 @@ describe('DsDynamicGroupComponent test suite', () => {
}
}
} as any;
}
describe('DsDynamicGroupComponent test suite', () => {
let testComp: TestComponent;
let groupComp: DsDynamicGroupComponent;
let testFixture: ComponentFixture<TestComponent>;
let groupFixture: ComponentFixture<DsDynamicGroupComponent>;
// let modelValue: any;
let modelValue: any;
let html;
let control1: FormControl;
let model1: DsDynamicInputModel;
@@ -100,7 +109,9 @@ describe('DsDynamicGroupComponent test suite', () => {
// async beforeEach
beforeEach(async(() => {
init();
const store = new MockStore<AppState>(Object.create(null));
/* TODO make sure these files use mocks instead of real services/components https://github.com/DSpace/dspace-angular/issues/281 */
TestBed.configureTestingModule({
imports: [
BrowserAnimationsModule,
@@ -110,18 +121,20 @@ describe('DsDynamicGroupComponent test suite', () => {
TranslateModule.forRoot()
],
declarations: [
MockComponent(FormComponent),
FormComponent,
DsDynamicGroupComponent,
TestComponent,
], // declare the test component
providers: [
ChangeDetectorRef,
DsDynamicGroupComponent,
{provide: FormBuilderService, useValue: getMockFormBuilderService()},
{provide: FormService, useValue: getMockFormService()},
DynamicFormValidationService,
DynamicFormLayoutService,
FormBuilderService,
FormComponent,
FormService,
{ provide: GLOBAL_CONFIG, useValue: config },
{provide: DynamicFormLayoutService, useValue: {}},
{provide: DynamicFormValidationService, useValue: {}}
{provide: Store, useValue: store},
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
@@ -143,6 +156,11 @@ describe('DsDynamicGroupComponent test suite', () => {
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
testComp = null;
});
it('should create DsDynamicGroupComponent', inject([DsDynamicGroupComponent], (app: DsDynamicGroupComponent) => {
expect(app).toBeDefined();
@@ -158,7 +176,6 @@ describe('DsDynamicGroupComponent test suite', () => {
groupComp.group = FORM_GROUP_TEST_GROUP;
groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG);
groupFixture.detectChanges();
control1 = service.getFormControlById('dc_contributor_author', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl;
model1 = service.findById('dc_contributor_author', groupComp.formModel) as DsDynamicInputModel;
control2 = service.getFormControlById('local_contributor_affiliation', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl;
@@ -172,123 +189,132 @@ describe('DsDynamicGroupComponent test suite', () => {
groupComp = null;
});
// it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
// const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
// const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
// const chips = new Chips([], 'value', 'dc.contributor.author');
//
// expect(groupComp.formCollapsed).toEqual(observableOf(false));
// expect(groupComp.formModel.length).toEqual(formModel.length);
// expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
// }));
//
// it('should save a new chips item', () => {
// control1.setValue('test author');
// (model1 as any).value = new FormFieldMetadataValueObject('test author');
// control2.setValue('test affiliation');
// (model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
// modelValue = [{
// 'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
// 'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
// }];
// groupFixture.detectChanges();
//
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
// const btnEl = buttons[0];
// btnEl.click();
//
// expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
// expect(groupComp.formCollapsed).toEqual(observableOf(true));
// });
//
// it('should clear form inputs', () => {
// control1.setValue('test author');
// (model1 as any).value = new FormFieldMetadataValueObject('test author');
// control2.setValue('test affiliation');
// (model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
//
// groupFixture.detectChanges();
//
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
// const btnEl = buttons[2];
// btnEl.click();
//
// expect(control1.value).toBeNull();
// expect(control2.value).toBeNull();
// expect(groupComp.formCollapsed).toEqual(observableOf(false));
// });
// });
//
// describe('when init model value is not empty', () => {
// beforeEach(() => {
//
// groupFixture = TestBed.createComponent(DsDynamicGroupComponent);
// groupComp = groupFixture.componentInstance; // FormComponent test instance
// groupComp.formId = 'testForm';
// groupComp.group = FORM_GROUP_TEST_GROUP;
// groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG);
// modelValue = [{
// 'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
// 'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
// }];
// groupComp.model.value = modelValue;
// groupComp.showErrorMessages = false;
// groupFixture.detectChanges();
//
// });
//
// afterEach(() => {
// groupFixture.destroy();
// groupComp = null;
// });
//
// it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
// const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
// const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
// const chips = new Chips(modelValue, 'value', 'dc.contributor.author');
//
// expect(groupComp.formCollapsed).toEqual(observableOf(true));
// expect(groupComp.formModel.length).toEqual(formModel.length);
// expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
// }));
//
// it('should modify existing chips item', inject([FormBuilderService], (service: FormBuilderService) => {
// groupComp.onChipSelected(0);
// groupFixture.detectChanges();
//
// control1 = service.getFormControlById('dc_contributor_author', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl;
// model1 = service.findById('dc_contributor_author', groupComp.formModel) as DsDynamicInputModel;
//
// control1.setValue('test author modify');
// (model1 as any).value = new FormFieldMetadataValueObject('test author modify');
//
// modelValue = [{
// 'dc.contributor.author': new FormFieldMetadataValueObject('test author modify'),
// 'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
// }];
// groupFixture.detectChanges();
//
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
// const btnEl = buttons[0];
// btnEl.click();
//
// groupFixture.detectChanges();
//
// expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
// expect(groupComp.formCollapsed).toEqual(observableOf(true));
// }));
//
// it('should delete existing chips item', () => {
// groupComp.onChipSelected(0);
// groupFixture.detectChanges();
//
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
// const btnEl = buttons[1];
// btnEl.click();
//
// expect(groupComp.chips.getChipsItems()).toEqual([]);
// expect(groupComp.formCollapsed).toEqual(observableOf(false));
// });
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const formConfig = { rows: groupComp.model.formConfiguration } as SubmissionFormsModel;
const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips([], 'value', 'dc.contributor.author');
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(false);
});
expect(groupComp.formModel.length).toEqual(formModel.length);
expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
}));
it('should save a new chips item', () => {
control1.setValue('test author');
(model1 as any).value = new FormFieldMetadataValueObject('test author');
control2.setValue('test affiliation');
(model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
modelValue = [{
'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
}];
groupFixture.detectChanges();
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
const btnEl = buttons[0];
btnEl.click();
expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(true);
})
});
it('should clear form inputs', () => {
control1.setValue('test author');
(model1 as any).value = new FormFieldMetadataValueObject('test author');
control2.setValue('test affiliation');
(model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
groupFixture.detectChanges();
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
const btnEl = buttons[2];
btnEl.click();
expect(control1.value).toBeNull();
expect(control2.value).toBeNull();
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(false);
});
});
});
describe('when init model value is not empty', () => {
beforeEach(() => {
groupFixture = TestBed.createComponent(DsDynamicGroupComponent);
groupComp = groupFixture.componentInstance; // FormComponent test instance
groupComp.formId = 'testForm';
groupComp.group = FORM_GROUP_TEST_GROUP;
groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG);
modelValue = [{
'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
}];
groupComp.model.value = modelValue;
groupFixture.detectChanges();
});
afterEach(() => {
groupFixture.destroy();
groupComp = null;
});
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const formConfig = { rows: groupComp.model.formConfiguration } as SubmissionFormsModel;
const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips(modelValue, 'value', 'dc.contributor.author');
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(true);
})
expect(groupComp.formModel.length).toEqual(formModel.length);
expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
}));
it('should modify existing chips item', inject([FormBuilderService], (service: FormBuilderService) => {
groupComp.onChipSelected(0);
groupFixture.detectChanges();
control1 = service.getFormControlById('dc_contributor_author', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl;
model1 = service.findById('dc_contributor_author', groupComp.formModel) as DsDynamicInputModel;
control1.setValue('test author modify');
(model1 as any).value = new FormFieldMetadataValueObject('test author modify');
modelValue = [{
'dc.contributor.author': new FormFieldMetadataValueObject('test author modify'),
'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
}];
groupFixture.detectChanges();
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
const btnEl = buttons[0];
btnEl.click();
groupFixture.detectChanges();
expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(true);
})
}));
it('should delete existing chips item', () => {
groupComp.onChipSelected(0);
groupFixture.detectChanges();
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
const btnEl = buttons[1];
btnEl.click();
expect(groupComp.chips.getChipsItems()).toEqual([]);
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(false);
})
});
});
});

View File

@@ -45,7 +45,6 @@ export class DsDynamicGroupComponent extends DynamicFormControlComponent impleme
@Input() formId: string;
@Input() group: FormGroup;
@Input() model: DynamicGroupModel;
// @Input() showErrorMessages = false;
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
@Output() change: EventEmitter<any> = new EventEmitter<any>();

View File

@@ -33,7 +33,6 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen
@Input() bindId = true;
@Input() group: FormGroup;
@Input() model: DynamicListCheckboxGroupModel | DynamicListRadioGroupModel;
// @Input() showErrorMessages = false;
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
@Output() change: EventEmitter<any> = new EventEmitter<any>();

View File

@@ -18,16 +18,13 @@ import { DsDynamicLookupComponent } from './dynamic-lookup.component';
import { DynamicLookupModel } from './dynamic-lookup.model';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { TranslateModule } from '@ngx-translate/core';
import { FormBuilderService } from '../../../form-builder.service';
import { FormService } from '../../../../form.service';
import { FormComponent } from '../../../../form.component';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { By } from '@angular/platform-browser';
import { AuthorityValueModel } from '../../../../../../core/integration/models/authority-value.model';
import { DynamicLookupNameModel } from './dynamic-lookup-name.model';
import { createTestComponent } from '../../../../../testing/utils';
import { DynamicLookupNameModel } from './dynamic-lookup-name.model';
export const LOOKUP_TEST_MODEL_CONFIG = {
let LOOKUP_TEST_MODEL_CONFIG = {
authorityOptions: {
closed: false,
metadata: 'lookup',
@@ -49,7 +46,7 @@ export const LOOKUP_TEST_MODEL_CONFIG = {
value: undefined
};
export const LOOKUP_NAME_TEST_MODEL_CONFIG = {
let LOOKUP_NAME_TEST_MODEL_CONFIG = {
authorityOptions: {
closed: false,
metadata: 'lookup-name',
@@ -71,12 +68,63 @@ export const LOOKUP_NAME_TEST_MODEL_CONFIG = {
value: undefined
};
export const LOOKUP_TEST_GROUP = new FormGroup({
let LOOKUP_TEST_GROUP = new FormGroup({
lookup: new FormControl(),
lookupName: new FormControl()
});
describe('Dynamic Lookup component', () => {
function init() {
LOOKUP_TEST_MODEL_CONFIG = {
authorityOptions: {
closed: false,
metadata: 'lookup',
name: 'RPAuthority',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
disabled: false,
errorMessages: { required: 'Required field.' },
id: 'lookup',
label: 'Author',
maxOptions: 10,
name: 'lookup',
placeholder: 'Author',
readOnly: false,
required: true,
repeatable: true,
separator: ',',
validators: { required: null },
value: undefined
};
LOOKUP_NAME_TEST_MODEL_CONFIG = {
authorityOptions: {
closed: false,
metadata: 'lookup-name',
name: 'RPAuthority',
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
} as AuthorityOptions,
disabled: false,
errorMessages: { required: 'Required field.' },
id: 'lookupName',
label: 'Author',
maxOptions: 10,
name: 'lookupName',
placeholder: 'Author',
readOnly: false,
required: true,
repeatable: true,
separator: ',',
validators: { required: null },
value: undefined
};
LOOKUP_TEST_GROUP = new FormGroup({
lookup: new FormControl(),
lookupName: new FormControl()
});
}
let testComp: TestComponent;
let lookupComp: DsDynamicLookupComponent;
@@ -84,11 +132,11 @@ describe('Dynamic Lookup component', () => {
let lookupFixture: ComponentFixture<DsDynamicLookupComponent>;
let html;
const authorityServiceStub = new AuthorityServiceStub();
let authorityServiceStub;
// async beforeEach
beforeEach(async(() => {
const authorityService = new AuthorityServiceStub();
authorityServiceStub = authorityService;
TestBed.configureTestingModule({
imports: [
DynamicFormsCoreModule,
@@ -106,16 +154,19 @@ describe('Dynamic Lookup component', () => {
providers: [
ChangeDetectorRef,
DsDynamicLookupComponent,
{provide: AuthorityService, useValue: authorityServiceStub},
{ provide: AuthorityService, useValue: authorityService },
{ provide: DynamicFormLayoutService, useValue: {} },
{ provide: DynamicFormValidationService, useValue: {} }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
}));
describe('', () => {
beforeEach(() => {
init();
});
describe('DynamicLookUpComponent', () => {
// synchronous beforeEach
beforeEach(() => {
html = `
@@ -130,11 +181,13 @@ describe('Dynamic Lookup component', () => {
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
testComp = null;
});
it('should create DsDynamicLookupComponent', inject([DsDynamicLookupComponent], (app: DsDynamicLookupComponent) => {
expect(app).toBeDefined();
}));
});
describe('when model is DynamicLookupModel', () => {
@@ -147,7 +200,10 @@ describe('Dynamic Lookup component', () => {
lookupComp.model = new DynamicLookupModel(LOOKUP_TEST_MODEL_CONFIG);
lookupFixture.detectChanges();
});
afterEach(() => {
lookupFixture.destroy();
lookupComp = null;
});
it('should render only an input element', () => {
const de = lookupFixture.debugElement.queryAll(By.css('input.form-control'));
expect(de.length).toBe(1);
@@ -157,7 +213,6 @@ describe('Dynamic Lookup component', () => {
describe('and init model value is empty', () => {
beforeEach(() => {
lookupFixture = TestBed.createComponent(DsDynamicLookupComponent);
lookupComp = lookupFixture.componentInstance; // FormComponent test instance
lookupComp.group = LOOKUP_TEST_GROUP;
@@ -165,6 +220,11 @@ describe('Dynamic Lookup component', () => {
lookupFixture.detectChanges();
});
afterEach(() => {
lookupFixture.destroy();
lookupComp = null;
});
it('should init component properly', () => {
expect(lookupComp.firstInputValue).toBe('');
});
@@ -182,16 +242,19 @@ describe('Dynamic Lookup component', () => {
lookupFixture.detectChanges();
results$.subscribe((results) => {
expect(lookupComp.optionsList).toEqual(results.payload);
})
});
}));
it('should select a results entry properly', fakeAsync(() => {
let de = lookupFixture.debugElement.queryAll(By.css('button'));
const btnEl = de[0].nativeElement;
const selectedValue = Object.assign(new AuthorityValueModel(), {id: 1, display: 'one', value: 1});
const selectedValue = Object.assign(new AuthorityValueModel(), {
id: 1,
display: 'one',
value: 1
});
spyOn(lookupComp.change, 'emit');
console.log("debugger");
lookupComp.firstInputValue = 'test';
lookupFixture.detectChanges();
btnEl.click();
@@ -200,7 +263,7 @@ describe('Dynamic Lookup component', () => {
de = lookupFixture.debugElement.queryAll(By.css('button.dropdown-item'));
const entryEl = de[0].nativeElement;
entryEl.click();
lookupFixture.detectChanges();
expect(lookupComp.firstInputValue).toEqual('one');
expect(lookupComp.model.value).toEqual(selectedValue);
expect(lookupComp.change.emit).toHaveBeenCalled();
@@ -238,9 +301,12 @@ describe('Dynamic Lookup component', () => {
// spyOn(store, 'dispatch');
});
afterEach(() => {
lookupFixture.destroy();
lookupComp = null;
});
it('should init component properly', () => {
expect(lookupComp.firstInputValue).toBe('test')
expect(lookupComp.firstInputValue).toBe('test');
});
});
});
@@ -258,7 +324,10 @@ describe('Dynamic Lookup component', () => {
// spyOn(store, 'dispatch');
});
afterEach(() => {
lookupFixture.destroy();
lookupComp = null;
});
it('should render two input element', () => {
const de = lookupFixture.debugElement.queryAll(By.css('input.form-control'));
expect(de.length).toBe(2);
@@ -277,15 +346,31 @@ describe('Dynamic Lookup component', () => {
lookupFixture.detectChanges();
});
afterEach(() => {
lookupFixture.destroy();
lookupComp = null;
});
it('should select a results entry properly', fakeAsync(() => {
const payload = [
Object.assign(new AuthorityValueModel(), {id: 1, display: 'Name, Lastname', value: 1}),
Object.assign(new AuthorityValueModel(), {id: 2, display: 'NameTwo, LastnameTwo', value: 2}),
Object.assign(new AuthorityValueModel(), {
id: 1,
display: 'Name, Lastname',
value: 1
}),
Object.assign(new AuthorityValueModel(), {
id: 2,
display: 'NameTwo, LastnameTwo',
value: 2
}),
];
let de = lookupFixture.debugElement.queryAll(By.css('button'));
const btnEl = de[0].nativeElement;
const selectedValue = Object.assign(new AuthorityValueModel(), {id: 1, display: 'Name, Lastname', value: 1});
const selectedValue = Object.assign(new AuthorityValueModel(), {
id: 1,
display: 'Name, Lastname',
value: 1
});
spyOn(lookupComp.change, 'emit');
authorityServiceStub.setNewPayload(payload);
lookupComp.firstInputValue = 'test';
@@ -302,7 +387,6 @@ describe('Dynamic Lookup component', () => {
expect(lookupComp.model.value).toEqual(selectedValue);
expect(lookupComp.change.emit).toHaveBeenCalled();
}));
});
describe('and init model value is not empty', () => {
@@ -316,13 +400,16 @@ describe('Dynamic Lookup component', () => {
lookupFixture.detectChanges();
});
afterEach(() => {
lookupFixture.destroy();
lookupComp = null;
});
it('should init component properly', () => {
expect(lookupComp.firstInputValue).toBe('Name');
expect(lookupComp.secondInputValue).toBe('Lastname');
});
});
});
});
});
@@ -338,7 +425,4 @@ class TestComponent {
inputLookupModelConfig = LOOKUP_TEST_MODEL_CONFIG;
model = new DynamicLookupModel(this.inputLookupModelConfig);
showErrorMessages = false;
}

View File

@@ -28,7 +28,6 @@ export class DsDynamicLookupComponent extends DynamicFormControlComponent implem
@Input() bindId = true;
@Input() group: FormGroup;
@Input() model: DynamicLookupModel | DynamicLookupNameModel;
// @Input() showErrorMessages = false;
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
@Output() change: EventEmitter<any> = new EventEmitter<any>();

View File

@@ -26,7 +26,6 @@ export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComp
@Input() bindId = true;
@Input() group: FormGroup;
@Input() model: DynamicScrollableDropdownModel;
// @Input() showErrorMessages = false;
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
@Output() change: EventEmitter<any> = new EventEmitter<any>();

View File

@@ -37,11 +37,15 @@ function createKeyUpEvent(key: number) {
return event;
}
export const TAG_TEST_GROUP = new FormGroup({
let TAG_TEST_GROUP;
let TAG_TEST_MODEL_CONFIG;
function init() {
TAG_TEST_GROUP = new FormGroup({
tag: new FormControl(),
});
export const TAG_TEST_MODEL_CONFIG = {
TAG_TEST_MODEL_CONFIG = {
authorityOptions: {
closed: false,
metadata: 'tag',
@@ -58,6 +62,7 @@ export const TAG_TEST_MODEL_CONFIG = {
required: false,
repeatable: false
};
}
describe('DsDynamicTagComponent test suite', () => {
@@ -72,7 +77,7 @@ describe('DsDynamicTagComponent test suite', () => {
// async beforeEach
beforeEach(async(() => {
const authorityServiceStub = new AuthorityServiceStub();
init();
TestBed.configureTestingModule({
imports: [
DynamicFormsCoreModule,
@@ -112,7 +117,9 @@ describe('DsDynamicTagComponent test suite', () => {
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
});
it('should create DsDynamicTagComponent', inject([DsDynamicTagComponent], (app: DsDynamicTagComponent) => {
expect(app).toBeDefined();
@@ -138,6 +145,7 @@ describe('DsDynamicTagComponent test suite', () => {
it('should init component properly', () => {
chips = new Chips([], 'display');
expect(tagComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
expect(tagComp.searchOptions).toBeDefined();
});
@@ -154,7 +162,11 @@ describe('DsDynamicTagComponent test suite', () => {
Object.assign(new AuthorityValueModel(), { id: 1, display: 'Name, Lastname', value: 1 })
];
const event: NgbTypeaheadSelectItemEvent = {
item: Object.assign(new AuthorityValueModel(), {id: 1, display: 'Name, Lastname', value: 1}),
item: Object.assign(new AuthorityValueModel(), {
id: 1,
display: 'Name, Lastname',
value: 1
}),
preventDefault: () => {
return;
}

View File

@@ -1,4 +1,3 @@
import {of as observableOf, Observable } from 'rxjs';
import {catchError, debounceTime, distinctUntilChanged, tap, switchMap, map, merge} from 'rxjs/operators';
@@ -29,7 +28,6 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
@Input() bindId = true;
@Input() group: FormGroup;
@Input() model: DynamicTagModel;
// @Input() showErrorMessages = false;
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
@Output() change: EventEmitter<any> = new EventEmitter<any>();
@@ -86,6 +84,7 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement
ngOnInit() {
this.hasAuthority = this.model.authorityOptions && hasValue(this.model.authorityOptions.name);
if (this.hasAuthority) {
this.searchOptions = new IntegrationSearchOptions(
this.model.authorityOptions.scope,

View File

@@ -22,11 +22,16 @@ import { DynamicTypeaheadModel } from './dynamic-typeahead.model';
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
import { createTestComponent } from '../../../../../testing/utils';
export const TYPEAHEAD_TEST_GROUP = new FormGroup({
export let TYPEAHEAD_TEST_GROUP;
export let TYPEAHEAD_TEST_MODEL_CONFIG;
function init() {
TYPEAHEAD_TEST_GROUP = new FormGroup({
typeahead: new FormControl(),
});
export const TYPEAHEAD_TEST_MODEL_CONFIG = {
TYPEAHEAD_TEST_MODEL_CONFIG = {
authorityOptions: {
closed: false,
metadata: 'typeahead',
@@ -44,7 +49,7 @@ export const TYPEAHEAD_TEST_MODEL_CONFIG = {
repeatable: false,
value: undefined
};
}
describe('DsDynamicTypeaheadComponent test suite', () => {
let testComp: TestComponent;
@@ -56,7 +61,7 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
// async beforeEach
beforeEach(async(() => {
const authorityServiceStub = new AuthorityServiceStub();
init()
TestBed.configureTestingModule({
imports: [
DynamicFormsCoreModule,
@@ -96,6 +101,9 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
});
it('should create DsDynamicTypeaheadComponent', inject([DsDynamicTypeaheadComponent], (app: DsDynamicTypeaheadComponent) => {
expect(app).toBeDefined();
@@ -221,6 +229,4 @@ class TestComponent {
model = new DynamicTypeaheadModel(TYPEAHEAD_TEST_MODEL_CONFIG);
showErrorMessages = false;
}

View File

@@ -26,7 +26,6 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp
@Input() bindId = true;
@Input() group: FormGroup;
@Input() model: DynamicTypeaheadModel;
@Input() showErrorMessages = false;
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
@Output() change: EventEmitter<any> = new EventEmitter<any>();

View File

@@ -254,7 +254,7 @@ describe('FormBuilderService test suite', () => {
{
id: 'testFormRowArray',
initialCount: 5,
notRepeteable: false,
notRepeatable: false,
groupFactory: () => {
return [
new DynamicInputModel({id: 'testFormRowArrayGroupInput'})

View File

@@ -35,7 +35,7 @@ export abstract class FieldParser {
id: uniqueId() + '_array',
label: this.configData.label,
initialCount: this.getInitArrayIndex(),
notRepeteable: !this.configData.repeatable,
notRepeatable: !this.configData.repeatable,
groupFactory: () => {
let model;
if ((arrayCounter === 0)) {

View File

@@ -14,7 +14,7 @@
<ng-template modelType="ARRAY" let-group let-index="index" let-context="context">
<!--Array with repeteable items-->
<div *ngIf="!context.notRepeteable"
<div *ngIf="!context.notRepeatable"
class="col-xs-2 d-flex flex-column justify-content-sm-start align-items-end">
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary"
@@ -31,7 +31,7 @@
</div>
<!--Array with non repeteable items - Only delete button-->
<div *ngIf="context.notRepeteable && group.context.groups.length > 1"
<div *ngIf="context.notRepeatable && group.context.groups.length > 1"
class="col-xs-2 d-flex flex-column justify-content-sm-start align-items-end">
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary"

View File

@@ -1,28 +1,41 @@
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, inject, TestBed, } from '@angular/core/testing';
import { CommonModule } from '@angular/common';
import { BrowserModule, By } from '@angular/platform-browser';
import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import {
DynamicFormArrayModel,
DynamicFormControlEvent,
DynamicFormControlModel,
DynamicFormValidationService,
DynamicInputModel
} from '@ng-dynamic-forms/core';
import { Store } from '@ngrx/store';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
import { FormComponent } from './form.component';
import { FormService } from './form.service';
import { FormBuilderService } from './builder/form-builder.service';
import { FormAddError, FormChangeAction } from './form.actions';
import { FormState } from './form.reducer';
import { FormChangeAction, FormStatusChangeAction } from './form.actions';
import { MockStore } from '../testing/mock-store';
import { FormFieldMetadataValueObject } from './builder/models/form-field-metadata-value.model';
import { GLOBAL_CONFIG } from '../../../config';
import { createTestComponent } from '../testing/utils';
import { getMockFormService } from '../mocks/mock-form-service';
import { getMockFormBuilderService } from '../mocks/mock-form-builder-service';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
export const TEST_FORM_MODEL = [
let TEST_FORM_MODEL;
let TEST_FORM_MODEL_WITH_ARRAY;
let config;
let formState: FormState;
let html;
let store: MockStore<FormState>;
function init() {
TEST_FORM_MODEL = [
new DynamicInputModel(
{
id: 'dc_title',
@@ -70,7 +83,7 @@ export const TEST_FORM_MODEL = [
),
];
export const TEST_FORM_MODEL_WITH_ARRAY = [
TEST_FORM_MODEL_WITH_ARRAY = [
new DynamicFormArrayModel({
id: 'bootstrapFormArray',
@@ -88,15 +101,7 @@ export const TEST_FORM_MODEL_WITH_ARRAY = [
}
})
];
describe('FormComponent test suite', () => {
let testComp: TestComponent;
let formComp: FormComponent;
let testFixture: ComponentFixture<TestComponent>;
let formFixture: ComponentFixture<FormComponent>;
let dynamicForm;
const config = {
config = {
form: {
validatorMap: {
required: 'required',
@@ -105,12 +110,33 @@ describe('FormComponent test suite', () => {
}
} as any;
let html;
let formService;
let formBuilderService;
formState = {
testForm: {
data: {
dc_title: null,
dc_title_alternative: null,
dc_publisher: null,
dc_identifier_citation: null,
dc_identifier_issn: null
},
valid: false,
errors: []
}
};
store = new MockStore<FormState>(formState);
}
describe('FormComponent test suite', () => {
let testComp: TestComponent;
let formComp: FormComponent;
let testFixture: ComponentFixture<TestComponent>;
let formFixture: ComponentFixture<FormComponent>;
// async beforeEach
beforeEach(async(() => {
init();
/* TODO make sure these files use mocks instead of real services/components https://github.com/DSpace/dspace-angular/issues/281 */
TestBed.configureTestingModule({
imports: [
BrowserModule,
@@ -126,19 +152,22 @@ describe('FormComponent test suite', () => {
], // declare the test component
providers: [
ChangeDetectorRef,
DynamicFormValidationService,
FormBuilderService,
FormComponent,
{ provide: FormBuilderService, useValue: getMockFormBuilderService() },
{ provide: FormService, useValue: getMockFormService() },
{ provide: GLOBAL_CONFIG, useValue: config }
FormService,
{ provide: GLOBAL_CONFIG, useValue: config },
{
provide: Store, useValue: store
}
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
formService = TestBed.get(FormService);
formBuilderService = TestBed.get(FormBuilderService);
}));
describe('', () => {
// // synchronous beforeEach
// synchronous beforeEach
beforeEach(() => {
html = `
<ds-form *ngIf="formModel" #formRef="formComponent"
@@ -149,13 +178,19 @@ describe('FormComponent test suite', () => {
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance;
});
afterEach(() => {
testFixture.destroy();
testComp = null;
html = undefined;
});
it('should create FormComponent', inject([FormComponent], (app: FormComponent) => {
expect(app).toBeDefined();
}));
});
describe('', () => {
let form;
let valid;
beforeEach(() => {
formFixture = TestBed.createComponent(FormComponent);
@@ -163,247 +198,238 @@ describe('FormComponent test suite', () => {
formComp.formId = 'testForm';
formComp.formModel = TEST_FORM_MODEL;
formComp.displaySubmit = false;
form = new BehaviorSubject(formState);
valid = new BehaviorSubject(false);
spyOn((formComp as any).formService, 'getForm').and.returnValue(form);
spyOn((formComp as any).formService, 'isValid').and.returnValue(valid);
formFixture.detectChanges();
dynamicForm = formFixture.debugElement.query(By.css('ds-dynamic-form'));
formBuilderService.findById.and.returnValue(TEST_FORM_MODEL);
spyOn(store, 'dispatch');
});
afterEach(() => {
formFixture.destroy();
formComp = null;
});
//
// it('should dispatch a FormStatusChangeAction when Form group status changes', () => {
// // spyOn(formComp, 'onChange');
// const control = new FormControl('', Validators.required);
// const event = {
// $event: new FormFieldMetadataValueObject('Test Title'),
// context: null,
// control: control,
// group: formComp.formGroup,
// model: formComp.formModel[0],
// type: 'change'
// } as DynamicFormControlEvent;
// dynamicForm.componentInstance.change.emit(event);
//
// // expect(formComp.onChange).toHaveBeenCalledWith('testForm', formComp.formGroup.valid);
// formComp.onChange(event);
// // const control = new FormControl('', Validators.required);
// formComp.formGroup.addControl('dc_title', control);
// control.setValue('Test Title');
//
// expect(formService.changeForm).toHaveBeenCalledWith('testForm', formComp.formGroup.valid);
// });
//
// it('should display form errors when errors are added to the state', () => {
//
// const error = {formComp.formId, 'dc_title', 0, 'error.validation.required';
// formService.getFormErrors().next([error]);
// formFixture.detectChanges();
//
// expect((formComp as any).formErrors).toEqual([error]);
//
// });
//
// fit('should remove form errors when errors are empty in the state', () => {
// (formComp as any).formErrors = [{
// fieldId: 'dc_title',
// message: 'error.validation.required'
// }];
// const errors = [];
//
// formService.getFormErrors().next([]);
// formFixture.detectChanges();
//
// expect((formComp as any).formErrors).toEqual(errors);
//
// });
//
// it('should dispatch FormChangeAction on form change', inject([FormBuilderService], (service: FormBuilderService) => {
// const event = {
// $event: new FormFieldMetadataValueObject('Test Title'),
// context: null,
// control: formComp.formGroup.get('dc_title'),
// group: formComp.formGroup,
// model: formComp.formModel[0],
// type: 'change'
// } as DynamicFormControlEvent;
//
// spyOn(formComp.change, 'emit');
//
// formComp.onChange(event);
//
// expect(store.dispatch).toHaveBeenCalledWith(new FormChangeAction('testForm', service.getValueFromModel(formComp.formModel)));
// expect(formComp.change.emit).toHaveBeenCalled();
// }));
//
// it('should emit change on form change', inject([FormBuilderService], (service: FormBuilderService) => {
// const event = {
// $event: new FormFieldMetadataValueObject('Test Title'),
// context: null,
// control: formComp.formGroup.get('dc_title'),
// group: formComp.formGroup,
// model: formComp.formModel[0],
// type: 'change'
// } as DynamicFormControlEvent;
//
// spyOn(formComp.change, 'emit');
//
// formComp.onChange(event);
//
// expect(formComp.change.emit).toHaveBeenCalled();
// }));
//
// it('should not emit change Event on form change when emitChange is false', inject([FormBuilderService], (service: FormBuilderService) => {
// const event = {
// $event: new FormFieldMetadataValueObject('Test Title'),
// context: null,
// control: formComp.formGroup.get('dc_title'),
// group: formComp.formGroup,
// model: formComp.formModel[0],
// type: 'change'
// } as DynamicFormControlEvent;
//
// formComp.emitChange = false;
// spyOn(formComp.change, 'emit');
//
// formComp.onChange(event);
//
// expect(formComp.change.emit).not.toHaveBeenCalled();
// }));
//
// it('should emit blur Event on blur', () => {
// const event = {
// $event: new FocusEvent('blur'),
// context: null,
// control: formComp.formGroup.get('dc_title'),
// group: formComp.formGroup,
// model: formComp.formModel[0],
// type: 'blur'
// } as DynamicFormControlEvent;
//
// spyOn(formComp.blur, 'emit');
//
// formComp.onBlur(event);
//
// expect(formComp.blur.emit).toHaveBeenCalled();
// });
//
// it('should emit focus Event on focus', () => {
// const event = {
// $event: new FocusEvent('focus'),
// context: null,
// control: formComp.formGroup.get('dc_title'),
// group: formComp.formGroup,
// model: formComp.formModel[0],
// type: 'focus'
// } as DynamicFormControlEvent;
//
// spyOn(formComp.focus, 'emit');
//
// formComp.onFocus(event);
//
// expect(formComp.focus.emit).toHaveBeenCalled();
// });
//
// it('should return Observable of form status', () => {
//
// const control = formComp.formGroup.get(['dc_title']);
// control.setValue('Test Title');
// formState.testForm.valid = true;
// store.nextState(formState);
// formFixture.detectChanges();
//
// formComp.isValid().subscribe((valid) => {
// expect(valid).toBe(true);
// });
// });
//
// it('should emit submit Event on form submit whether the form is valid', () => {
//
// const control = formComp.formGroup.get(['dc_title']);
// control.setValue('Test Title');
// formState.testForm.valid = true;
// spyOn(formComp.submit, 'emit');
//
// store.nextState(formState);
// formFixture.detectChanges();
//
// formComp.onSubmit();
// expect(formComp.submit.emit).toHaveBeenCalled();
// });
//
// it('should not emit submit Event on form submit whether the form is not valid', () => {
//
// spyOn((formComp as any).formService, 'validateAllFormFields');
//
// store.nextState(formState);
// formFixture.detectChanges();
//
// formComp.onSubmit();
// expect((formComp as any).formService.validateAllFormFields).toHaveBeenCalled();
// });
//
// it('should reset form group', () => {
//
// spyOn(formComp.formGroup, 'reset');
//
// formComp.reset();
//
// expect(formComp.formGroup.reset).toHaveBeenCalled();
// });
// });
//
// describe('', () => {
// beforeEach(() => {
//
// formFixture = TestBed.createComponent(FormComponent);
// formComp = formFixture.componentInstance; // FormComponent test instance
// formComp.formId = 'testFormArray';
// formComp.formModel = TEST_FORM_MODEL_WITH_ARRAY;
// formComp.displaySubmit = false;
// formFixture.detectChanges();
// spyOn(store, 'dispatch');
// });
//
// afterEach(() => {
// formFixture.destroy();
// formComp = null;
// });
//
// it('should return ReadOnly property from array item', inject([FormBuilderService], (service: FormBuilderService) => {
// const readOnly = formComp.isItemReadOnly(formComp.formModel[0] as DynamicFormArrayModel, 0);
//
// expect(readOnly).toBe(false);
// }));
//
// it('should dispatch FormChangeAction when an item has been added to an array', inject([FormBuilderService], (service: FormBuilderService) => {
// formComp.insertItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 1);
//
// expect(store.dispatch).toHaveBeenCalledWith(new FormChangeAction('testFormArray', service.getValueFromModel(formComp.formModel)));
// }));
//
// it('should emit addArrayItem Event when an item has been added to an array', inject([FormBuilderService], (service: FormBuilderService) => {
// spyOn(formComp.addArrayItem, 'emit');
//
// formComp.insertItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 1);
//
// expect(formComp.addArrayItem.emit).toHaveBeenCalled();
// }));
//
// it('should dispatch FormChangeAction when an item has been removed from an array', inject([FormBuilderService], (service: FormBuilderService) => {
// formComp.removeItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 1);
//
// expect(store.dispatch).toHaveBeenCalledWith(new FormChangeAction('testFormArray', service.getValueFromModel(formComp.formModel)));
// }));
//
// it('should emit removeArrayItem Event when an item has been removed from an array', inject([FormBuilderService], (service: FormBuilderService) => {
// spyOn(formComp.removeArrayItem, 'emit');
//
// formComp.removeItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 1);
//
// expect(formComp.removeArrayItem.emit).toHaveBeenCalled();
// }));
it('should dispatch a FormStatusChangeAction when Form group status changes', () => {
const control = formComp.formGroup.get(['dc_title']);
control.setValue('Test Title');
expect(store.dispatch).toHaveBeenCalledWith(new FormStatusChangeAction('testForm', formComp.formGroup.valid));
});
it('should display form errors when errors are added to the state', () => {
const errors = [{
fieldId: 'dc_title',
fieldIndex: 0,
message: 'error.validation.required'
}];
formState.testForm.errors = errors;
form.next(formState.testForm);
formFixture.detectChanges();
expect((formComp as any).formErrors).toEqual(errors);
});
it('should remove form errors when errors are empty in the state', () => {
(formComp as any).formErrors = [{
fieldId: 'dc_title',
message: 'error.validation.required'
}];
const errors = [];
formState.testForm.errors = errors;
form.next(formState.testForm);
formFixture.detectChanges();
expect((formComp as any).formErrors).toEqual(errors);
});
it('should dispatch FormChangeAction on form change', inject([FormBuilderService], (service: FormBuilderService) => {
const event = {
$event: new FormFieldMetadataValueObject('Test Title'),
context: null,
control: formComp.formGroup.get('dc_title'),
group: formComp.formGroup,
model: formComp.formModel[0],
type: 'change'
} as DynamicFormControlEvent;
spyOn(formComp.change, 'emit');
formComp.onChange(event);
expect(store.dispatch).toHaveBeenCalledWith(new FormChangeAction('testForm', service.getValueFromModel(formComp.formModel)));
expect(formComp.change.emit).toHaveBeenCalled();
}));
it('should emit change on form change', inject([FormBuilderService], (service: FormBuilderService) => {
const event = {
$event: new FormFieldMetadataValueObject('Test Title'),
context: null,
control: formComp.formGroup.get('dc_title'),
group: formComp.formGroup,
model: formComp.formModel[0],
type: 'change'
} as DynamicFormControlEvent;
spyOn(formComp.change, 'emit');
formComp.onChange(event);
expect(formComp.change.emit).toHaveBeenCalled();
}));
it('should not emit change Event on form change when emitChange is false', inject([FormBuilderService], (service: FormBuilderService) => {
const event = {
$event: new FormFieldMetadataValueObject('Test Title'),
context: null,
control: formComp.formGroup.get('dc_title'),
group: formComp.formGroup,
model: formComp.formModel[0],
type: 'change'
} as DynamicFormControlEvent;
formComp.emitChange = false;
spyOn(formComp.change, 'emit');
formComp.onChange(event);
expect(formComp.change.emit).not.toHaveBeenCalled();
}));
it('should emit blur Event on blur', () => {
const event = {
$event: new FocusEvent('blur'),
context: null,
control: formComp.formGroup.get('dc_title'),
group: formComp.formGroup,
model: formComp.formModel[0],
type: 'blur'
} as DynamicFormControlEvent;
spyOn(formComp.blur, 'emit');
formComp.onBlur(event);
expect(formComp.blur.emit).toHaveBeenCalled();
});
it('should emit focus Event on focus', () => {
const event = {
$event: new FocusEvent('focus'),
context: null,
control: formComp.formGroup.get('dc_title'),
group: formComp.formGroup,
model: formComp.formModel[0],
type: 'focus'
} as DynamicFormControlEvent;
spyOn(formComp.focus, 'emit');
formComp.onFocus(event);
expect(formComp.focus.emit).toHaveBeenCalled();
});
it('should return Observable of form status', () => {
const control = formComp.formGroup.get(['dc_title']);
control.setValue('Test Title');
valid.next(true);
formFixture.detectChanges();
formComp.isValid().subscribe((v) => {
expect(v).toBe(true);
});
});
it('should emit submit Event on form submit whether the form is valid', () => {
const control = formComp.formGroup.get(['dc_title']);
control.setValue('Test Title');
formState.testForm.valid = true;
spyOn(formComp.submit, 'emit');
form.next(formState.testForm);
formFixture.detectChanges();
formComp.onSubmit();
expect(formComp.submit.emit).toHaveBeenCalled();
});
it('should not emit submit Event on form submit whether the form is not valid', () => {
spyOn((formComp as any).formService, 'validateAllFormFields');
form.next(formState.testForm)
formFixture.detectChanges();
formComp.onSubmit();
expect((formComp as any).formService.validateAllFormFields).toHaveBeenCalled();
});
it('should reset form group', () => {
spyOn(formComp.formGroup, 'reset');
formComp.reset();
expect(formComp.formGroup.reset).toHaveBeenCalled();
});
});
describe('', () => {
beforeEach(() => {
formFixture = TestBed.createComponent(FormComponent);
formComp = formFixture.componentInstance; // FormComponent test instance
formComp.formId = 'testFormArray';
formComp.formModel = TEST_FORM_MODEL_WITH_ARRAY;
formComp.displaySubmit = false;
formFixture.detectChanges();
spyOn(store, 'dispatch');
});
afterEach(() => {
formFixture.destroy();
formComp = null;
});
it('should return ReadOnly property from array item', inject([FormBuilderService], (service: FormBuilderService) => {
const readOnly = formComp.isItemReadOnly(formComp.formModel[0] as DynamicFormArrayModel, 0);
expect(readOnly).toBe(false);
}));
it('should dispatch FormChangeAction when an item has been added to an array', inject([FormBuilderService], (service: FormBuilderService) => {
formComp.insertItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 0);
expect(store.dispatch).toHaveBeenCalledWith(new FormChangeAction('testFormArray', service.getValueFromModel(formComp.formModel)));
}));
it('should emit addArrayItem Event when an item has been added to an array', inject([FormBuilderService], (service: FormBuilderService) => {
spyOn(formComp.addArrayItem, 'emit');
formComp.insertItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 0);
expect(formComp.addArrayItem.emit).toHaveBeenCalled();
}));
it('should dispatch FormChangeAction when an item has been removed from an array', inject([FormBuilderService], (service: FormBuilderService) => {
formComp.removeItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 0);
expect(store.dispatch).toHaveBeenCalledWith(new FormChangeAction('testFormArray', service.getValueFromModel(formComp.formModel)));
}));
it('should emit removeArrayItem Event when an item has been removed from an array', inject([FormBuilderService], (service: FormBuilderService) => {
spyOn(formComp.removeArrayItem, 'emit');
formComp.removeItem(new Event('click'), formComp.formModel[0] as DynamicFormArrayModel, 0);
expect(formComp.removeArrayItem.emit).toHaveBeenCalled();
}));
})
});

View File

@@ -156,7 +156,6 @@ export class FormComponent implements OnDestroy, OnInit {
// .delay(100) // this terrible delay is here to prevent the detection change error
.subscribe((errors: FormError[]) => {
const { formGroup, formModel } = this;
errors
.filter((error: FormError) => findIndex(this.formErrors, {
fieldId: error.fieldId,
@@ -171,25 +170,15 @@ export class FormComponent implements OnDestroy, OnInit {
} else {
field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel, fieldIndex);
}
console.log('1', error);
if (field) {
console.log('2',error);
const model: DynamicFormControlModel = this.formBuilderService.findById(fieldId, formModel);
console.log('4',error);
this.formService.addErrorToField(field, model, error.message);
// this.formService.validateAllFormFields(formGroup);
console.log('5',error);
this.changeDetectorRef.detectChanges();
}
console.log('4',error);
});
console.log(errors);
this.formErrors
.filter((error: FormError) => findIndex(errors, {
@@ -211,7 +200,6 @@ export class FormComponent implements OnDestroy, OnInit {
this.formService.removeErrorFromField(field, model, error.message);
}
});
console.log(this.formErrors);
this.formErrors = errors;
this.changeDetectorRef.detectChanges();
})
@@ -256,7 +244,6 @@ export class FormComponent implements OnDestroy, OnInit {
}
onChange(event: DynamicFormControlEvent): void {
this.formService.changeForm(this.formId, this.formModel);
this.formGroup.markAsPristine();

View File

@@ -30,7 +30,6 @@ export interface FormState {
const initialState: FormState = Object.create(null);
export function formReducer(state = initialState, action: FormAction): FormState {
console.log('TEST');
switch (action.type) {
case FormActionTypes.FORM_INIT: {
@@ -68,7 +67,6 @@ export function formReducer(state = initialState, action: FormAction): FormState
}
function addFormErrors(state: FormState, action: FormAddError) {
console.log(state);
const formId = action.payload.formId;
if (hasValue(state[formId])) {
const error: FormError = {

View File

@@ -1,14 +1,8 @@
import { Store, StoreModule } from '@ngrx/store';
import { async, inject, TestBed } from '@angular/core/testing';
import { FormGroup } from '@angular/forms';
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import {
DynamicFormControlModel,
DynamicFormGroupModel,
DynamicFormService,
DynamicFormValidationService,
DynamicInputModel
} from '@ng-dynamic-forms/core';
import { DynamicFormControlModel, DynamicInputModel } from '@ng-dynamic-forms/core';
import { FormService } from './form.service';
import { FormBuilderService } from './builder/form-builder.service';
@@ -43,32 +37,34 @@ describe('FormService test suite', () => {
}),
new DynamicInputModel({ id: 'date' }),
new DynamicInputModel({ id: 'description' }),
new DynamicFormGroupModel({
id: 'addressLocation',
group: [
new DynamicInputModel({
id: 'zipCode',
label: 'Zip Code',
placeholder: 'ZIP'
}),
new DynamicInputModel({
id: 'state',
label: 'State',
placeholder: 'State'
}),
new DynamicInputModel({
id: 'city',
label: 'City',
placeholder: 'City'
})
]
}),
// new DynamicFormGroupModel({
//
// id: 'addressLocation',
// group: [
// new DynamicInputModel({
//
// id: 'zipCode',
// label: 'Zip Code',
// placeholder: 'ZIP'
// }),
// new DynamicInputModel({
//
// id: 'state',
// label: 'State',
// placeholder: 'State'
// }),
// new DynamicInputModel({
//
// id: 'city',
// label: 'City',
// placeholder: 'City'
// })
// ]
// }),
];
let controls;
const formData = {
author: ['test'],
title: null,
@@ -92,22 +88,26 @@ describe('FormService test suite', () => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({ formReducer })
],
providers: [
{provide: FormBuilderService, useValue: getMockFormBuilderService()},
]
}).compileComponents();
}));
beforeEach(inject([Store, FormBuilderService], (store: Store<AppState>, formBuilderService: FormBuilderService) => {
beforeEach(inject([Store], (store: Store<AppState>) => {
builderService = getMockFormBuilderService();
store
.subscribe((state) => {
state.forms = formState;
});
builderService = formBuilderService;
formGroup = builderService.createFormGroup(formModel);
service = new FormService(config, formBuilderService, store);
}));
const author: AbstractControl = new FormControl('test');
const title: AbstractControl = new FormControl(undefined, Validators.required);
const date: AbstractControl = new FormControl(undefined);
const description: AbstractControl = new FormControl(undefined);
formGroup = new FormGroup({ author, title, date, description });
controls = { author, title, date, description };
service = new FormService(config, builderService, store);
})
)
;
it('should check whether form state is init', () => {
service.isFormInitialized(formId).subscribe((init) => {
@@ -136,7 +136,6 @@ describe('FormService test suite', () => {
it('should validate all form fields', () => {
service.validateAllFormFields(formGroup);
expect(formGroup.controls.author.touched).toBe(true);
expect(formGroup.controls.author.status).toBe('VALID');
@@ -149,8 +148,8 @@ describe('FormService test suite', () => {
});
it('should add error to field', () => {
let control = builderService.getFormControlById('description', formGroup, formModel);
let model = builderService.findById('description', formModel);
let control = controls.description;
let model = formModel.find((mdl: DynamicFormControlModel) => mdl.id === 'description');
let errorKeys: string[];
service.addErrorToField(control, model, 'Test error message');
@@ -162,8 +161,8 @@ describe('FormService test suite', () => {
expect(formGroup.controls.description.touched).toBe(true);
control = builderService.getFormControlById('title', formGroup, formModel);
model = builderService.findById('title', formModel);
control = controls.title;
model = formModel.find((mdl: DynamicFormControlModel) => mdl.id === 'title');
service.addErrorToField(control, model, 'error.required');
errorKeys = Object.keys(control.errors);
@@ -175,8 +174,8 @@ describe('FormService test suite', () => {
});
it('should remove error from field', () => {
let control = builderService.getFormControlById('description', formGroup, formModel);
let model = builderService.findById('description', formModel);
let control = controls.description;
let model = formModel.find((mdl: DynamicFormControlModel) => mdl.id === 'description');
let errorKeys: string[];
service.addErrorToField(control, model, 'Test error message');
@@ -190,8 +189,8 @@ describe('FormService test suite', () => {
expect(formGroup.controls.description.touched).toBe(false);
control = builderService.getFormControlById('title', formGroup, formModel);
model = builderService.findById('title', formModel);
control = controls.title;
model = formModel.find((mdl: DynamicFormControlModel) => mdl.id === 'title');
service.addErrorToField(control, model, 'error.required');
@@ -205,10 +204,11 @@ describe('FormService test suite', () => {
});
it('should reset form group', () => {
const control = builderService.getFormControlById('author', formGroup, formModel);
const control = controls.author;
service.resetForm(formGroup, formModel, formId);
expect(control.value).toBeNull();
});
});
})
;

View File

@@ -1,11 +1,9 @@
import { filter, takeWhile, map } from 'rxjs/operators';
import { filter, map, takeWhile } from 'rxjs/operators';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { select, Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import {
AuthenticateAction,
ResetAuthenticationMessagesAction
@@ -135,7 +133,7 @@ export class LogInComponent implements OnDestroy, OnInit {
this.store.pipe(
select(isAuthenticated),
takeWhile(() => this.alive),
filter((authenticated) => authenticated),)
filter((authenticated) => authenticated))
.subscribe(() => {
this.authService.redirectToPreviousUrl();
}

View File

@@ -2,7 +2,7 @@ import { FormBuilderService } from '../form/builder/form-builder.service';
import { FormControl, FormGroup } from '@angular/forms';
export function getMockFormBuilderService(): FormBuilderService {
return jasmine.createSpyObj('FormService', {
return jasmine.createSpyObj('FormBuilderService', {
modelFromConfiguration: [],
createFormGroup: new FormGroup({}),
getValueFromModel: {},

View File

@@ -1,23 +1,12 @@
import { FormService } from '../form/form.service';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { map } from 'rxjs/operators';
export function getMockFormService(
id$: string = 'random_id',
errors = new BehaviorSubject([])
id$: string = 'random_id'
): FormService {
return jasmine.createSpyObj('FormService', {
getUniqueId: id$,
resetForm: {},
validateAllFormFields: {},
getForm: errors.pipe(map((err) => { return {data: {}, valid: true, errors: err} })),
removeForm: undefined,
removeError: undefined,
changeForm: undefined,
setStatusChanged: undefined,
initForm: undefined,
getFormErrors: errors,
addErrorToField: undefined
validateAllFormFields: {}
});
}

View File

@@ -1,4 +1,5 @@
import { Observable } from 'rxjs';
import {of as observableOf, Observable } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
import { ResponseCacheEntry } from '../../core/cache/response-cache.reducer';
@@ -19,7 +20,7 @@ export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observab
} as RemoteData<any>)))
}
},
buildSingle: (href$: string | Observable<string>) => Observable.of(new RemoteData(false, false, true, undefined, {}))
buildSingle: (href$: string | Observable<string>) => observableOf(new RemoteData(false, false, true, undefined, {}))
} as RemoteDataBuildService;
}

View File

@@ -1,4 +0,0 @@
import { Store } from '@ngrx/store';
import { of as observableOf } from 'rxjs';

View File

@@ -99,7 +99,7 @@ export class NumberPickerComponent implements OnInit, ControlValueAccessor {
update(event) {
try {
const i = Number.parseInt(event.target.value);
const i = Number.parseInt(event.target.value, 10);
if (i >= this.min && i <= this.max) {
this.value = i;

View File

@@ -1,4 +1,4 @@
import {of as observableOf, Observable } from 'rxjs';
import { Observable, of as observableOf } from 'rxjs';
import { HttpOptions } from '../../core/dspace-rest-v2/dspace-rest-v2.service';
import { AuthStatus } from '../../core/auth/models/auth-status.model';
import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
@@ -27,7 +27,7 @@ export class AuthRequestServiceStub {
if (this.validateToken(token)) {
authStatusStub.authenticated = true;
authStatusStub.token = this.mockTokenInfo;
authStatusStub.eperson = Observable.of(new RemoteData<EPerson>(false, false, true, undefined, this.mockUser));
authStatusStub.eperson = observableOf(new RemoteData<EPerson>(false, false, true, undefined, this.mockUser));
} else {
authStatusStub.authenticated = false;
}
@@ -46,7 +46,7 @@ export class AuthRequestServiceStub {
if (this.validateToken(token)) {
authStatusStub.authenticated = true;
authStatusStub.token = this.mockTokenInfo;
authStatusStub.eperson = Observable.of(new RemoteData<EPerson>(false, false, true, undefined, this.mockUser));
authStatusStub.eperson = observableOf(new RemoteData<EPerson>(false, false, true, undefined, this.mockUser));
} else {
authStatusStub.authenticated = false;
}

View File

@@ -1,5 +1,4 @@
import {of as observableOf, Observable } from 'rxjs';
import { Observable, of as observableOf } from 'rxjs';
import { AuthStatus } from '../../core/auth/models/auth-status.model';
import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
import { EPersonMock } from './eperson-mock';
@@ -21,7 +20,7 @@ export class AuthServiceStub {
authStatus.okay = true;
authStatus.authenticated = true;
authStatus.token = this.token;
authStatus.eperson = Observable.of(new RemoteData<EPerson>(false, false, true, undefined, EPersonMock));
authStatus.eperson = observableOf(new RemoteData<EPerson>(false, false, true, undefined, EPersonMock));
return observableOf(authStatus);
} else {
console.log('error');
@@ -31,7 +30,7 @@ export class AuthServiceStub {
public authenticatedUser(token: AuthTokenInfo): Observable<EPerson> {
if (token.accessToken === 'token_test') {
return Observable.of(EPersonMock);
return observableOf(EPersonMock);
} else {
throw(new Error('Message Error test'));
}

View File

@@ -1,10 +1,7 @@
import {distinctUntilChanged, debounceTime, takeUntil} from 'rxjs/operators';
import { Directive, Input, Output, EventEmitter, OnDestroy, OnInit } from '@angular/core';
import { NgControl } from '@angular/forms';
import { Subject } from 'rxjs';
@Directive({

View File

@@ -1,8 +1,5 @@
import { of as observableOf } from 'rxjs';
import { map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { Action, Store } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects';

View File

@@ -6,8 +6,6 @@ import { RouterModule } from '@angular/router';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { AppComponent } from '../../app/app.component';
import { AppModule } from '../../app/app.module';

View File

@@ -151,10 +151,10 @@
"use-input-property-decorator": true,
"use-life-cycle-interface": false,
"use-output-property-decorator": true,
"use-pipe-transform-interface": true,
"rxjs-collapse-imports": true,
"rxjs-pipeable-operators-only": true,
"rxjs-no-static-observable-methods": true,
"rxjs-proper-imports": true
"use-pipe-transform-interface": true
// "rxjs-collapse-imports": true,
// "rxjs-pipeable-operators-only": true,
// "rxjs-no-static-observable-methods": true,
// "rxjs-proper-imports": true
}
}