Skip to content

Commit 3983b45

Browse files
feat: simplify error handling and add test coverage
1 parent 8fafcea commit 3983b45

File tree

9 files changed

+754
-79
lines changed

9 files changed

+754
-79
lines changed

demo/server.mjs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ app.post('/api/deploy', async (req, res) => {
6363
} catch (err) {
6464
console.error('Deployment error:', err);
6565

66-
res.status(500).json({ error: err.message });
66+
res.status(500).json({ success: false, error: err.message });
6767
}
6868
});
6969

@@ -95,7 +95,7 @@ app.post('/api/startInstance', async (req, res) => {
9595

9696
res.json({ success: true, response });
9797
} catch (err) {
98-
res.status(500).json({ error: err.message });
98+
res.status(500).json({ success: false, error: err.message });
9999
}
100100
});
101101

@@ -117,7 +117,7 @@ app.get('/api/getProcessInstance/:processInstanceKey', async (req, res) => {
117117

118118
res.json({ success: true, response });
119119
} catch (err) {
120-
res.status(500).json({ error: err.message });
120+
res.status(500).json({ success: false, error: err.message });
121121
}
122122
});
123123

@@ -139,7 +139,7 @@ app.get('/api/getProcessInstanceVariables/:processInstanceKey', async (req, res)
139139

140140
res.json({ success: true, response });
141141
} catch (err) {
142-
res.status(500).json({ error: err.message });
142+
res.status(500).json({ success: false, error: err.message });
143143
}
144144
});
145145

@@ -161,7 +161,7 @@ app.get('/api/getProcessInstanceIncident/:processInstanceKey', async (req, res)
161161

162162
res.json({ success: true, response });
163163
} catch (err) {
164-
res.status(500).json({ error: err.message });
164+
res.status(500).json({ success: false, error: err.message });
165165
}
166166
});
167167

lib/TaskExecution.js

Lines changed: 71 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -126,92 +126,75 @@ export default class TaskExecution extends EventEmitter {
126126
/** @type {import('./types').TaskExecutionEvents.Start} */
127127
this.emit('taskExecution.start');
128128

129-
const deploymentResponse = await this._api.deploy();
129+
const deploymentResult = await this._api.deploy();
130130

131-
if (!deploymentResponse.success) {
132-
133-
/** @type {import('./types').TaskExecutionEvents.Error} */
134-
this.emit('taskExecution.error', {
135-
message: 'Failed to deploy process definition',
136-
response: deploymentResponse
137-
});
131+
if (!deploymentResult.success) {
132+
this.emitError('Failed to deploy process definition', deploymentResult.error);
138133

139134
await this.cancelTaskExecution();
140135

141136
return;
142137
}
143138

144-
const processId = getProcessId(deploymentResponse.response);
139+
const processId = getProcessId(deploymentResult.response);
145140

146141
if (!processId) {
147-
148-
/** @type {import('./types').TaskExecutionEvents.Error} */
149-
this.emit('taskExecution.error', {
150-
message: 'Failed to retrieve process ID from deployment response',
151-
response: deploymentResponse
152-
});
142+
this.emitError('Failed to retrieve process ID from deployment response');
153143

154144
await this.cancelTaskExecution();
155145

156146
return;
157147
}
158148

159-
this._currentTaskExecution.processDefinitionKey = getProcessDefinitionKey(deploymentResponse.response);
160-
161-
const startInstanceResponse = await this._api.startInstance(processId, elementId, variables);
149+
this._currentTaskExecution.processDefinitionKey = getProcessDefinitionKey(deploymentResult.response);
162150

163-
if (!startInstanceResponse.success) {
151+
const startInstanceResult = await this._api.startInstance(processId, elementId, variables);
164152

165-
/** @type {import('./types').TaskExecutionEvents.Error} */
166-
this.emit('taskExecution.error', {
167-
message: 'Failed to start process instance',
168-
response: startInstanceResponse
169-
});
153+
if (!startInstanceResult.success) {
154+
this.emitError('Failed to start process instance', startInstanceResult.error);
170155

171156
await this.cancelTaskExecution();
172157

173158
return;
174159
}
175160

176-
const { processInstanceKey } = startInstanceResponse.response;
161+
const processInstanceKey = getProcessInstanceKey(startInstanceResult.response);
162+
163+
if (!processInstanceKey) {
164+
this.emitError('Failed to retrieve process instance key from start instance response');
165+
166+
await this.cancelTaskExecution();
167+
168+
return;
169+
}
177170

178171
this._currentTaskExecution.processInstanceKey = processInstanceKey;
179172

180173
const intervalCallback = async () => {
181174
const getProcessInstanceResult = await this._api.getProcessInstance(processInstanceKey);
182175

183176
if (!getProcessInstanceResult.success) {
184-
185-
/** @type {import('./types').TaskExecutionEvents.Error} */
186-
this.emit('taskExecution.error', {
187-
message: 'Failed to get process instance',
188-
response: getProcessInstanceResult
189-
});
177+
this.emitError('Failed to get process instance', getProcessInstanceResult.error);
190178

191179
return;
192180
}
193181

194-
const processInstance = getProcessInstance(getProcessInstanceResult.response);
182+
const processInstance = getProcessInstance(getProcessInstanceResult.response, processInstanceKey);
195183

196184
if (!processInstance) {
197185

198186
// No process instance found, try again
199187
return;
200188
}
201189

202-
const state = getProcessInstanceState(getProcessInstanceResult.response),
203-
hasIncident = hasProcessInstanceIncident(getProcessInstanceResult.response);
190+
const state = getProcessInstanceState(getProcessInstanceResult.response, processInstanceKey),
191+
hasIncident = hasProcessInstanceIncident(getProcessInstanceResult.response, processInstanceKey);
204192

205193
if (hasIncident) {
206194
const getProcessInstanceIncidentResult = await this._api.getProcessInstanceIncident(processInstanceKey);
207195

208196
if (!getProcessInstanceIncidentResult.success) {
209-
210-
/** @type {import('./types').TaskExecutionEvents.Error} */
211-
this.emit('taskExecution.error', {
212-
message: 'Failed to get process instance incident',
213-
response: getProcessInstanceIncidentResult
214-
});
197+
this.emitError('Failed to get process instance incident', getProcessInstanceIncidentResult.error);
215198

216199
return;
217200
}
@@ -231,10 +214,7 @@ export default class TaskExecution extends EventEmitter {
231214
const getProcessInstanceVariablesResult = await this._api.getProcessInstanceVariables(processInstanceKey);
232215

233216
if (!getProcessInstanceVariablesResult.success) {
234-
this.emit('taskExecution.error', {
235-
message: 'Failed to get process instance variables',
236-
response: getProcessInstanceVariablesResult
237-
});
217+
this.emitError('Failed to get process instance variables', getProcessInstanceVariablesResult.error);
238218
} else {
239219
if (this._currentTaskExecution) {
240220
this._currentTaskExecution.variables = getVariables(getProcessInstanceVariablesResult.response);
@@ -247,16 +227,29 @@ export default class TaskExecution extends EventEmitter {
247227

248228
this._currentTaskExecution.interval = setInterval(intervalCallback, INTERVAL_MS);
249229
}
230+
231+
emitError(message, detail) {
232+
233+
/** @type {import('./types').TaskExecutionEvents.Error} */
234+
this.emit('taskExecution.error', {
235+
message,
236+
detail
237+
});
238+
}
250239
}
251240

252241
/**
253242
* Get the process ID from the deployment response.
254243
*
255-
* @param {import('./types').DeploymentResponse} response
244+
* @param {import('./types').DeploymentResponse} [response]
256245
*
257246
* @returns {string|null} The process ID or null if not found.
258247
*/
259248
function getProcessId(response) {
249+
if (!response) {
250+
return null;
251+
}
252+
260253
const { processes = [] } = response;
261254

262255
for (const process of processes) {
@@ -271,11 +264,15 @@ function getProcessId(response) {
271264
/**
272265
* Get the process definition key from the deployment response.
273266
*
274-
* @param {import('./types').DeploymentResponse} response
267+
* @param {import('./types').DeploymentResponse} [response]
275268
*
276269
* @returns {string|null} The process definition key or null if not found.
277270
*/
278271
function getProcessDefinitionKey(response) {
272+
if (!response) {
273+
return null;
274+
}
275+
279276
const { processes = [] } = response;
280277

281278
for (const process of processes) {
@@ -287,18 +284,35 @@ function getProcessDefinitionKey(response) {
287284
return null;
288285
}
289286

290-
function getProcessInstance(response) {
287+
/**
288+
* Get the process instance key from the response.
289+
*
290+
* @param {import('./types').StartInstanceResponse} [response]
291+
*
292+
* @returns {string|null} The process instance key or null if not found.
293+
*/
294+
function getProcessInstanceKey(response) {
295+
if (!response) {
296+
return null;
297+
}
298+
299+
const { processInstanceKey } = response;
300+
301+
return processInstanceKey || null;
302+
}
303+
304+
function getProcessInstance(response, processInstanceKey) {
291305
const { items = [] } = response;
292306

293307
if (!items.length) {
294308
return null;
295309
}
296310

297-
return items[0];
311+
return items.find(item => item.processInstanceKey === processInstanceKey) || null;
298312
}
299313

300-
function getProcessInstanceState(response) {
301-
const processInstance = getProcessInstance(response);
314+
function getProcessInstanceState(response, processInstanceKey) {
315+
const processInstance = getProcessInstance(response, processInstanceKey);
302316

303317
if (!processInstance) {
304318
return null;
@@ -307,8 +321,8 @@ function getProcessInstanceState(response) {
307321
return processInstance.state;
308322
}
309323

310-
function hasProcessInstanceIncident(response) {
311-
const processInstance = getProcessInstance(response);
324+
function hasProcessInstanceIncident(response, processInstanceKey) {
325+
const processInstance = getProcessInstance(response, processInstanceKey);
312326

313327
if (!processInstance) {
314328
return false;
@@ -325,7 +339,11 @@ function getVariables(response) {
325339
for (const item of items) {
326340
const { name, value } = item;
327341

328-
variables[name] = JSON.parse(value);
342+
try {
343+
variables[name] = JSON.parse(value);
344+
} catch {
345+
variables[name] = value;
346+
}
329347
}
330348

331349
return variables;

lib/components/Output/Output.jsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ function Error({
180180
maxCollapsedNumberOfRows={ 100 }
181181
align="left"
182182
>
183-
{ printError(incident) }
183+
{ printIncident(incident) }
184184
</CodeSnippet>
185185
}
186186
{
@@ -191,17 +191,24 @@ function Error({
191191
maxCollapsedNumberOfRows={ 100 }
192192
align="left"
193193
>
194-
{ printError(error) }
194+
{ error.detail || 'No error details available' }
195195
</CodeSnippet>
196196
}
197197
</>;
198198
}
199199

200-
function printError(error) {
200+
/**
201+
* Print the details of an incident.
202+
*
203+
* @param {Object} incident
204+
*
205+
* @returns {string}
206+
*/
207+
function printIncident(incident) {
201208
let text = '';
202209

203-
Object.keys(error).forEach((key) => {
204-
text += `${capitalize(key)}: ${JSON.stringify(error[key], null, 2)}\n`;
210+
Object.keys(incident).forEach((key) => {
211+
text += `${capitalize(key)}: ${JSON.stringify(incident[key], null, 2)}\n`;
205212
});
206213

207214
return text;

lib/components/TaskTesting/TaskTesting.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export default function TaskTesting({
155155

156156
taskExecutionRef.current.on('taskExecution.start', handleTaskExecutionStart);
157157

158-
const handleTaskExecutionError = ({ message, response }) => {
158+
const handleTaskExecutionError = ({ message, detail }) => {
159159
setIsTaskExecuting(false);
160160

161161
if (!element || !elementConfigRef.current) {
@@ -166,7 +166,7 @@ export default function TaskTesting({
166166
success: false,
167167
error: {
168168
message,
169-
response
169+
detail
170170
}
171171
});
172172
};

lib/types.d.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,34 @@ export type DeploymentResponse = DeployResourceResponse;
3939

4040
export type DeploymentResult = {
4141
success: boolean;
42-
response: DeploymentResponse;
42+
response?: DeploymentResponse;
43+
error?: string;
4344
}
4445

4546
export type StartInstanceResponse = CreateProcessInstanceResponse;
4647

4748
export type StartInstanceResult = {
4849
success: boolean;
49-
response: StartInstanceResponse;
50+
response?: StartInstanceResponse;
51+
error?: string;
5052
}
5153

5254
export type GetProcessInstanceResult = {
5355
success: boolean;
54-
response: SearchProcessInstanceResponse;
56+
response?: SearchProcessInstanceResponse;
57+
error?: string;
5558
}
5659

5760
export type GetProcessInstanceVariablesResult = {
5861
success: boolean;
59-
response: SearchVariablesResponse;
62+
response?: SearchVariablesResponse;
63+
error?: string;
6064
}
6165

6266
export type GetProcessInstanceIncidentResult = {
6367
success: boolean;
64-
response: SearchIncidentsResponse;
68+
response?: SearchIncidentsResponse;
69+
error?: string;
6570
}
6671

6772
export type TaskExecutionApi = {

0 commit comments

Comments
 (0)