Added tests

This commit is contained in:
Giuseppe Digilio
2018-12-28 18:31:36 +01:00
parent feb8172b32
commit dff2518bf4
6 changed files with 637 additions and 6 deletions

View File

@@ -22,7 +22,7 @@ import {
} from './auth.actions';
import { AuthServiceStub } from '../../shared/testing/auth-service-stub';
import { AuthService } from './auth.service';
import { TruncatablesState } from '../../shared/truncatable/truncatable.reducer';
import { AuthState } from './auth.reducer';
import { EPersonMock } from '../../shared/testing/eperson-mock';
@@ -30,7 +30,7 @@ describe('AuthEffects', () => {
let authEffects: AuthEffects;
let actions: Observable<any>;
let authServiceStub;
const store: Store<TruncatablesState> = jasmine.createSpyObj('store', {
const store: Store<AuthState> = jasmine.createSpyObj('store', {
/* tslint:disable:no-empty */
dispatch: {},
/* tslint:enable:no-empty */

View File

@@ -73,7 +73,7 @@ describe('AuthService test', () => {
{ provide: REQUEST, useValue: {} },
{ provide: Router, useValue: routerStub },
{ provide: ActivatedRoute, useValue: routeStub },
{provide: Store, useValue: mockStore},
{ provide: Store, useValue: mockStore },
{ provide: RemoteDataBuildService, useValue: rdbService },
CookieService,
AuthService

View File

@@ -0,0 +1,58 @@
import { TestBed } from '@angular/core/testing';
import { cold, hot } from 'jasmine-marbles';
import { provideMockActions } from '@ngrx/effects/testing';
import { Store } from '@ngrx/store';
import { Observable, of as observableOf } from 'rxjs';
import { JsonPatchOperationsEffects } from './json-patch-operations.effects';
import { JsonPatchOperationsState } from './json-patch-operations.reducer';
import { FlushPatchOperationsAction, JsonPatchOperationsActionTypes } from './json-patch-operations.actions';
describe('JsonPatchOperationsEffects test suite', () => {
let jsonPatchOperationsEffects: JsonPatchOperationsEffects;
let actions: Observable<any>;
const store: Store<JsonPatchOperationsState> = jasmine.createSpyObj('store', {
/* tslint:disable:no-empty */
dispatch: {},
/* tslint:enable:no-empty */
select: observableOf(true)
});
const testJsonPatchResourceType = 'testResourceType';
const testJsonPatchResourceId = 'testResourceId';
function init() {
}
beforeEach(() => {
init();
TestBed.configureTestingModule({
providers: [
JsonPatchOperationsEffects,
{provide: Store, useValue: store},
provideMockActions(() => actions),
// other providers
],
});
jsonPatchOperationsEffects = TestBed.get(JsonPatchOperationsEffects);
});
describe('commit$', () => {
it('should return a FLUSH_JSON_PATCH_OPERATIONS action in response to a COMMIT_JSON_PATCH_OPERATIONS action', () => {
actions = hot('--a-', {
a: {
type: JsonPatchOperationsActionTypes.COMMIT_JSON_PATCH_OPERATIONS,
payload: {resourceType: testJsonPatchResourceType, resourceId: testJsonPatchResourceId}
}
});
const expected = cold('--b-', {
b: new FlushPatchOperationsAction(testJsonPatchResourceType, testJsonPatchResourceId)
});
expect(jsonPatchOperationsEffects.commit$).toBeObservable(expected);
});
});
});

View File

@@ -0,0 +1,328 @@
import * as deepFreeze from 'deep-freeze';
import {
CommitPatchOperationsAction,
FlushPatchOperationsAction,
NewPatchAddOperationAction,
NewPatchRemoveOperationAction,
RollbacktPatchOperationsAction,
StartTransactionPatchOperationsAction
} from './json-patch-operations.actions';
import {
JsonPatchOperationsEntry,
jsonPatchOperationsReducer,
JsonPatchOperationsResourceEntry,
JsonPatchOperationsState
} from './json-patch-operations.reducer';
class NullAction extends NewPatchAddOperationAction {
resourceType: string;
resourceId: string;
path: string;
value: any;
constructor() {
super(null, null, null, null);
this.type = null;
}
}
describe('jsonPatchOperationsReducer test suite', () => {
const testJsonPatchResourceType = 'testResourceType';
const testJsonPatchResourceId = 'testResourceId';
const testJsonPatchResourceAnotherId = 'testResourceAnotherId';
const testJsonPatchResourcePath = '/testResourceType/testResourceId/testField';
const testJsonPatchResourceValue = ['test'];
const patchOpBody = [{
op: 'add',
path: '/testResourceType/testResourceId/testField',
value: ['test']
}];
const timestampBeforeStart = 1545994811991;
const timestampAfterStart = 1545994837492;
const startTimestamp = 1545994827492;
const testState: JsonPatchOperationsState = {
testResourceType: {
children: {
testResourceId: {
body: [
{
operation: {
op: 'add',
path: '/testResourceType/testResourceId/testField',
value: ['test']
},
timeAdded: timestampBeforeStart
},
]
} as JsonPatchOperationsEntry
},
transactionStartTime: null,
commitPending: false
} as JsonPatchOperationsResourceEntry
};
let initState: JsonPatchOperationsState;
const anotherTestState: JsonPatchOperationsState = {
testResourceType: {
children: {
testResourceId: {
body: [
{
operation: {
op: 'add',
path: '/testResourceType/testResourceId/testField',
value: ['test']
},
timeAdded: timestampBeforeStart
},
{
operation: {
op: 'remove',
path: '/testResourceType/testResourceId/testField'
},
timeAdded: timestampBeforeStart
},
]
} as JsonPatchOperationsEntry
},
transactionStartTime: null,
commitPending: false
} as JsonPatchOperationsResourceEntry
};
deepFreeze(testState);
beforeEach(() => {
spyOn(Date.prototype, 'getTime').and.callFake(() => {
return timestampBeforeStart;
});
});
it('should start with an empty state', () => {
const action = new NullAction();
const initialState = jsonPatchOperationsReducer(undefined, action);
expect(initialState).toEqual(Object.create(null));
});
it('should return the current state when no valid actions have been made', () => {
const action = new NullAction();
const newState = jsonPatchOperationsReducer(testState, action);
expect(newState).toEqual(testState);
});
describe('When a new patch operation actions have been dispatched', () => {
it('should return the properly state when it is empty', () => {
const action = new NewPatchAddOperationAction(
testJsonPatchResourceType,
testJsonPatchResourceId,
testJsonPatchResourcePath,
testJsonPatchResourceValue);
const newState = jsonPatchOperationsReducer(undefined, action);
expect(newState).toEqual(testState);
});
it('should return the properly state when it is not empty', () => {
const action = new NewPatchRemoveOperationAction(
testJsonPatchResourceType,
testJsonPatchResourceId,
testJsonPatchResourcePath);
const newState = jsonPatchOperationsReducer(testState, action);
expect(newState).toEqual(anotherTestState);
});
});
describe('When StartTransactionPatchOperationsAction has been dispatched', () => {
it('should set \'transactionStartTime\' and \'commitPending\' to true', () => {
const action = new StartTransactionPatchOperationsAction(
testJsonPatchResourceType,
testJsonPatchResourceId,
startTimestamp);
const newState = jsonPatchOperationsReducer(testState, action);
expect(newState[testJsonPatchResourceType].transactionStartTime).toEqual(startTimestamp);
expect(newState[testJsonPatchResourceType].commitPending).toBeTruthy();
});
});
describe('When CommitPatchOperationsAction has been dispatched', () => {
it('should set \'commitPending\' to false ', () => {
const action = new CommitPatchOperationsAction(
testJsonPatchResourceType,
testJsonPatchResourceId);
initState = Object.assign({}, testState, {
[testJsonPatchResourceType]: Object.assign({}, testState[testJsonPatchResourceType], {
transactionStartTime: startTimestamp,
commitPending: true
})
});
const newState = jsonPatchOperationsReducer(initState, action);
expect(newState[testJsonPatchResourceType].transactionStartTime).toEqual(startTimestamp);
expect(newState[testJsonPatchResourceType].commitPending).toBeFalsy();
});
});
describe('When RollbacktPatchOperationsAction has been dispatched', () => {
it('should set \'transactionStartTime\' to null and \'commitPending\' to false ', () => {
const action = new RollbacktPatchOperationsAction(
testJsonPatchResourceType,
testJsonPatchResourceId);
initState = Object.assign({}, testState, {
[testJsonPatchResourceType]: Object.assign({}, testState[testJsonPatchResourceType], {
transactionStartTime: startTimestamp,
commitPending: true
})
});
const newState = jsonPatchOperationsReducer(initState, action);
expect(newState[testJsonPatchResourceType].transactionStartTime).toBeNull();
expect(newState[testJsonPatchResourceType].commitPending).toBeFalsy();
});
});
describe('When FlushPatchOperationsAction has been dispatched', () => {
it('should flush only committed operations', () => {
const action = new FlushPatchOperationsAction(
testJsonPatchResourceType,
testJsonPatchResourceId);
initState = Object.assign({}, testState, {
[testJsonPatchResourceType]: Object.assign({}, testState[testJsonPatchResourceType], {
children: {
testResourceId: {
body: [
{
operation: {
op: 'add',
path: '/testResourceType/testResourceId/testField',
value: ['test']
},
timeAdded: timestampBeforeStart
},
{
operation: {
op: 'remove',
path: '/testResourceType/testResourceId/testField'
},
timeAdded: timestampAfterStart
},
]
} as JsonPatchOperationsEntry
},
transactionStartTime: startTimestamp,
commitPending: false
})
});
const newState = jsonPatchOperationsReducer(initState, action);
const expectedBody: any = [
{
operation: {
op: 'remove',
path: '/testResourceType/testResourceId/testField'
},
timeAdded: timestampAfterStart
},
];
expect(newState[testJsonPatchResourceType].transactionStartTime).toBeNull();
expect(newState[testJsonPatchResourceType].commitPending).toBeFalsy();
expect(newState[testJsonPatchResourceType].children[testJsonPatchResourceId].body).toEqual(expectedBody);
});
beforeEach(() => {
initState = Object.assign({}, testState, {
[testJsonPatchResourceType]: Object.assign({}, testState[testJsonPatchResourceType], {
children: {
testResourceId: {
body: [
{
operation: {
op: 'add',
path: '/testResourceType/testResourceId/testField',
value: ['test']
},
timeAdded: timestampBeforeStart
},
{
operation: {
op: 'remove',
path: '/testResourceType/testResourceId/testField'
},
timeAdded: timestampBeforeStart
},
]
} as JsonPatchOperationsEntry,
testResourceAnotherId: {
body: [
{
operation: {
op: 'add',
path: '/testResourceType/testResourceAnotherId/testField',
value: ['test']
},
timeAdded: timestampBeforeStart
},
{
operation: {
op: 'remove',
path: '/testResourceType/testResourceAnotherId/testField'
},
timeAdded: timestampBeforeStart
},
]
} as JsonPatchOperationsEntry
},
transactionStartTime: startTimestamp,
commitPending: false
})
});
});
it('should flush committed operations for specified resource id', () => {
const action = new FlushPatchOperationsAction(
testJsonPatchResourceType,
testJsonPatchResourceId);
const newState = jsonPatchOperationsReducer(initState, action);
const expectedBody: any = [
{
operation: {
op: 'add',
path: '/testResourceType/testResourceAnotherId/testField',
value: ['test']
},
timeAdded: timestampBeforeStart
},
{
operation: {
op: 'remove',
path: '/testResourceType/testResourceAnotherId/testField'
},
timeAdded: timestampBeforeStart
},
];
expect(newState[testJsonPatchResourceType].transactionStartTime).toBeNull();
expect(newState[testJsonPatchResourceType].commitPending).toBeFalsy();
expect(newState[testJsonPatchResourceType].children[testJsonPatchResourceId].body).toEqual([]);
expect(newState[testJsonPatchResourceType].children[testJsonPatchResourceAnotherId].body).toEqual(expectedBody);
});
it('should flush operation list', () => {
const action = new FlushPatchOperationsAction(testJsonPatchResourceType, undefined);
const newState = jsonPatchOperationsReducer(initState, action);
console.log(initState);
console.log(newState);
expect(newState[testJsonPatchResourceType].transactionStartTime).toBeNull();
expect(newState[testJsonPatchResourceType].commitPending).toBeFalsy();
expect(newState[testJsonPatchResourceType].children[testJsonPatchResourceId].body).toEqual([]);
expect(newState[testJsonPatchResourceType].children[testJsonPatchResourceAnotherId].body).toEqual([]);
});
});
});

View File

@@ -0,0 +1,245 @@
import { cold, getTestScheduler } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing';
import { of as observableOf } from 'rxjs';
import { Store } from '@ngrx/store';
import { getMockRequestService } from '../../shared/mocks/mock-request.service';
import { ResponseCacheService } from '../cache/response-cache.service';
import { RequestService } from '../data/request.service';
import { SubmissionPatchRequest } from '../data/request.models';
import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service';
import { JsonPatchOperationsService } from './json-patch-operations.service';
import { SubmitDataResponseDefinitionObject } from '../shared/submit-data-response-definition.model';
import { CoreState } from '../core.reducers';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { JsonPatchOperationsEntry, JsonPatchOperationsResourceEntry } from './json-patch-operations.reducer';
import { MockStore } from '../../shared/testing/mock-store';
import {
CommitPatchOperationsAction,
RollbacktPatchOperationsAction,
StartTransactionPatchOperationsAction
} from './json-patch-operations.actions';
class TestService extends JsonPatchOperationsService<SubmitDataResponseDefinitionObject, SubmissionPatchRequest> {
protected linkPath = '';
protected patchRequestConstructor = SubmissionPatchRequest;
constructor(
protected responseCache: ResponseCacheService,
protected requestService: RequestService,
protected store: Store<CoreState>,
protected halService: HALEndpointService) {
super();
}
}
describe('JsonPatchOperationsService test suite', () => {
let scheduler: TestScheduler;
let service: TestService;
let responseCache: ResponseCacheService;
let requestService: RequestService;
let rdbService: RemoteDataBuildService;
let halService: any;
let store: any;
const timestamp = 1545994811991;
const timestampResponse = 1545994811992;
const mockState = {
'json/patch': {
testResourceType: {
children: {
testResourceId: {
body: [
{
operation: {
op: 'add',
path: '/testResourceType/testResourceId/testField',
value: ['test']
},
timeAdded: timestamp
},
]
} as JsonPatchOperationsEntry
},
transactionStartTime: null,
commitPending: false
} as JsonPatchOperationsResourceEntry
}
};
const resourceEndpointURL = 'https://rest.api/endpoint';
const resourceEndpoint = 'resource';
const resourceScope = '260';
const resourceHref = resourceEndpointURL + '/' + resourceEndpoint + '/' + resourceScope;
const testJsonPatchResourceType = 'testResourceType';
const testJsonPatchResourceId = 'testResourceId';
const patchOpBody = [{
op: 'add',
path: '/testResourceType/testResourceId/testField',
value: ['test']
}];
function initMockResponseCacheService(isSuccessful: boolean): ResponseCacheService {
return jasmine.createSpyObj('responseCache', {
get: cold('c-', {
c: {response: {isSuccessful},
timeAdded: timestampResponse}
})
});
}
function initTestService(): TestService {
return new TestService(
responseCache,
requestService,
store,
halService
);
}
beforeEach(() => {
store = new MockStore<CoreState>({} as CoreState);
responseCache = initMockResponseCacheService(true);
requestService = getMockRequestService();
rdbService = getMockRemoteDataBuildService();
scheduler = getTestScheduler();
halService = new HALEndpointServiceStub(resourceEndpointURL);
service = initTestService();
spyOn((service as any).store, 'select').and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType]));
spyOn((service as any).store, 'dispatch').and.callThrough();
spyOn(Date.prototype, 'getTime').and.callFake(() => {
return timestamp;
});
});
describe('jsonPatchByResourceType', () => {
it('should call submitJsonPatchOperations method', () => {
spyOn((service as any), 'submitJsonPatchOperations').and.callThrough();
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpointURL, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush();
expect((service as any).submitJsonPatchOperations).toHaveBeenCalled();
});
it('should configure a new SubmissionPatchRequest', () => {
const expected = new SubmissionPatchRequest(requestService.generateRequestId(), resourceHref, patchOpBody);
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected, true);
});
it('should dispatch a new StartTransactionPatchOperationsAction', () => {
const expectedAction = new StartTransactionPatchOperationsAction(testJsonPatchResourceType, undefined, timestamp)
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction);
});
describe('when request is successful', () => {
it('should dispatch a new CommitPatchOperationsAction', () => {
const expectedAction = new CommitPatchOperationsAction(testJsonPatchResourceType, undefined)
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction);
});
});
describe('when request is not successful', () => {
beforeEach(() => {
store = new MockStore<CoreState>({} as CoreState);
responseCache = initMockResponseCacheService(false);
requestService = getMockRequestService();
rdbService = getMockRemoteDataBuildService();
scheduler = getTestScheduler();
halService = new HALEndpointServiceStub(resourceEndpointURL);
service = initTestService();
spyOn((service as any).store, 'select').and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType]));
spyOn((service as any).store, 'dispatch').and.callThrough();
});
it('should dispatch a new RollbacktPatchOperationsAction', () => {
const expectedAction = new RollbacktPatchOperationsAction(testJsonPatchResourceType, undefined)
scheduler.schedule(() => service.jsonPatchByResourceType(resourceEndpoint, resourceScope, testJsonPatchResourceType).subscribe());
scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction);
});
});
});
describe('jsonPatchByResourceID', () => {
it('should call submitJsonPatchOperations method', () => {
spyOn((service as any), 'submitJsonPatchOperations').and.callThrough();
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpointURL, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush();
expect((service as any).submitJsonPatchOperations).toHaveBeenCalled();
});
it('should configure a new SubmissionPatchRequest', () => {
const expected = new SubmissionPatchRequest(requestService.generateRequestId(), resourceHref, patchOpBody);
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected, true);
});
it('should dispatch a new StartTransactionPatchOperationsAction', () => {
const expectedAction = new StartTransactionPatchOperationsAction(testJsonPatchResourceType, testJsonPatchResourceId, timestamp)
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction);
});
describe('when request is successful', () => {
it('should dispatch a new CommitPatchOperationsAction', () => {
const expectedAction = new CommitPatchOperationsAction(testJsonPatchResourceType, testJsonPatchResourceId)
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction);
});
});
describe('when request is not successful', () => {
beforeEach(() => {
store = new MockStore<CoreState>({} as CoreState);
responseCache = initMockResponseCacheService(false);
requestService = getMockRequestService();
rdbService = getMockRemoteDataBuildService();
scheduler = getTestScheduler();
halService = new HALEndpointServiceStub(resourceEndpointURL);
service = initTestService();
spyOn((service as any).store, 'select').and.returnValue(observableOf(mockState['json/patch'][testJsonPatchResourceType]));
spyOn((service as any).store, 'dispatch').and.callThrough();
});
it('should dispatch a new RollbacktPatchOperationsAction', () => {
const expectedAction = new RollbacktPatchOperationsAction(testJsonPatchResourceType, testJsonPatchResourceId)
scheduler.schedule(() => service.jsonPatchByResourceID(resourceEndpoint, resourceScope, testJsonPatchResourceType, testJsonPatchResourceId).subscribe());
scheduler.flush();
expect((service as any).store.dispatch).toHaveBeenCalledWith(expectedAction);
});
});
});
});

View File

@@ -13,15 +13,15 @@ export const MOCK_SUBMISSION_CONFIG = {
metadata: [
{
name: 'mainField',
style: 'fa-user'
style: 'fas fa-user'
},
{
name: 'relatedField',
style: 'fa-university'
style: 'fas fa-university'
},
{
name: 'otherRelatedField',
style: 'fa-circle'
style: 'fas fa-circle'
},
{
name: 'default',