Skip to content

Commit

Permalink
AAE-24371 Fix invalid endpoint is called when process with form is st… (
Browse files Browse the repository at this point in the history
#10052)

* AAE-24371 Fix invalid endpoint is called when process with form is started

* AAE-24371 Unit tests

* AAE-24371 update tests to remove subscription
  • Loading branch information
kathrine0 authored Aug 7, 2024
1 parent f88ff10 commit d38e782
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
fakeStartForm,
fakeStartFormNotValid,
fakeProcessInstance,
fakeProcessWithFormInstance,
fakeNoNameProcessDefinitions,
fakeSingleProcessDefinition,
fakeSingleProcessDefinitionWithoutForm,
Expand All @@ -43,6 +44,7 @@ import {
} from '../mock/start-process.component.mock';
import { By } from '@angular/platform-browser';
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
import { ProcessWithFormPayloadCloud } from '../models/process-with-form-payload-cloud.model';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { ProcessNameCloudPipe } from '../../../pipes/process-name-cloud.pipe';
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
Expand All @@ -62,6 +64,7 @@ describe('StartProcessCloudComponent', () => {
let formCloudService: FormCloudService;
let getDefinitionsSpy: jasmine.Spy;
let startProcessSpy: jasmine.Spy;
let startProcessWithFormSpy: jasmine.Spy;
let formDefinitionSpy: jasmine.Spy;
let getStartEventFormStaticValuesMappingSpy: jasmine.Spy;

Expand Down Expand Up @@ -107,6 +110,7 @@ describe('StartProcessCloudComponent', () => {
formDefinitionSpy = spyOn(formCloudService, 'getForm');
spyOn(processService, 'updateProcess').and.returnValue(of());
startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(fakeProcessInstance));
startProcessWithFormSpy = spyOn(processService, 'startProcessWithForm').and.returnValue(of(fakeProcessWithFormInstance));
getStartEventFormStaticValuesMappingSpy = spyOn(processService, 'getStartEventFormStaticValuesMapping').and.returnValue(of([]));
loader = TestbedHarnessEnvironment.loader(fixture);
});
Expand Down Expand Up @@ -716,16 +720,22 @@ describe('StartProcessCloudComponent', () => {
expect(component.hasForm).toBeTruthy();
expect(processForm).not.toBeNull();

const payload: ProcessPayloadCloud = new ProcessPayloadCloud({
name: component.processInstanceName.value,
const payload: ProcessWithFormPayloadCloud = new ProcessWithFormPayloadCloud({
processName: component.processInstanceName.value,
processDefinitionKey: fakeProcessDefinitions[2].key,
variables: Object.assign({}, component.formCloud.values)
variables: {},
values: component.formCloud.values
});
const startButton = fixture.debugElement.query(By.css('#button-start'));
expect(startButton).not.toBeNull();

startButton.triggerEventHandler('click', null);
expect(startProcessSpy).toHaveBeenCalledWith(component.appName, payload);
expect(startProcessWithFormSpy).toHaveBeenCalledWith(
component.appName,
component.processDefinitionCurrent.formKey,
component.processDefinitionCurrent.version,
payload
);
});

it('should output start event when process started successfully', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ import {
import { ContentLinkModel, FORM_FIELD_VALIDATORS, FormFieldValidator, FormModel } from '@alfresco/adf-core';
import { AbstractControl, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { TaskVariableCloud } from '../../../form/models/task-variable-cloud.model';
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
import { ProcessNameCloudPipe } from '../../../pipes/process-name-cloud.pipe';
import { ProcessInstanceCloud } from '../models/process-instance-cloud.model';
import { ProcessPayloadCloud } from '../models/process-payload-cloud.model';
import { ProcessWithFormPayloadCloud } from '../models/process-with-form-payload-cloud.model';
import { StartProcessCloudService } from '../services/start-process-cloud.service';
import { Subject } from 'rxjs';
import { ProcessDefinitionCloud } from '../../../models/process-definition-cloud.model';
import { TaskVariableCloud } from '../../../form/models/task-variable-cloud.model';
import { ProcessNameCloudPipe } from '../../../pipes/process-name-cloud.pipe';

const MAX_NAME_LENGTH: number = 255;
const PROCESS_DEFINITION_DEBOUNCE: number = 300;
Expand Down Expand Up @@ -330,29 +331,39 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy

startProcess() {
this.isProcessStarting = true;
let payloadVariables = {};
if (this.variables) {
payloadVariables = this.variables;
}
if (this.hasForm) {
payloadVariables = Object.assign(payloadVariables, this.formCloud.values);
}
const createPayload = new ProcessPayloadCloud({
name: this.processInstanceName.value,
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
variables: payloadVariables
});
this.startProcessCloudService.startProcess(this.appName, createPayload).subscribe(
(res) => {

const action = this.hasForm
? this.startProcessCloudService.startProcessWithForm(
this.appName,
this.processDefinitionCurrent.formKey,
this.processDefinitionCurrent.version,
new ProcessWithFormPayloadCloud({
processName: this.processInstanceName.value,
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
variables: this.variables ?? {},
values: this.formCloud.values
})
)
: this.startProcessCloudService.startProcess(
this.appName,
new ProcessPayloadCloud({
name: this.processInstanceName.value,
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
variables: this.variables ?? {}
})
);

action.subscribe({
next: (res) => {
this.success.emit(res);
this.isProcessStarting = false;
},
(err) => {
error: (err) => {
this.errorMessageId = 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.START';
this.error.emit(err);
this.isProcessStarting = false;
}
);
});
}

cancelStartProcess() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ export const fakeProcessInstance: ProcessInstanceCloud = {
processDefinitionKey: 'BasicProcess'
};

export const fakeProcessWithFormInstance: ProcessInstanceCloud = {
appName: 'simple-app',
appVersion: '1',
serviceName: 'rb',
serviceFullName: 'rb',
serviceType: 'runtime-bundle',
serviceVersion: '',
id: '9a846781-53e1-11ef-8e97-7a3367d98fa2',
name: 'My Process With Form Name',
startDate: new Date('2024-08-06T10:49:49.689+0000'),
initiator: 'usermock',
status: 'RUNNING',
processDefinitionId: 'Process_TwzKUfeG:1:5518ac74-53de-11ef-8e97-7a3367d98fa2',
processDefinitionKey: 'Process_TwzKUfeG',
processDefinitionName: 'my-process'
};

export const fakeCreatedProcessInstance: ProcessInstanceCloud = {
appName: 'simple-app',
id: 'd0b30377-dc5a-11e8-ae24-0a58646001fa',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export class ProcessWithFormPayloadCloud {
processName: string;
processDefinitionKey: string;
variables: any;
values: any;

constructor(obj: ProcessWithFormPayloadCloud) {
this.processName = obj.processName;
this.processDefinitionKey = obj.processDefinitionKey;
this.variables = obj.variables;
this.values = obj.values;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { HttpErrorResponse, HttpClientModule } from '@angular/common/http';
import { AdfHttpClient } from '@alfresco/adf-core/api';

describe('StartProcessCloudService', () => {

let service: StartProcessCloudService;
let adfHttpClient: AdfHttpClient;

Expand All @@ -36,91 +35,94 @@ describe('StartProcessCloudService', () => {
adfHttpClient = TestBed.inject(AdfHttpClient);
});

it('should be able to create a new process', (done) => {
it('should be able to create a new process', async () => {
spyOn(service, 'startProcess').and.returnValue(of({ id: 'fake-id', name: 'fake-name' }));
service.startProcess('appName1', fakeProcessPayload)
.subscribe(
(res) => {
expect(res).toBeDefined();
expect(res.id).toEqual('fake-id');
expect(res.name).toEqual('fake-name');
done();
}
);
const result = await service.startProcess('appName1', fakeProcessPayload).toPromise();

expect(result).toBeDefined();
expect(result.id).toEqual('fake-id');
expect(result.name).toEqual('fake-name');
});

it('should be able to create a new process with form', async () => {
spyOn(service, 'startProcessWithForm').and.returnValue(of({ id: 'fake-id', name: 'fake-name' }));
const result = await service.startProcessWithForm('appName1', 'mockFormId', 1, fakeProcessPayload).toPromise();

expect(result).toBeDefined();
expect(result.id).toEqual('fake-id');
expect(result.name).toEqual('fake-name');
});

it('Should not be able to create a process if error occurred', () => {
it('Should not be able to create a process if error occurred', async () => {
const errorResponse = new HttpErrorResponse({
error: 'Mock Error',
status: 404, statusText: 'Not Found'
status: 404,
statusText: 'Not Found'
});

spyOn(service, 'startProcess').and.returnValue(throwError(errorResponse));
service.startProcess('appName1', fakeProcessPayload)
.subscribe(
() => {
fail('expected an error, not applications');
},
(error) => {
expect(error.status).toEqual(404);
expect(error.statusText).toEqual('Not Found');
expect(error.error).toEqual('Mock Error');
}
);
const result = await service
.startProcess('appName1', fakeProcessPayload)
.toPromise()
.catch((error) => {
expect(error.status).toEqual(404);
expect(error.statusText).toEqual('Not Found');
expect(error.error).toEqual('Mock Error');
});

if (result) {
fail('expected an error, not applications');
}
});

it('should be able to get all the process definitions', (done) => {
it('should be able to get all the process definitions', async () => {
spyOn(service, 'getProcessDefinitions').and.returnValue(of([new ProcessDefinitionCloud({ id: 'fake-id', name: 'fake-name' })]));
service.getProcessDefinitions('appName1')
.subscribe(
(res: ProcessDefinitionCloud[]) => {
expect(res).toBeDefined();
expect(res[0].id).toEqual('fake-id');
expect(res[0].name).toEqual('fake-name');
done();
}
);
const result = await service.getProcessDefinitions('appName1').toPromise();

expect(result).toBeDefined();
expect(result[0].id).toEqual('fake-id');
expect(result[0].name).toEqual('fake-name');
});

it('should not be able to get all the process definitions if error occurred', () => {
it('should not be able to get all the process definitions if error occurred', async () => {
const errorResponse = new HttpErrorResponse({
error: 'Mock Error',
status: 404, statusText: 'Not Found'
status: 404,
statusText: 'Not Found'
});
spyOn(service, 'getProcessDefinitions').and.returnValue(throwError(errorResponse));
service.getProcessDefinitions('appName1')
.subscribe(
() => {
fail('expected an error, not applications');
},
(error) => {
expect(error.status).toEqual(404);
expect(error.statusText).toEqual('Not Found');
expect(error.error).toEqual('Mock Error');
}
);
const result = await service
.getProcessDefinitions('appName1')
.toPromise()
.catch((error) => {
expect(error.status).toEqual(404);
expect(error.statusText).toEqual('Not Found');
expect(error.error).toEqual('Mock Error');
});

if (result) {
fail('expected an error, not applications');
}
});

it('should transform the response into task variables', (done) => {
it('should transform the response into task variables', async () => {
const appName = 'test-app';
const processDefinitionId = 'processDefinitionId';
const requestSpy = spyOn(adfHttpClient, 'request');
requestSpy.and.returnValue(Promise.resolve({ static1: 'value', static2: 0, static3: true }));

service.getStartEventFormStaticValuesMapping(appName, processDefinitionId).subscribe((result) => {
expect(result.length).toEqual(3);
expect(result[0].name).toEqual('static1');
expect(result[0].id).toEqual('static1');
expect(result[0].value).toEqual('value');
expect(result[1].name).toEqual('static2');
expect(result[1].id).toEqual('static2');
expect(result[1].value).toEqual(0);
expect(result[2].name).toEqual('static3');
expect(result[2].id).toEqual('static3');
expect(result[2].value).toEqual(true);
expect(requestSpy.calls.mostRecent().args[0]).toContain(`${appName}/rb/v1/process-definitions/${processDefinitionId}/static-values`);
expect(requestSpy.calls.mostRecent().args[1].httpMethod).toBe('GET');
done();
});
const result = await service.getStartEventFormStaticValuesMapping(appName, processDefinitionId).toPromise();
expect(result.length).toEqual(3);
expect(result[0].name).toEqual('static1');
expect(result[0].id).toEqual('static1');
expect(result[0].value).toEqual('value');
expect(result[1].name).toEqual('static2');
expect(result[1].id).toEqual('static2');
expect(result[1].value).toEqual(0);
expect(result[2].name).toEqual('static3');
expect(result[2].id).toEqual('static3');
expect(result[2].value).toEqual(true);
expect(requestSpy.calls.mostRecent().args[0]).toContain(`${appName}/rb/v1/process-definitions/${processDefinitionId}/static-values`);
expect(requestSpy.calls.mostRecent().args[1].httpMethod).toBe('GET');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ export class StartProcessCloudService extends BaseCloudService {
return this.post(url, payload).pipe(map((result: any) => result.entry));
}

startProcessWithForm(appName: string, formId: string, version: number, payload: any): Observable<ProcessInstanceCloud> {
const url = `${this.getBasePath(appName)}/form/v1/forms/${formId}/submit/versions/${version}`;
payload.payloadType = 'StartProcessPayload';

return this.post(url, payload);
}

/**
* Update an existing process instance
*
Expand Down

0 comments on commit d38e782

Please sign in to comment.