Skip to content

Commit d39024a

Browse files
committed
WIP
1 parent e9e76c2 commit d39024a

File tree

7 files changed

+283
-363
lines changed

7 files changed

+283
-363
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Requires a live Camunda 8 instance configured in `demo/.env` (same as `npm start
120120
npm run scenarios:record
121121

122122
# Record a single scenario
123-
npm run scenarios:record:one test/scenarios/service-task-success/scenario.mjs
123+
npm run scenarios:record:single test/scenarios/service-task-success/scenario.mjs
124124

125125
# Review what changed
126126
npm run scenarios:diff
@@ -129,7 +129,7 @@ npm run scenarios:diff
129129
### Adding a new scenario
130130

131131
1. Create a new folder under `test/scenarios/` with a minimal `process.bpmn` and a `scenario.mjs` that exports the scenario definition. Use a unique `processId` and a scoped job type (e.g. `task-testing:<scenario-name>`) to avoid collisions on a shared cluster.
132-
2. Run `npm run scenarios:record:one test/scenarios/<name>/scenario.mjs` to produce the fixture JSON.
132+
2. Run `npm run scenarios:record:single test/scenarios/<name>/scenario.mjs` to produce the fixture JSON.
133133
3. Write a spec in `test/` that uses `replayScenario` / `createReplayApi` to exercise the component with the new fixture.
134134
4. Commit both the `process.bpmn` and the generated JSON fixture.
135135

demo/api.mjs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* Shared Camunda REST API wrapper.
3+
*
4+
* createApi(client) returns an object whose methods mirror the SDK calls used
5+
* by both demo/server.mjs and test/scenarios/run.mjs. Every method returns a
6+
* `{ success: true, response }` or `{ success: false, error }` object so
7+
* callers never need their own try/catch. Recording stays with the caller.
8+
*
9+
* Response-shape helpers are also exported here since they depend only on the
10+
* result structures produced by these methods.
11+
*/
12+
13+
async function safe(promise) {
14+
try {
15+
const response = await promise;
16+
return { success: true, response };
17+
} catch (err) {
18+
return { success: false, error: err.message };
19+
}
20+
}
21+
22+
/**
23+
* @param {import('@camunda8/sdk').CamundaRestClient} client
24+
*/
25+
export function createApi(client) {
26+
return {
27+
28+
/** @param {Array<{ name: string, content: string }>} resources */
29+
deployResources(resources) {
30+
return safe(client.deployResources(resources));
31+
},
32+
33+
/**
34+
* Starts a process instance scoped to a single element, which is also
35+
* used as the TERMINATE_PROCESS_INSTANCE instruction target.
36+
*/
37+
createProcessInstance({ processDefinitionKey, variables = {}, elementId }) {
38+
return safe(client.createProcessInstance({
39+
processDefinitionKey,
40+
variables,
41+
startInstructions: [ { elementId } ],
42+
runtimeInstructions: [
43+
{ type: 'TERMINATE_PROCESS_INSTANCE', afterElementId: elementId }
44+
]
45+
}));
46+
},
47+
48+
searchProcessInstances(processInstanceKey) {
49+
return safe(client.searchProcessInstances({
50+
filter: { processInstanceKey }
51+
}));
52+
},
53+
54+
searchVariables(processInstanceKey) {
55+
return safe(client.searchVariables({
56+
filter: { processInstanceKey }
57+
}));
58+
},
59+
60+
searchJobs(processInstanceKey, elementId) {
61+
return safe(client.callApiEndpoint({
62+
urlPath: 'jobs/search',
63+
method: 'POST',
64+
body: {
65+
filter: {
66+
processInstanceKey,
67+
...(elementId && { elementId })
68+
}
69+
}
70+
}));
71+
},
72+
73+
searchUserTasks(processInstanceKey, elementId) {
74+
return safe(client.searchUserTasks({
75+
filter: {
76+
processInstanceKey,
77+
...(elementId && { elementId })
78+
}
79+
}));
80+
},
81+
82+
searchMessageSubscriptions(processInstanceKey, elementId) {
83+
return safe(client.callApiEndpoint({
84+
urlPath: 'message-subscriptions/search',
85+
method: 'POST',
86+
body: {
87+
filter: {
88+
processInstanceKey,
89+
...(elementId && { elementId })
90+
}
91+
}
92+
}));
93+
},
94+
95+
searchElementInstances(processInstanceKey) {
96+
return safe(client.searchElementInstances({
97+
filter: { processInstanceKey }
98+
}));
99+
},
100+
101+
searchIncidents(processInstanceKey) {
102+
return safe(client.searchIncidents({
103+
filter: { processInstanceKey }
104+
}));
105+
}
106+
};
107+
}
108+
109+
// ---------------------------------------------------------------------------
110+
// Response-shape helpers
111+
// ---------------------------------------------------------------------------
112+
113+
export function getProcessDefinitionKey(deployResponse, processId) {
114+
const items = deployResponse && (deployResponse.deployments || deployResponse.processes || []);
115+
for (const item of items) {
116+
const def = item.processDefinition || item;
117+
if (def.processDefinitionId === processId) {
118+
return def.processDefinitionKey;
119+
}
120+
}
121+
return null;
122+
}
123+
124+
export function getProcessInstanceKey(startResponse) {
125+
if (!startResponse) return null;
126+
return String(
127+
startResponse.processInstanceKey ||
128+
(startResponse.items && startResponse.items[0] && startResponse.items[0].processInstanceKey) ||
129+
''
130+
) || null;
131+
}
132+
133+
export function getProcessInstanceState(piResult) {
134+
const items = piResult && piResult.response && piResult.response.items;
135+
return items && items[0] && items[0].state;
136+
}
137+
138+
export function hasProcessInstanceIncident(piResult) {
139+
const items = piResult && piResult.response && piResult.response.items;
140+
return !!(items && items[0] && items[0].hasIncident);
141+
}

0 commit comments

Comments
 (0)