From d38e782fe34c64ae6666d89eca467ff1ee629061 Mon Sep 17 00:00:00 2001 From: Kasia Biernat <1268696+kathrine0@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:26:47 +0200 Subject: [PATCH] =?UTF-8?q?AAE-24371=20Fix=20invalid=20endpoint=20is=20cal?= =?UTF-8?q?led=20when=20process=20with=20form=20is=20st=E2=80=A6=20(#10052?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * AAE-24371 Fix invalid endpoint is called when process with form is started * AAE-24371 Unit tests * AAE-24371 update tests to remove subscription --- .../start-process-cloud.component.spec.ts | 18 ++- .../start-process-cloud.component.ts | 51 ++++--- .../mock/start-process.component.mock.ts | 17 +++ .../process-with-form-payload-cloud.model.ts | 30 ++++ .../start-process-cloud.service.spec.ts | 128 +++++++++--------- .../services/start-process-cloud.service.ts | 7 + 6 files changed, 164 insertions(+), 87 deletions(-) create mode 100755 lib/process-services-cloud/src/lib/process/start-process/models/process-with-form-payload-cloud.model.ts diff --git a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts index 5df1703b823..1866049f3a8 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts @@ -35,6 +35,7 @@ import { fakeStartForm, fakeStartFormNotValid, fakeProcessInstance, + fakeProcessWithFormInstance, fakeNoNameProcessDefinitions, fakeSingleProcessDefinition, fakeSingleProcessDefinitionWithoutForm, @@ -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'; @@ -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; @@ -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); }); @@ -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', () => { diff --git a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts index 34d87e6ab67..ae701c20d47 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.ts @@ -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; @@ -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() { diff --git a/lib/process-services-cloud/src/lib/process/start-process/mock/start-process.component.mock.ts b/lib/process-services-cloud/src/lib/process/start-process/mock/start-process.component.mock.ts index 7d931eaaa97..8691861820f 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/mock/start-process.component.mock.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/mock/start-process.component.mock.ts @@ -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', diff --git a/lib/process-services-cloud/src/lib/process/start-process/models/process-with-form-payload-cloud.model.ts b/lib/process-services-cloud/src/lib/process/start-process/models/process-with-form-payload-cloud.model.ts new file mode 100755 index 00000000000..eadb0008afd --- /dev/null +++ b/lib/process-services-cloud/src/lib/process/start-process/models/process-with-form-payload-cloud.model.ts @@ -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; + } +} diff --git a/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.spec.ts index c02bab27bd8..f10b6027475 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.spec.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.spec.ts @@ -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; @@ -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'); }); }); diff --git a/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.ts b/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.ts index ce9b0cbe15e..d847f99e39f 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/services/start-process-cloud.service.ts @@ -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 { + 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 *