Added tests

This commit is contained in:
Giuseppe Digilio
2019-01-08 23:25:44 +01:00
parent 959c02af74
commit 967d682962
17 changed files with 1094 additions and 393 deletions

View File

@@ -6,16 +6,30 @@ import { AuthStatus } from './models/auth-status.model';
import { AuthResponseParsingService } from './auth-response-parsing.service'; import { AuthResponseParsingService } from './auth-response-parsing.service';
import { AuthGetRequest, AuthPostRequest } from '../data/request.models'; import { AuthGetRequest, AuthPostRequest } from '../data/request.models';
import { MockStore } from '../../shared/testing/mock-store'; import { MockStore } from '../../shared/testing/mock-store';
import { ObjectCacheState } from '../cache/object-cache.reducer'; import { async, TestBed } from '@angular/core/testing';
import { Store, StoreModule } from '@ngrx/store';
describe('AuthResponseParsingService', () => { describe('AuthResponseParsingService', () => {
let service: AuthResponseParsingService; let service: AuthResponseParsingService;
const EnvConfig = { cache: { msToLive: 1000 } } as GlobalConfig; const EnvConfig = { cache: { msToLive: 1000 } } as GlobalConfig;
const store = new MockStore<ObjectCacheState>({}); let store: any;
const objectCacheService = new ObjectCacheService(store as any); let objectCacheService: ObjectCacheService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({}),
],
providers: [
{ provide: Store, useClass: MockStore }
]
}).compileComponents();
}));
beforeEach(() => { beforeEach(() => {
store = TestBed.get(Store);
objectCacheService = new ObjectCacheService(store as any);
service = new AuthResponseParsingService(EnvConfig, objectCacheService); service = new AuthResponseParsingService(EnvConfig, objectCacheService);
}); });

View File

@@ -42,10 +42,12 @@ describe('IntegrationService', () => {
const name = 'type'; const name = 'type';
const metadata = 'dc.type'; const metadata = 'dc.type';
const query = ''; const query = '';
const value = 'test';
const uuid = 'd9d30c0c-69b7-4369-8397-ca67c888974d'; const uuid = 'd9d30c0c-69b7-4369-8397-ca67c888974d';
const integrationEndpoint = 'https://rest.api/integration'; const integrationEndpoint = 'https://rest.api/integration';
const serviceEndpoint = `${integrationEndpoint}/${LINK_NAME}`; const serviceEndpoint = `${integrationEndpoint}/${LINK_NAME}`;
const entriesEndpoint = `${serviceEndpoint}/${name}/entries?query=${query}&metadata=${metadata}&uuid=${uuid}`; const entriesEndpoint = `${serviceEndpoint}/${name}/entries?query=${query}&metadata=${metadata}&uuid=${uuid}`;
const entryValueEndpoint = `${serviceEndpoint}/${name}/entryValue/${value}?metadata=${metadata}`;
findOptions = new IntegrationSearchOptions(uuid, name, metadata); findOptions = new IntegrationSearchOptions(uuid, name, metadata);
@@ -88,4 +90,20 @@ describe('IntegrationService', () => {
}); });
}); });
describe('getEntryByValue', () => {
it('should configure a new IntegrationRequest', () => {
findOptions = new IntegrationSearchOptions(
null,
name,
metadata,
value);
const expected = new IntegrationRequest(requestService.generateRequestId(), entryValueEndpoint);
scheduler.schedule(() => service.getEntryByValue(findOptions).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
});
});
}); });

View File

@@ -315,8 +315,6 @@ describe('jsonPatchOperationsReducer test suite', () => {
const action = new FlushPatchOperationsAction(testJsonPatchResourceType, undefined); const action = new FlushPatchOperationsAction(testJsonPatchResourceType, undefined);
const newState = jsonPatchOperationsReducer(initState, action); const newState = jsonPatchOperationsReducer(initState, action);
console.log(initState);
console.log(newState);
expect(newState[testJsonPatchResourceType].transactionStartTime).toBeNull(); expect(newState[testJsonPatchResourceType].transactionStartTime).toBeNull();
expect(newState[testJsonPatchResourceType].commitPending).toBeFalsy(); expect(newState[testJsonPatchResourceType].commitPending).toBeFalsy();
expect(newState[testJsonPatchResourceType].children[testJsonPatchResourceId].body).toEqual([]); expect(newState[testJsonPatchResourceType].children[testJsonPatchResourceId].body).toEqual([]);

View File

@@ -1,8 +1,9 @@
import { cold, getTestScheduler } from 'jasmine-marbles'; import { async, TestBed } from '@angular/core/testing';
import { cold, getTestScheduler } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing'; import { TestScheduler } from 'rxjs/testing';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { Store } from '@ngrx/store'; import { Store, StoreModule } from '@ngrx/store';
import { getMockRequestService } from '../../shared/mocks/mock-request.service'; import { getMockRequestService } from '../../shared/mocks/mock-request.service';
import { ResponseCacheService } from '../cache/response-cache.service'; import { ResponseCacheService } from '../cache/response-cache.service';
@@ -16,12 +17,12 @@ import { SubmitDataResponseDefinitionObject } from '../shared/submit-data-respon
import { CoreState } from '../core.reducers'; import { CoreState } from '../core.reducers';
import { HALEndpointService } from '../shared/hal-endpoint.service'; import { HALEndpointService } from '../shared/hal-endpoint.service';
import { JsonPatchOperationsEntry, JsonPatchOperationsResourceEntry } from './json-patch-operations.reducer'; import { JsonPatchOperationsEntry, JsonPatchOperationsResourceEntry } from './json-patch-operations.reducer';
import { MockStore } from '../../shared/testing/mock-store';
import { import {
CommitPatchOperationsAction, CommitPatchOperationsAction,
RollbacktPatchOperationsAction, RollbacktPatchOperationsAction,
StartTransactionPatchOperationsAction StartTransactionPatchOperationsAction
} from './json-patch-operations.actions'; } from './json-patch-operations.actions';
import { MockStore } from '../../shared/testing/mock-store';
class TestService extends JsonPatchOperationsService<SubmitDataResponseDefinitionObject, SubmissionPatchRequest> { class TestService extends JsonPatchOperationsService<SubmitDataResponseDefinitionObject, SubmissionPatchRequest> {
protected linkPath = ''; protected linkPath = '';
@@ -102,8 +103,19 @@ describe('JsonPatchOperationsService test suite', () => {
} }
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({}),
],
providers: [
{ provide: Store, useClass: MockStore }
]
}).compileComponents();
}));
beforeEach(() => { beforeEach(() => {
store = new MockStore<CoreState>({} as CoreState); store = TestBed.get(Store);
responseCache = initMockResponseCacheService(true); responseCache = initMockResponseCacheService(true);
requestService = getMockRequestService(); requestService = getMockRequestService();
rdbService = getMockRemoteDataBuildService(); rdbService = getMockRemoteDataBuildService();
@@ -111,8 +123,8 @@ describe('JsonPatchOperationsService test suite', () => {
halService = new HALEndpointServiceStub(resourceEndpointURL); halService = new HALEndpointServiceStub(resourceEndpointURL);
service = initTestService(); service = initTestService();
spyOn((service as any).store, 'select').and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType])); spyOn(store, 'select').and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType]));
spyOn((service as any).store, 'dispatch').and.callThrough(); spyOn(store, 'dispatch').and.callThrough();
spyOn(Date.prototype, 'getTime').and.callFake(() => { spyOn(Date.prototype, 'getTime').and.callFake(() => {
return timestamp; return timestamp;
}); });
@@ -142,7 +154,7 @@ describe('JsonPatchOperationsService test suite', () => {
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe()); scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush(); scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction); expect(store.dispatch).toHaveBeenCalledWith(expectedAction);
}); });
describe('when request is successful', () => { describe('when request is successful', () => {
@@ -151,13 +163,13 @@ describe('JsonPatchOperationsService test suite', () => {
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe()); scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush(); scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction); expect(store.dispatch).toHaveBeenCalledWith(expectedAction);
}); });
}); });
describe('when request is not successful', () => { describe('when request is not successful', () => {
beforeEach(() => { beforeEach(() => {
store = new MockStore<CoreState>({} as CoreState); store = TestBed.get(Store);
responseCache = initMockResponseCacheService(false); responseCache = initMockResponseCacheService(false);
requestService = getMockRequestService(); requestService = getMockRequestService();
rdbService = getMockRemoteDataBuildService(); rdbService = getMockRemoteDataBuildService();
@@ -165,8 +177,8 @@ describe('JsonPatchOperationsService test suite', () => {
halService = new HALEndpointServiceStub(resourceEndpointURL); halService = new HALEndpointServiceStub(resourceEndpointURL);
service = initTestService(); service = initTestService();
spyOn((service as any).store, 'select').and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType])); store.select.and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType]));
spyOn((service as any).store, 'dispatch').and.callThrough(); store.dispatch.and.callThrough();
}); });
it('should dispatch a new RollbacktPatchOperationsAction', () => { it('should dispatch a new RollbacktPatchOperationsAction', () => {
@@ -175,7 +187,7 @@ describe('JsonPatchOperationsService test suite', () => {
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe()); scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush(); scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction); expect(store.dispatch).toHaveBeenCalledWith(expectedAction);
}); });
}); });
}); });
@@ -204,7 +216,7 @@ describe('JsonPatchOperationsService test suite', () => {
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe()); scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush(); scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction); expect(store.dispatch).toHaveBeenCalledWith(expectedAction);
}); });
describe('when request is successful', () => { describe('when request is successful', () => {
@@ -213,13 +225,13 @@ describe('JsonPatchOperationsService test suite', () => {
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe()); scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush(); scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction); expect(store.dispatch).toHaveBeenCalledWith(expectedAction);
}); });
}); });
describe('when request is not successful', () => { describe('when request is not successful', () => {
beforeEach(() => { beforeEach(() => {
store = new MockStore<CoreState>({} as CoreState); store = TestBed.get(Store);
responseCache = initMockResponseCacheService(false); responseCache = initMockResponseCacheService(false);
requestService = getMockRequestService(); requestService = getMockRequestService();
rdbService = getMockRemoteDataBuildService(); rdbService = getMockRemoteDataBuildService();
@@ -227,8 +239,8 @@ describe('JsonPatchOperationsService test suite', () => {
halService = new HALEndpointServiceStub(resourceEndpointURL); halService = new HALEndpointServiceStub(resourceEndpointURL);
service = initTestService(); service = initTestService();
spyOn((service as any).store, 'select').and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType])); store.select.and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType]));
spyOn((service as any).store, 'dispatch').and.callThrough(); store.dispatch.and.callThrough();
}); });
it('should dispatch a new RollbacktPatchOperationsAction', () => { it('should dispatch a new RollbacktPatchOperationsAction', () => {
@@ -237,7 +249,7 @@ describe('JsonPatchOperationsService test suite', () => {
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe()); scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush(); scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction); expect(store.dispatch).toHaveBeenCalledWith(expectedAction);
}); });
}); });
}); });

View File

@@ -20,14 +20,11 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat
import { DsDynamicInputModel } from '../ds-dynamic-input.model'; import { DsDynamicInputModel } from '../ds-dynamic-input.model';
import { createTestComponent } from '../../../../../testing/utils'; import { createTestComponent } from '../../../../../testing/utils';
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
import { MockStore } from '../../../../../testing/mock-store';
import { Store } from '@ngrx/store';
import { AppState } from '../../../../../../app.reducer';
import { AuthService } from '../../../../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../../../testing/auth-service-stub';
import { AuthorityService } from '../../../../../../core/integration/authority.service'; import { AuthorityService } from '../../../../../../core/integration/authority.service';
import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub'; import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub';
import { MOCK_SUBMISSION_CONFIG } from '../../../../../testing/mock-submission-config'; import { MOCK_SUBMISSION_CONFIG } from '../../../../../testing/mock-submission-config';
import { Store, StoreModule } from '@ngrx/store';
import { MockStore } from '../../../../../testing/mock-store';
export let FORM_GROUP_TEST_MODEL_CONFIG; export let FORM_GROUP_TEST_MODEL_CONFIG;
@@ -103,7 +100,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
// async beforeEach // async beforeEach
beforeEach(async(() => { beforeEach(async(() => {
init(); 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 */ /* TODO make sure these files use mocks instead of real services/components https://github.com/DSpace/dspace-angular/issues/281 */
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
@@ -111,6 +108,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
NgbModule.forRoot(), NgbModule.forRoot(),
StoreModule.forRoot({}),
TranslateModule.forRoot() TranslateModule.forRoot()
], ],
declarations: [ declarations: [
@@ -128,7 +126,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {
FormService, FormService,
{ provide: AuthorityService, useValue: new AuthorityServiceStub() }, { provide: AuthorityService, useValue: new AuthorityServiceStub() },
{ provide: GLOBAL_CONFIG, useValue: config }, { provide: GLOBAL_CONFIG, useValue: config },
{ provide: Store, useValue: store }, { provide: Store, useClass: MockStore }
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
}); });

View File

@@ -10,7 +10,7 @@ import {
DynamicFormValidationService, DynamicFormValidationService,
DynamicInputModel DynamicInputModel
} from '@ng-dynamic-forms/core'; } from '@ng-dynamic-forms/core';
import { Store } from '@ngrx/store'; import { Store, StoreModule } from '@ngrx/store';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -124,7 +124,6 @@ function init() {
} }
}; };
store = new MockStore<FormState>(formState);
} }
describe('FormComponent test suite', () => { describe('FormComponent test suite', () => {
@@ -144,6 +143,7 @@ describe('FormComponent test suite', () => {
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
NgbModule.forRoot(), NgbModule.forRoot(),
StoreModule.forRoot({}),
TranslateModule.forRoot() TranslateModule.forRoot()
], ],
declarations: [ declarations: [
@@ -157,9 +157,7 @@ describe('FormComponent test suite', () => {
FormComponent, FormComponent,
FormService, FormService,
{ provide: GLOBAL_CONFIG, useValue: config }, { provide: GLOBAL_CONFIG, useValue: config },
{ { provide: Store, useClass: MockStore }
provide: Store, useValue: store
}
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
}); });
@@ -177,6 +175,7 @@ describe('FormComponent test suite', () => {
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
testComp = testFixture.componentInstance; testComp = testFixture.componentInstance;
}); });
afterEach(() => { afterEach(() => {
testFixture.destroy(); testFixture.destroy();
@@ -194,6 +193,7 @@ describe('FormComponent test suite', () => {
beforeEach(() => { beforeEach(() => {
formFixture = TestBed.createComponent(FormComponent); formFixture = TestBed.createComponent(FormComponent);
store = TestBed.get(Store);
formComp = formFixture.componentInstance; // FormComponent test instance formComp = formFixture.componentInstance; // FormComponent test instance
formComp.formId = 'testForm'; formComp.formId = 'testForm';
formComp.formModel = TEST_FORM_MODEL; formComp.formModel = TEST_FORM_MODEL;
@@ -384,6 +384,7 @@ describe('FormComponent test suite', () => {
beforeEach(() => { beforeEach(() => {
formFixture = TestBed.createComponent(FormComponent); formFixture = TestBed.createComponent(FormComponent);
store = TestBed.get(Store);
formComp = formFixture.componentInstance; // FormComponent test instance formComp = formFixture.componentInstance; // FormComponent test instance
formComp.formId = 'testFormArray'; formComp.formId = 'testFormArray';
formComp.formModel = TEST_FORM_MODEL_WITH_ARRAY; formComp.formModel = TEST_FORM_MODEL_WITH_ARRAY;

View File

@@ -0,0 +1,7 @@
import { TranslateService } from '@ngx-translate/core';
export function getMockTranslateService(): TranslateService {
return jasmine.createSpyObj('translateService', {
get: jasmine.createSpy('get')
});
}

View File

@@ -1,24 +1,21 @@
import { map } from 'rxjs/operators'; import { Injectable } from '@angular/core';
import { Action } from '@ngrx/store'; import { ActionsSubject, ReducerManager, StateObservable, Store } from '@ngrx/store';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
export class MockStore<T> extends BehaviorSubject<T> { @Injectable()
export class MockStore<T> extends Store<T> {
private stateSubject = new BehaviorSubject<T>({} as T);
constructor(private _initialState: T) { constructor(
super(_initialState); state$: StateObservable,
actionsObserver: ActionsSubject,
reducerManager: ReducerManager
) {
super(state$, actionsObserver, reducerManager);
this.source = this.stateSubject.asObservable();
} }
dispatch = (action: Action): void => { nextState(nextState: T) {
// console.info(action); this.stateSubject.next(nextState);
};
select = <R>(pathOrMapFn: any): Observable<T> => {
return this.asObservable().pipe(
map((value) => pathOrMapFn.projector(value)))
};
nextState(_newState: T) {
this.next(_newState);
} }
} }

View File

@@ -2,7 +2,7 @@ import { TestBed } from '@angular/core/testing';
import { cold, hot } from 'jasmine-marbles'; import { cold, hot } from 'jasmine-marbles';
import { provideMockActions } from '@ngrx/effects/testing'; import { provideMockActions } from '@ngrx/effects/testing';
import { Store } from '@ngrx/store'; import { Store, StoreModule } from '@ngrx/store';
import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs'; import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
@@ -65,6 +65,7 @@ describe('SubmissionObjectEffects test suite', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
StoreModule.forRoot({}),
TranslateModule.forRoot({ TranslateModule.forRoot({
loader: { loader: {
provide: TranslateLoader, provide: TranslateLoader,
@@ -75,16 +76,17 @@ describe('SubmissionObjectEffects test suite', () => {
providers: [ providers: [
SubmissionObjectEffects, SubmissionObjectEffects,
TranslateService, TranslateService,
{provide: Store, useValue: new MockStore({})}, { provide: Store, useClass: MockStore },
provideMockActions(() => actions), provideMockActions(() => actions),
{provide: NotificationsService, useValue: notificationsServiceStub}, { provide: NotificationsService, useValue: notificationsServiceStub },
{provide: SectionsService, useClass: SectionsServiceStub}, { provide: SectionsService, useClass: SectionsServiceStub },
{provide: SubmissionService, useValue: submissionServiceStub}, { provide: SubmissionService, useValue: submissionServiceStub },
{provide: SubmissionJsonPatchOperationsService, useValue: submissionJsonPatchOperationsServiceStub}, { provide: SubmissionJsonPatchOperationsService, useValue: submissionJsonPatchOperationsServiceStub },
], ],
}); });
submissionObjectEffects = TestBed.get(SubmissionObjectEffects); submissionObjectEffects = TestBed.get(SubmissionObjectEffects);
store = TestBed.get(Store);
}); });
describe('loadForm$', () => { describe('loadForm$', () => {
@@ -263,7 +265,6 @@ describe('SubmissionObjectEffects test suite', () => {
describe('saveSubmissionSuccess$', () => { describe('saveSubmissionSuccess$', () => {
it('should return a UPLOAD_SECTION_DATA action for each updated section', () => { it('should return a UPLOAD_SECTION_DATA action for each updated section', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -312,7 +313,6 @@ describe('SubmissionObjectEffects test suite', () => {
}); });
it('should display a success notification', () => { it('should display a success notification', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -358,7 +358,6 @@ describe('SubmissionObjectEffects test suite', () => {
}); });
it('should display a warning notification when there are errors', () => { it('should display a warning notification when there are errors', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -406,7 +405,6 @@ describe('SubmissionObjectEffects test suite', () => {
}); });
it('should detect and notify a new section', () => { it('should detect and notify a new section', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -534,7 +532,6 @@ describe('SubmissionObjectEffects test suite', () => {
}); });
it('should not allow to deposit when there are errors', () => { it('should not allow to deposit when there are errors', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -609,7 +606,6 @@ describe('SubmissionObjectEffects test suite', () => {
describe('depositSubmission$', () => { describe('depositSubmission$', () => {
it('should return a DEPOSIT_SUBMISSION_SUCCESS action on success', () => { it('should return a DEPOSIT_SUBMISSION_SUCCESS action on success', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -636,7 +632,6 @@ describe('SubmissionObjectEffects test suite', () => {
}); });
it('should return a DEPOSIT_SUBMISSION_ERROR action on error', () => { it('should return a DEPOSIT_SUBMISSION_ERROR action on error', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -721,7 +716,6 @@ describe('SubmissionObjectEffects test suite', () => {
describe('discardSubmission$', () => { describe('discardSubmission$', () => {
it('should return a DISCARD_SUBMISSION_SUCCESS action on success', () => { it('should return a DISCARD_SUBMISSION_SUCCESS action on success', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState
@@ -748,7 +742,6 @@ describe('SubmissionObjectEffects test suite', () => {
}); });
it('should return a DISCARD_SUBMISSION_ERROR action on error', () => { it('should return a DISCARD_SUBMISSION_ERROR action on error', () => {
store = TestBed.get(Store);
store.nextState({ store.nextState({
submission: { submission: {
objects: mockSubmissionState objects: mockSubmissionState

View File

@@ -69,7 +69,7 @@ export class SectionsDirective implements OnDestroy, OnInit {
this.changeDetectorRef.detectChanges(); this.changeDetectorRef.detectChanges();
// If section is no longer active dispatch save action // If section is no longer active dispatch save action
if (!this.active && isNotNull(activeSectionId)) { if (!this.active && isNotNull(activeSectionId)) {
this.submissionService.dispatchSaveSection(this.submissionId, this.sectionId); this.submissionService.dispatchSave(this.submissionId);
} }
} }
}) })
@@ -89,7 +89,7 @@ export class SectionsDirective implements OnDestroy, OnInit {
} }
public isOpen() { public isOpen() {
return (this.sectionState) ? true : false; return this.sectionState;
} }
public isMandatory() { public isMandatory() {

View File

@@ -0,0 +1,378 @@
import { async, TestBed } from '@angular/core/testing';
import { cold, getTestScheduler } from 'jasmine-marbles';
import { of as observableOf } from 'rxjs';
import { Store, StoreModule } from '@ngrx/store';
import { ScrollToService } from '@nicky-lenaers/ngx-scroll-to';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { submissionReducers } from '../submission.reducers';
import { MockTranslateLoader } from '../../shared/mocks/mock-translate-loader';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { SubmissionService } from '../submission.service';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
import { SubmissionServiceStub } from '../../shared/testing/submission-service-stub';
import { getMockTranslateService } from '../../shared/mocks/mock-translate.service';
import { SectionsService } from './sections.service';
import { mockSectionsData, mockSectionsErrors, mockSubmissionState } from '../../shared/mocks/mock-submission';
import {
DisableSectionAction,
EnableSectionAction,
InertSectionErrorsAction,
RemoveSectionErrorsAction,
SectionStatusChangeAction,
UpdateSectionDataAction
} from '../objects/submission-objects.actions';
import { FormAddError, FormClearErrorsAction, FormRemoveErrorAction } from '../../shared/form/form.actions';
import parseSectionErrors from '../utils/parseSectionErrors';
import { SubmissionScopeType } from '../../core/submission/submission-scope-type';
import { SubmissionSectionError } from '../objects/submission-objects.reducer';
describe('SectionsService test suite', () => {
let notificationsServiceStub: NotificationsServiceStub;
let scrollToService: ScrollToService;
let service: SectionsService;
let submissionServiceStub: SubmissionServiceStub;
let translateService: any;
const formId = 'formTest';
const submissionId = '826';
const sectionId = 'traditionalpageone';
const sectionErrors: any = parseSectionErrors(mockSectionsErrors);
const sectionData: any = mockSectionsData;
const sectionState: any = mockSubmissionState['826'].sections[sectionId];
const store: any = jasmine.createSpyObj('store', {
dispatch: jasmine.createSpy('dispatch'),
select: jasmine.createSpy('select')
});
function getMockScrollToService(): ScrollToService {
return jasmine.createSpyObj('scrollToService', {
scrollTo: jasmine.createSpy('scrollTo')
});
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
StoreModule.forRoot({submissionReducers} as any),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: MockTranslateLoader
}
})
],
providers: [
{ provide: NotificationsService, useClass: NotificationsServiceStub },
{ provide: ScrollToService, useValue: getMockScrollToService() },
{ provide: SubmissionService, useClass: SubmissionServiceStub },
{ provide: TranslateService, useValue: getMockTranslateService() },
{ provide: Store, useValue: store },
SectionsService
]
}).compileComponents();
}));
beforeEach(() => {
service = TestBed.get(SectionsService);
submissionServiceStub = TestBed.get(SubmissionService);
notificationsServiceStub = TestBed.get(NotificationsService);
scrollToService = TestBed.get(ScrollToService);
translateService = TestBed.get(TranslateService);
});
describe('checkSectionErrors', () => {
it('should dispatch a new RemoveSectionErrorsAction and FormClearErrorsAction when there are no errors', () => {
service.checkSectionErrors(submissionId, sectionId, formId, []);
expect(store.dispatch).toHaveBeenCalledWith(new RemoveSectionErrorsAction(submissionId, sectionId));
expect(store.dispatch).toHaveBeenCalledWith(new FormClearErrorsAction(formId));
});
it('should dispatch a new FormAddError for each section\'s error', () => {
service.checkSectionErrors(submissionId, sectionId, formId, sectionErrors[sectionId]);
expect(store.dispatch).toHaveBeenCalledWith(new FormAddError(
formId,
'dc_contributor_author',
0,
'error.validation.required'));
expect(store.dispatch).toHaveBeenCalledWith(new FormAddError(
formId,
'dc_title',
0,
'error.validation.required'));
expect(store.dispatch).toHaveBeenCalledWith(new FormAddError(formId,
'dc_date_issued',
0,
'error.validation.required'));
});
it('should dispatch a new FormRemoveErrorAction for each section\'s error that no longer exists', () => {
const currentErrors = Array.of(...sectionErrors[sectionId]);
const prevErrors = Array.of(...sectionErrors[sectionId]);
currentErrors.pop();
service.checkSectionErrors(submissionId, sectionId, formId, currentErrors, prevErrors);
expect(store.dispatch).toHaveBeenCalledWith(new FormAddError(
formId,
'dc_contributor_author',
0,
'error.validation.required'));
expect(store.dispatch).toHaveBeenCalledWith(new FormAddError(
formId,
'dc_title',
0,
'error.validation.required'));
expect(store.dispatch).toHaveBeenCalledWith(new FormRemoveErrorAction(
formId,
'dc_date_issued',
0));
});
});
describe('dispatchRemoveSectionErrors', () => {
it('should dispatch a new RemoveSectionErrorsAction', () => {
service.dispatchRemoveSectionErrors(submissionId, sectionId);
const expected = new RemoveSectionErrorsAction(submissionId, sectionId);
expect(store.dispatch).toHaveBeenCalledWith(expected);
});
});
describe('getSectionData', () => {
it('should return an observable with section\'s data', () => {
store.select.and.returnValue(observableOf(sectionData[sectionId]));
const expected = cold('(b|)', {
b: sectionData[sectionId]
});
expect(service.getSectionData(submissionId, sectionId)).toBeObservable(expected);
});
});
describe('getSectionErrors', () => {
it('should return an observable with section\'s errors', () => {
store.select.and.returnValue(observableOf(sectionErrors[sectionId]));
const expected = cold('(b|)', {
b: sectionErrors[sectionId]
});
expect(service.getSectionErrors(submissionId, sectionId)).toBeObservable(expected);
});
});
describe('getSectionState', () => {
it('should return an observable with section\'s state', () => {
store.select.and.returnValue(observableOf(sectionState));
const expected = cold('(b|)', {
b: sectionState
});
expect(service.getSectionState(submissionId, sectionId)).toBeObservable(expected);
});
});
describe('isSectionValid', () => {
it('should return an observable of boolean', () => {
store.select.and.returnValue(observableOf({isValid: false}));
let expected = cold('(b|)', {
b: false
});
expect(service.isSectionValid(submissionId, sectionId)).toBeObservable(expected);
store.select.and.returnValue(observableOf({isValid: true}));
expected = cold('(b|)', {
b: true
});
expect(service.isSectionValid(submissionId, sectionId)).toBeObservable(expected);
});
});
describe('isSectionActive', () => {
it('should return an observable of boolean', () => {
submissionServiceStub.getActiveSectionId.and.returnValue(observableOf(sectionId));
let expected = cold('(b|)', {
b: true
});
expect(service.isSectionActive(submissionId, sectionId)).toBeObservable(expected);
submissionServiceStub.getActiveSectionId.and.returnValue(observableOf('test'));
expected = cold('(b|)', {
b: false
});
expect(service.isSectionActive(submissionId, sectionId)).toBeObservable(expected);
});
});
describe('isSectionEnabled', () => {
it('should return an observable of boolean', () => {
store.select.and.returnValue(observableOf({enabled: false}));
let expected = cold('(b|)', {
b: false
});
expect(service.isSectionEnabled(submissionId, sectionId)).toBeObservable(expected);
store.select.and.returnValue(observableOf({enabled: true}));
expected = cold('(b|)', {
b: true
});
expect(service.isSectionEnabled(submissionId, sectionId)).toBeObservable(expected);
});
});
describe('isSectionReadOnly', () => {
it('should return an observable of true when it\'s a readonly section and scope is not workspace', () => {
store.select.and.returnValue(observableOf({
visibility: {
main: null,
other: 'READONLY'
}
}));
const expected = cold('(b|)', {
b: true
});
expect(service.isSectionReadOnly(submissionId, sectionId, SubmissionScopeType.WorkflowItem)).toBeObservable(expected);
});
it('should return an observable of false when it\'s a readonly section and scope is workspace', () => {
store.select.and.returnValue(observableOf({
visibility: {
main: null,
other: 'READONLY'
}
}));
const expected = cold('(b|)', {
b: false
});
expect(service.isSectionReadOnly(submissionId, sectionId, SubmissionScopeType.WorkspaceItem)).toBeObservable(expected);
});
it('should return an observable of false when it\'s not a readonly section', () => {
store.select.and.returnValue(observableOf({
visibility: null
}));
const expected = cold('(b|)', {
b: false
});
expect(service.isSectionReadOnly(submissionId, sectionId, SubmissionScopeType.WorkflowItem)).toBeObservable(expected);
});
});
describe('isSectionAvailable', () => {
it('should return an observable of true when section is available', () => {
store.select.and.returnValue(observableOf(mockSubmissionState[submissionId]));
const expected = cold('(b|)', {
b: true
});
expect(service.isSectionAvailable(submissionId, sectionId)).toBeObservable(expected);
});
it('should return an observable of false when section is not available', () => {
store.select.and.returnValue(observableOf(mockSubmissionState[submissionId]));
const expected = cold('(b|)', {
b: false
});
expect(service.isSectionAvailable(submissionId, 'test')).toBeObservable(expected);
});
});
describe('addSection', () => {
it('should dispatch a new EnableSectionAction a move target to new section', () => {
service.addSection(submissionId, 'newSection');
expect(store.dispatch).toHaveBeenCalledWith(new EnableSectionAction(submissionId, 'newSection'));
expect(scrollToService.scrollTo).toHaveBeenCalled();
});
});
describe('removeSection', () => {
it('should dispatch a new DisableSectionAction', () => {
service.removeSection(submissionId, 'newSection');
expect(store.dispatch).toHaveBeenCalledWith(new DisableSectionAction(submissionId, 'newSection'));
});
});
describe('setSectionError', () => {
it('should dispatch a new InertSectionErrorsAction', () => {
const error: SubmissionSectionError = {
path: 'test',
message: 'message test'
};
service.setSectionError(submissionId, sectionId, error);
expect(store.dispatch).toHaveBeenCalledWith(new InertSectionErrorsAction(submissionId, sectionId, error));
});
});
describe('setSectionStatus', () => {
it('should dispatch a new SectionStatusChangeAction', () => {
service.setSectionStatus(submissionId, sectionId, true);
expect(store.dispatch).toHaveBeenCalledWith(new SectionStatusChangeAction(submissionId, sectionId, true));
});
});
describe('updateSectionData', () => {
it('should dispatch a new UpdateSectionDataAction', () => {
const scheduler = getTestScheduler();
const data: any = {test: 'test'};
spyOn(service, 'isSectionAvailable').and.returnValue(observableOf(true));
spyOn(service, 'isSectionEnabled').and.returnValue(observableOf(true));
scheduler.schedule(() => service.updateSectionData(submissionId, sectionId, data, []));
scheduler.flush();
expect(store.dispatch).toHaveBeenCalledWith(new UpdateSectionDataAction(submissionId, sectionId, data, []));
});
it('should dispatch a new UpdateSectionDataAction and display a new notification when section is not enabled', () => {
const scheduler = getTestScheduler();
const data: any = {test: 'test'};
spyOn(service, 'isSectionAvailable').and.returnValue(observableOf(true));
spyOn(service, 'isSectionEnabled').and.returnValue(observableOf(false));
translateService.get.and.returnValue(observableOf('test'));
scheduler.schedule(() => service.updateSectionData(submissionId, sectionId, data, []));
scheduler.flush();
expect(notificationsServiceStub.info).toHaveBeenCalled();
expect(store.dispatch).toHaveBeenCalledWith(new UpdateSectionDataAction(submissionId, sectionId, data, []));
});
});
});

View File

@@ -133,7 +133,9 @@ export class SectionsService {
return this.store.select(submissionSectionFromIdSelector(submissionId, sectionId)).pipe( return this.store.select(submissionSectionFromIdSelector(submissionId, sectionId)).pipe(
filter((sectionObj) => hasValue(sectionObj)), filter((sectionObj) => hasValue(sectionObj)),
map((sectionObj: SubmissionSectionObject) => { map((sectionObj: SubmissionSectionObject) => {
return sectionObj.visibility.other === 'READONLY' && submissionScope !== SubmissionScopeType.WorkspaceItem return isNotEmpty(sectionObj.visibility)
&& sectionObj.visibility.other === 'READONLY'
&& submissionScope !== SubmissionScopeType.WorkspaceItem
}), }),
distinctUntilChanged()); distinctUntilChanged());
} }

View File

@@ -12,7 +12,7 @@
<ng-container *ngIf="readMode"> <ng-container *ngIf="readMode">
<button class="btn btn-link" (click)="downloadBitstreamFile(); $event.stopPropagation()"><i class="fa fa-download fa-2x text-normal" aria-hidden="true"></i></button> <button class="btn btn-link" (click)="downloadBitstreamFile(); $event.stopPropagation()"><i class="fa fa-download fa-2x text-normal" aria-hidden="true"></i></button>
<!--<a href="{{fileData.url}}" title="Download file" target="_blank"><i class="fa fa-download text-normal mr-3" aria-hidden="true"></i></a>--> <!--<a href="{{fileData.url}}" title="Download file" target="_blank"><i class="fa fa-download text-normal mr-3" aria-hidden="true"></i></a>-->
<button class="btn btn-link" (click)="$event.preventDefault();switchMode();"><i class="fa fa-pencil-square-o fa-2x text-normal"></i></button> <button class="btn btn-link" (click)="$event.preventDefault();switchMode();"><i class="fa fa-edit fa-2x text-normal"></i></button>
<button class="btn btn-link" (click)="$event.preventDefault();confirmDelete(content);"><i class="fa fa-trash fa-2x text-danger"></i></button> <button class="btn btn-link" (click)="$event.preventDefault();confirmDelete(content);"><i class="fa fa-trash fa-2x text-danger"></i></button>
</ng-container> </ng-container>
<ng-container *ngIf="!readMode"> <ng-container *ngIf="!readMode">

View File

@@ -0,0 +1,102 @@
import { TestScheduler } from 'rxjs/testing';
import { cold, getTestScheduler } from 'jasmine-marbles';
import { SubmissionRestService } from './submission-rest.service';
import { ResponseCacheService } from '../core/cache/response-cache.service';
import { RequestService } from '../core/data/request.service';
import { RemoteDataBuildService } from '../core/cache/builders/remote-data-build.service';
import { getMockRequestService } from '../shared/mocks/mock-request.service';
import { getMockRemoteDataBuildService } from '../shared/mocks/mock-remote-data-build.service';
import { HALEndpointServiceStub } from '../shared/testing/hal-endpoint-service-stub';
import {
SubmissionDeleteRequest,
SubmissionPatchRequest,
SubmissionPostRequest,
SubmissionRequest
} from '../core/data/request.models';
import { FormFieldMetadataValueObject } from '../shared/form/builder/models/form-field-metadata-value.model';
describe('SubmissionRestService test suite', () => {
let scheduler: TestScheduler;
let service: SubmissionRestService;
let responseCache: ResponseCacheService;
let requestService: RequestService;
let rdbService: RemoteDataBuildService;
let halService: any;
const resourceEndpointURL = 'https://rest.api/endpoint';
const resourceEndpoint = 'workspaceitems';
const resourceScope = '260';
const body = { test: new FormFieldMetadataValueObject('test')};
const resourceHref = resourceEndpointURL + '/' + resourceEndpoint + '/' + resourceScope;
const timestampResponse = 1545994811992;
function initMockResponseCacheService(isSuccessful: boolean): ResponseCacheService {
return jasmine.createSpyObj('responseCache', {
get: cold('c-', {
c: {response: {isSuccessful},
timeAdded: timestampResponse}
}),
remove: jasmine.createSpy('remove')
});
}
function initTestService() {
return new SubmissionRestService(
rdbService,
responseCache,
requestService,
halService
);
}
beforeEach(() => {
responseCache = initMockResponseCacheService(true);
requestService = getMockRequestService();
rdbService = getMockRemoteDataBuildService();
scheduler = getTestScheduler();
halService = new HALEndpointServiceStub(resourceEndpointURL);
service = initTestService();
});
describe('deleteById', () => {
it('should configure a new SubmissionDeleteRequest', () => {
const expected = new SubmissionDeleteRequest(requestService.generateRequestId(), resourceHref);
scheduler.schedule(() => service.deleteById(resourceScope, resourceEndpoint).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
});
});
describe('getDataById', () => {
it('should configure a new SubmissionRequest', () => {
const expected = new SubmissionRequest(requestService.generateRequestId(), resourceHref);
scheduler.schedule(() => service.getDataById(resourceEndpoint, resourceScope).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected, true);
});
});
describe('postToEndpoint', () => {
it('should configure a new SubmissionPostRequest', () => {
const expected = new SubmissionPostRequest(requestService.generateRequestId(), resourceHref, body);
scheduler.schedule(() => service.postToEndpoint(resourceEndpoint, body, resourceScope).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected, true);
});
});
describe('patchToEndpoint', () => {
it('should configure a new SubmissionPatchRequest', () => {
const expected = new SubmissionPatchRequest(requestService.generateRequestId(), resourceHref, body);
scheduler.schedule(() => service.patchToEndpoint(resourceEndpoint, body, resourceScope).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected, true);
});
});
});

View File

@@ -2,7 +2,6 @@ import { Injectable } from '@angular/core';
import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs'; import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs';
import { distinctUntilChanged, filter, flatMap, map, mergeMap, tap } from 'rxjs/operators'; import { distinctUntilChanged, filter, flatMap, map, mergeMap, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { ResponseCacheService } from '../core/cache/response-cache.service'; import { ResponseCacheService } from '../core/cache/response-cache.service';
import { RequestService } from '../core/data/request.service'; import { RequestService } from '../core/data/request.service';
@@ -10,7 +9,6 @@ import { ResponseCacheEntry } from '../core/cache/response-cache.reducer';
import { SubmissionSuccessResponse } from '../core/cache/response-cache.models'; import { SubmissionSuccessResponse } from '../core/cache/response-cache.models';
import { isNotEmpty } from '../shared/empty.util'; import { isNotEmpty } from '../shared/empty.util';
import { import {
ConfigRequest,
DeleteRequest, DeleteRequest,
PostRequest, PostRequest,
RestRequest, RestRequest,
@@ -20,7 +18,6 @@ import {
SubmissionRequest SubmissionRequest
} from '../core/data/request.models'; } from '../core/data/request.models';
import { SubmitDataResponseDefinitionObject } from '../core/shared/submit-data-response-definition.model'; import { SubmitDataResponseDefinitionObject } from '../core/shared/submit-data-response-definition.model';
import { CoreState } from '../core/core.reducers';
import { HttpOptions } from '../core/dspace-rest-v2/dspace-rest-v2.service'; import { HttpOptions } from '../core/dspace-rest-v2/dspace-rest-v2.service';
import { HALEndpointService } from '../core/shared/hal-endpoint.service'; import { HALEndpointService } from '../core/shared/hal-endpoint.service';
import { RemoteDataBuildService } from '../core/cache/builders/remote-data-build.service'; import { RemoteDataBuildService } from '../core/cache/builders/remote-data-build.service';
@@ -33,7 +30,6 @@ export class SubmissionRestService {
protected rdbService: RemoteDataBuildService, protected rdbService: RemoteDataBuildService,
protected responseCache: ResponseCacheService, protected responseCache: ResponseCacheService,
protected requestService: RequestService, protected requestService: RequestService,
protected store: Store<CoreState>,
protected halService: HALEndpointService) { protected halService: HALEndpointService) {
} }
@@ -104,13 +100,6 @@ export class SubmissionRestService {
distinctUntilChanged()); distinctUntilChanged());
} }
public getDataByHref(href: string, options?: HttpOptions): Observable<any> {
const request = new ConfigRequest(this.requestService.generateRequestId(), href, options);
this.requestService.configure(request, true);
return this.fetchRequest(request);
}
public getDataById(linkName: string, id: string): Observable<any> { public getDataById(linkName: string, id: string): Observable<any> {
return this.halService.getEndpoint(linkName).pipe( return this.halService.getEndpoint(linkName).pipe(
map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, id)), map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, id)),

View File

@@ -1,9 +1,9 @@
import { StoreModule } from '@ngrx/store'; import { StoreModule } from '@ngrx/store';
import { async, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { async, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { HttpHeaders } from '@angular/common/http'; import { HttpHeaders } from '@angular/common/http';
import { ScrollToService } from '@nicky-lenaers/ngx-scroll-to'; import { of as observableOf } from 'rxjs';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { cold, hot, } from 'jasmine-marbles'; import { cold, hot, } from 'jasmine-marbles';
@@ -17,14 +17,27 @@ import { MockActivatedRoute } from '../shared/mocks/mock-active-router';
import { GLOBAL_CONFIG } from '../../config'; import { GLOBAL_CONFIG } from '../../config';
import { HttpOptions } from '../core/dspace-rest-v2/dspace-rest-v2.service'; import { HttpOptions } from '../core/dspace-rest-v2/dspace-rest-v2.service';
import { SubmissionScopeType } from '../core/submission/submission-scope-type'; import { SubmissionScopeType } from '../core/submission/submission-scope-type';
import { submissionRestResponse } from '../shared/mocks/mock-submission'; import { mockSubmissionDefinition, submissionRestResponse } from '../shared/mocks/mock-submission';
import { NotificationsService } from '../shared/notifications/notifications.service'; import { NotificationsService } from '../shared/notifications/notifications.service';
import { MockTranslateLoader } from '../shared/mocks/mock-translate-loader'; import { MockTranslateLoader } from '../shared/mocks/mock-translate-loader';
import { MOCK_SUBMISSION_CONFIG } from '../shared/testing/mock-submission-config'; import { MOCK_SUBMISSION_CONFIG } from '../shared/testing/mock-submission-config';
import {
CancelSubmissionFormAction,
ChangeSubmissionCollectionAction,
DiscardSubmissionAction,
InitSubmissionFormAction,
ResetSubmissionFormAction,
SaveAndDepositSubmissionAction,
SaveForLaterSubmissionFormAction,
SaveSubmissionFormAction, SaveSubmissionSectionFormAction,
SetActiveSectionAction
} from './objects/submission-objects.actions';
describe('SubmissionService test suite', () => { describe('SubmissionService test suite', () => {
const config = MOCK_SUBMISSION_CONFIG; const config = MOCK_SUBMISSION_CONFIG;
const collectionId = '43fe1f8c-09a6-4fcf-9c78-5d4fed8f2c8f';
const submissionId = '826';
const sectionId = 'test';
const subState = { const subState = {
objects: { objects: {
826: { 826: {
@@ -317,13 +330,15 @@ describe('SubmissionService test suite', () => {
}; };
const restService = new SubmissionRestServiceStub(); const restService = new SubmissionRestServiceStub();
const router = new MockRouter(); const router = new MockRouter();
const selfUrl = 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826';
const submissionDefinition: any = mockSubmissionDefinition;
let service: SubmissionService; let service: SubmissionService;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
StoreModule.forRoot({ submissionReducers } as any), StoreModule.forRoot({submissionReducers} as any),
TranslateModule.forRoot({ TranslateModule.forRoot({
loader: { loader: {
provide: TranslateLoader, provide: TranslateLoader,
@@ -332,13 +347,12 @@ describe('SubmissionService test suite', () => {
}) })
], ],
providers: [ providers: [
{ provide: GLOBAL_CONFIG, useValue: config }, {provide: GLOBAL_CONFIG, useValue: config},
{ provide: Router, useValue: router }, {provide: Router, useValue: router},
{ provide: SubmissionRestService, useValue: restService }, {provide: SubmissionRestService, useValue: restService},
{ provide: ActivatedRoute, useValue: new MockActivatedRoute() }, {provide: ActivatedRoute, useValue: new MockActivatedRoute()},
NotificationsService, NotificationsService,
RouteService, RouteService,
ScrollToService,
SubmissionService, SubmissionService,
TranslateService TranslateService
] ]
@@ -347,334 +361,514 @@ describe('SubmissionService test suite', () => {
beforeEach(() => { beforeEach(() => {
service = TestBed.get(SubmissionService); service = TestBed.get(SubmissionService);
spyOn((service as any).store, 'dispatch').and.callThrough()
}); });
it('should create a new submission', () => { describe('changeSubmissionCollection', () => {
service.createSubmission(); it('should dispatch a new ChangeSubmissionCollectionAction', () => {
service.changeSubmissionCollection(submissionId, collectionId);
const expected = new ChangeSubmissionCollectionAction(submissionId, collectionId);
expect((service as any).restService.postToEndpoint).toHaveBeenCalled(); expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
});
it('should deposit submission', () => {
const selfUrl = 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826';
const options: HttpOptions = Object.create({});
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'text/uri-list');
options.headers = headers;
service.depositSubmission(selfUrl);
expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workflowitems', selfUrl, null, options);
});
it('should discard submission', () => {
service.discardSubmission('826');
expect((service as any).restService.deleteById).toHaveBeenCalledWith('826');
});
it('should return submission object state from the store', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('a', {
a: subState.objects[826]
}));
const result = service.getSubmissionObject('826');
const expected = cold('b', { b: subState.objects[826] });
expect(result).toBeObservable(expected);
});
it('should return current active submission form section', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('a', {
a: subState.objects[826]
}));
const result = service.getActiveSectionId('826');
const expected = cold('b', { b: 'keyinformation' });
expect(result).toBeObservable(expected);
});
it('should return submission form sections', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('a|', {
a: subState.objects[826]
}));
const result = service.getSubmissionSections('826');
const expected = cold('(bc|)', {
b: [],
c:
[
{
header: 'submit.progressbar.describe.keyinformation',
id: 'keyinformation',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/keyinformation',
mandatory: true,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.indexing',
id: 'indexing',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/indexing',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.publicationchannel',
id: 'publicationchannel',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/publicationchannel',
mandatory: true,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.acknowledgement',
id: 'acknowledgement',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/acknowledgement',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.identifiers',
id: 'identifiers',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/identifiers',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.references',
id: 'references',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/references',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.upload',
id: 'upload',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload',
mandatory: true,
sectionType: 'upload',
data: {},
errors: []
},
{
header: 'submit.progressbar.license',
id: 'license',
config: '',
mandatory: true,
sectionType: 'license',
data: {},
errors: []
}
]
}); });
expect(result).toBeObservable(expected);
}); });
it('should return list of submission disabled sections', () => { describe('createSubmission', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a|', { it('should create a new submission', () => {
a: subState.objects[826] service.createSubmission();
}));
const result = service.getDisabledSectionsList('826'); expect((service as any).restService.postToEndpoint).toHaveBeenCalled();
const expected = cold('bc|', {
b: [],
c:
[
{
header: 'submit.progressbar.describe.indexing',
id: 'indexing',
},
{
header: 'submit.progressbar.describe.acknowledgement',
id: 'acknowledgement',
},
{
header: 'submit.progressbar.describe.identifiers',
id: 'identifiers',
},
{
header: 'submit.progressbar.describe.references',
id: 'references',
}
]
}); });
expect(result).toBeObservable(expected);
}); });
it('should return true/false when section is hidden/visible', () => { describe('depositSubmission', () => {
let section: any = { it('should deposit submission', () => {
config: '', const options: HttpOptions = Object.create({});
header: '', let headers = new HttpHeaders();
mandatory: true, headers = headers.append('Content-Type', 'text/uri-list');
sectionType: 'collection' as any, options.headers = headers;
visibility: {
main: 'HIDDEN',
other: 'HIDDEN'
},
collapsed: false,
enabled: true,
data: {},
errors: [],
isLoading: false,
isValid: false
};
expect(service.isSectionHidden(section)).toBeTruthy();
section = { service.depositSubmission(selfUrl);
header: 'submit.progressbar.describe.keyinformation',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/keyinformation',
mandatory: true,
sectionType: 'submission-form',
collapsed: false,
enabled: true,
data: {},
errors: [],
isLoading: false,
isValid: false
};
expect(service.isSectionHidden(section)).toBeFalsy();
});
it('should return properly submission link name', () => { expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workflowitems', selfUrl, null, options);
let expected = 'workspaceitems';
router.setRoute('/workspaceitems/826/edit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
expected = 'workspaceitems';
router.setRoute('/submit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
expected = 'workflowitems';
router.setRoute('/workflowitems/826/edit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
expected = 'edititems';
router.setRoute('/items/9e79b1f2-ae0f-4737-9a4b-990952a8857c/edit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
});
it('should return properly submission scope', () => {
let expected = SubmissionScopeType.WorkspaceItem;
router.setRoute('/workspaceitems/826/edit');
expect(service.getSubmissionScope()).toBe(expected);
router.setRoute('/submit');
expect(service.getSubmissionScope()).toBe(expected);
expected = SubmissionScopeType.WorkflowItem;
router.setRoute('/workflowitems/826/edit');
expect(service.getSubmissionScope()).toBe(expected);
expected = SubmissionScopeType.EditItem;
router.setRoute('/items/9e79b1f2-ae0f-4737-9a4b-990952a8857c/edit');
expect(service.getSubmissionScope()).toBe(expected);
});
it('should return properly submission status', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a-b', {
a: subState,
b: validSubState
}));
const result = service.getSubmissionStatus('826');
const expected = cold('cc-d', {
c: false,
d: true
}); });
expect(result).toBeObservable(expected);
}); });
it('should return submission save processing status', () => { describe('discardSubmission', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a', { it('should discard submission', () => {
a: subState.objects[826] service.discardSubmission('826');
}));
const result = service.getSubmissionSaveProcessingStatus('826'); expect((service as any).restService.deleteById).toHaveBeenCalledWith('826');
const expected = cold('bb', {
b: false
}); });
expect(result).toBeObservable(expected);
}); });
it('should return submission deposit processing status', () => { describe('dispatchInit', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a', { it('should dispatch a new InitSubmissionFormAction', () => {
a: subState.objects[826] service.dispatchInit(
})); collectionId,
submissionId,
selfUrl,
submissionDefinition,
{},
[]
);
const expected = new InitSubmissionFormAction(
collectionId,
submissionId,
selfUrl,
submissionDefinition,
{},
[]);
const result = service.getSubmissionDepositProcessingStatus('826'); expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
const expected = cold('bb', {
b: false
}); });
expect(result).toBeObservable(expected);
}); });
it('should redirect to MyDspace page', () => { describe('dispatchDeposit', () => {
const spy = spyOn((service as any).routeService, 'getPreviousUrl'); it('should dispatch a new SaveAndDepositSubmissionAction', () => {
service.dispatchDeposit(submissionId,);
const expected = new SaveAndDepositSubmissionAction(submissionId);
spy.and.returnValue('/mydspace?configuration=workflow'); expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
service.redirectToMyDSpace();
expect((service as any).router.navigateByUrl).toHaveBeenCalledWith('/mydspace?configuration=workflow');
spy.and.returnValue('');
service.redirectToMyDSpace();
expect((service as any).router.navigate).toHaveBeenCalledWith(['/mydspace']);
});
it('should retrieve submission from REST endpoint', () => {
(service as any).restService.getDataById.and.returnValue(hot('a|', {
a: submissionRestResponse
}));
const result = service.retrieveSubmission('826');
const expected = cold('(b|)', {
b: submissionRestResponse[0]
}); });
expect(result).toBeObservable(expected);
}); });
it('should start Auto Save', fakeAsync(() => { describe('dispatchDiscard', () => {
const duration = config.submission.autosave.timer * (1000 * 60); it('should dispatch a new DiscardSubmissionAction', () => {
spyOn((service as any).store, 'dispatch'); service.dispatchDiscard(submissionId,);
const expected = new DiscardSubmissionAction(submissionId);
service.startAutoSave('826'); expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
const sub = (service as any).timerObs.subscribe(); });
});
tick(duration / 2); describe('dispatchSave', () => {
expect((service as any).store.dispatch).not.toHaveBeenCalled(); it('should dispatch a new SaveSubmissionFormAction', () => {
service.dispatchSave(submissionId,);
const expected = new SaveSubmissionFormAction(submissionId);
tick(duration / 2); expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
expect((service as any).store.dispatch).toHaveBeenCalled(); });
});
sub.unsubscribe(); describe('dispatchSaveForLater', () => {
(service as any).autoSaveSub.unsubscribe(); it('should dispatch a new SaveForLaterSubmissionFormAction', () => {
})); service.dispatchSaveForLater(submissionId,);
const expected = new SaveForLaterSubmissionFormAction(submissionId);
it('should stop Auto Save', () => { expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
service.startAutoSave('826'); });
service.stopAutoSave(); });
expect((service as any).autoSaveSub).toBeNull(); describe('dispatchSaveSection', () => {
it('should dispatch a new SaveSubmissionSectionFormAction', () => {
service.dispatchSaveSection(submissionId, sectionId);
const expected = new SaveSubmissionSectionFormAction(submissionId, sectionId);
expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
});
});
describe('getSubmissionObject', () => {
it('should return submission object state from the store', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('a', {
a: subState.objects[826]
}));
const result = service.getSubmissionObject('826');
const expected = cold('b', {b: subState.objects[826]});
expect(result).toBeObservable(expected);
});
});
describe('getActiveSectionId', () => {
it('should return current active submission form section', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('a', {
a: subState.objects[826]
}));
const result = service.getActiveSectionId('826');
const expected = cold('b', {b: 'keyinformation'});
expect(result).toBeObservable(expected);
});
});
describe('getSubmissionSections', () => {
it('should return submission form sections', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('a|', {
a: subState.objects[826]
}));
const result = service.getSubmissionSections('826');
const expected = cold('(bc|)', {
b: [],
c:
[
{
header: 'submit.progressbar.describe.keyinformation',
id: 'keyinformation',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/keyinformation',
mandatory: true,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.indexing',
id: 'indexing',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/indexing',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.publicationchannel',
id: 'publicationchannel',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/publicationchannel',
mandatory: true,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.acknowledgement',
id: 'acknowledgement',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/acknowledgement',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.identifiers',
id: 'identifiers',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/identifiers',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.describe.references',
id: 'references',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/references',
mandatory: false,
sectionType: 'submission-form',
data: {},
errors: []
},
{
header: 'submit.progressbar.upload',
id: 'upload',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload',
mandatory: true,
sectionType: 'upload',
data: {},
errors: []
},
{
header: 'submit.progressbar.license',
id: 'license',
config: '',
mandatory: true,
sectionType: 'license',
data: {},
errors: []
}
]
});
expect(result).toBeObservable(expected);
});
});
describe('getDisabledSectionsList', () => {
it('should return list of submission disabled sections', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a|', {
a: subState.objects[826]
}));
const result = service.getDisabledSectionsList('826');
const expected = cold('bc|', {
b: [],
c:
[
{
header: 'submit.progressbar.describe.indexing',
id: 'indexing',
},
{
header: 'submit.progressbar.describe.acknowledgement',
id: 'acknowledgement',
},
{
header: 'submit.progressbar.describe.identifiers',
id: 'identifiers',
},
{
header: 'submit.progressbar.describe.references',
id: 'references',
}
]
});
expect(result).toBeObservable(expected);
});
});
describe('getSubmissionObjectLinkName', () => {
it('should return properly submission link name', () => {
let expected = 'workspaceitems';
router.setRoute('/workspaceitems/826/edit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
expected = 'workspaceitems';
router.setRoute('/submit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
expected = 'workflowitems';
router.setRoute('/workflowitems/826/edit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
expected = 'edititems';
router.setRoute('/items/9e79b1f2-ae0f-4737-9a4b-990952a8857c/edit');
expect(service.getSubmissionObjectLinkName()).toBe(expected);
});
});
describe('getSubmissionScope', () => {
it('should return properly submission scope', () => {
let expected = SubmissionScopeType.WorkspaceItem;
router.setRoute('/workspaceitems/826/edit');
expect(service.getSubmissionScope()).toBe(expected);
router.setRoute('/submit');
expect(service.getSubmissionScope()).toBe(expected);
expected = SubmissionScopeType.WorkflowItem;
router.setRoute('/workflowitems/826/edit');
expect(service.getSubmissionScope()).toBe(expected);
expected = SubmissionScopeType.EditItem;
router.setRoute('/items/9e79b1f2-ae0f-4737-9a4b-990952a8857c/edit');
expect(service.getSubmissionScope()).toBe(expected);
});
});
describe('getSubmissionStatus', () => {
it('should return properly submission status', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a-b', {
a: subState,
b: validSubState
}));
const result = service.getSubmissionStatus('826');
const expected = cold('cc-d', {
c: false,
d: true
});
expect(result).toBeObservable(expected);
});
});
describe('getSubmissionSaveProcessingStatus', () => {
it('should return submission save processing status', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a', {
a: subState.objects[826]
}));
const result = service.getSubmissionSaveProcessingStatus('826');
const expected = cold('bb', {
b: false
});
expect(result).toBeObservable(expected);
});
});
describe('getSubmissionDepositProcessingStatus', () => {
it('should return submission deposit processing status', () => {
spyOn((service as any).store, 'select').and.returnValue(hot('-a', {
a: subState.objects[826]
}));
const result = service.getSubmissionDepositProcessingStatus('826');
const expected = cold('bb', {
b: false
});
expect(result).toBeObservable(expected);
});
});
describe('isSectionHidden', () => {
it('should return true/false when section is hidden/visible', () => {
let section: any = {
config: '',
header: '',
mandatory: true,
sectionType: 'collection' as any,
visibility: {
main: 'HIDDEN',
other: 'HIDDEN'
},
collapsed: false,
enabled: true,
data: {},
errors: [],
isLoading: false,
isValid: false
};
expect(service.isSectionHidden(section)).toBeTruthy();
section = {
header: 'submit.progressbar.describe.keyinformation',
config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/keyinformation',
mandatory: true,
sectionType: 'submission-form',
collapsed: false,
enabled: true,
data: {},
errors: [],
isLoading: false,
isValid: false
};
expect(service.isSectionHidden(section)).toBeFalsy();
});
});
describe('isSubmissionLoading', () => {
it('should return true/false when section is loading/not loading', () => {
const spy = spyOn(service, 'getSubmissionObject').and.returnValue(observableOf({isLoading: true}));
let expected = cold('(b|)', {
b: true
});
expect(service.isSubmissionLoading(submissionId)).toBeObservable(expected);
spy.and.returnValue(observableOf({isLoading: false}));
expected = cold('(b|)', {
b: false
});
expect(service.isSubmissionLoading(submissionId)).toBeObservable(expected);
});
});
describe('notifyNewSection', () => {
it('should return true/false when section is loading/not loading', fakeAsync(() => {
const spy = spyOn((service as any).translate, 'get').and.returnValue(observableOf('test'));
spyOn((service as any).notificationsService, 'info').and.callThrough();
service.notifyNewSection(submissionId, sectionId);
flush();
expect((service as any).notificationsService.info).toHaveBeenCalledWith(null, 'test', null, true);
}));
});
describe('redirectToMyDSpace', () => {
it('should redirect to MyDspace page', () => {
const spy = spyOn((service as any).routeService, 'getPreviousUrl');
spy.and.returnValue('/mydspace?configuration=workflow');
service.redirectToMyDSpace();
expect((service as any).router.navigateByUrl).toHaveBeenCalledWith('/mydspace?configuration=workflow');
spy.and.returnValue('');
service.redirectToMyDSpace();
expect((service as any).router.navigate).toHaveBeenCalledWith(['/mydspace']);
});
});
describe('resetAllSubmissionObjects', () => {
it('should dispatch a new CancelSubmissionFormAction', () => {
service.resetAllSubmissionObjects();
const expected = new CancelSubmissionFormAction();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
});
});
describe('resetSubmissionObject', () => {
it('should dispatch a new ResetSubmissionFormAction', () => {
service.resetSubmissionObject(
collectionId,
submissionId,
selfUrl,
submissionDefinition,
{}
);
const expected = new ResetSubmissionFormAction(
collectionId,
submissionId,
selfUrl,
{},
submissionDefinition
);
expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
});
});
describe('retrieveSubmission', () => {
it('should retrieve submission from REST endpoint', () => {
(service as any).restService.getDataById.and.returnValue(hot('a|', {
a: submissionRestResponse
}));
const result = service.retrieveSubmission('826');
const expected = cold('(b|)', {
b: submissionRestResponse[0]
});
expect(result).toBeObservable(expected);
});
});
describe('setActiveSection', () => {
it('should dispatch a new SetActiveSectionAction', () => {
service.setActiveSection(submissionId, sectionId);
const expected = new SetActiveSectionAction(submissionId, sectionId);
expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
});
});
describe('startAutoSave', () => {
it('should start Auto Save', fakeAsync(() => {
const duration = config.submission.autosave.timer * (1000 * 60);
service.startAutoSave('826');
const sub = (service as any).timerObs.subscribe();
tick(duration / 2);
expect((service as any).store.dispatch).not.toHaveBeenCalled();
tick(duration / 2);
expect((service as any).store.dispatch).toHaveBeenCalled();
sub.unsubscribe();
(service as any).autoSaveSub.unsubscribe();
}));
});
describe('stopAutoSave', () => {
it('should stop Auto Save', () => {
service.startAutoSave('826');
service.stopAutoSave();
expect((service as any).autoSaveSub).toBeNull();
});
}); });
}); });

View File

@@ -6,7 +6,6 @@ import { Observable, of as observableOf, Subscription, timer as observableTimer
import { catchError, distinctUntilChanged, filter, first, map, startWith } from 'rxjs/operators'; import { catchError, distinctUntilChanged, filter, first, map, startWith } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { ScrollToService } from '@nicky-lenaers/ngx-scroll-to';
import { submissionSelector, SubmissionState } from './submission.reducers'; import { submissionSelector, SubmissionState } from './submission.reducers';
import { hasValue, isEmpty, isNotUndefined } from '../shared/empty.util'; import { hasValue, isEmpty, isNotUndefined } from '../shared/empty.util';
@@ -18,7 +17,7 @@ import {
ResetSubmissionFormAction, ResetSubmissionFormAction,
SaveAndDepositSubmissionAction, SaveAndDepositSubmissionAction,
SaveForLaterSubmissionFormAction, SaveForLaterSubmissionFormAction,
SaveSubmissionFormAction, SaveSubmissionFormAction, SaveSubmissionSectionFormAction,
SetActiveSectionAction SetActiveSectionAction
} from './objects/submission-objects.actions'; } from './objects/submission-objects.actions';
import { import {
@@ -52,7 +51,6 @@ export class SubmissionService {
protected restService: SubmissionRestService, protected restService: SubmissionRestService,
protected router: Router, protected router: Router,
protected routeService: RouteService, protected routeService: RouteService,
protected scrollToService: ScrollToService,
protected store: Store<SubmissionState>, protected store: Store<SubmissionState>,
protected translate: TranslateService) { protected translate: TranslateService) {
} }
@@ -106,7 +104,7 @@ export class SubmissionService {
} }
dispatchSaveSection(submissionId, sectionId) { dispatchSaveSection(submissionId, sectionId) {
this.store.dispatch(new SaveSubmissionFormAction(submissionId)); this.store.dispatch(new SaveSubmissionSectionFormAction(submissionId, sectionId));
} }
getActiveSectionId(submissionId: string): Observable<string> { getActiveSectionId(submissionId: string): Observable<string> {