@camunda/e2e-test-suite 0.0.1241 → 0.0.1243

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/fixtures/api.d.ts +15 -0
  2. package/dist/fixtures/api.js +27 -0
  3. package/dist/pages/SM-8.10/NavigationPage.d.ts +3 -2
  4. package/dist/pages/SM-8.10/NavigationPage.js +24 -34
  5. package/dist/pages/SM-8.10/ProcessApplicationPage.js +7 -0
  6. package/dist/tests/api/v2/authorization/authorization-api-tests.spec.d.ts +1 -0
  7. package/dist/tests/api/v2/authorization/authorization-api-tests.spec.js +247 -0
  8. package/dist/tests/api/v2/authorization/authorization-enforcement-api-tests.spec.d.ts +18 -0
  9. package/dist/tests/api/v2/authorization/authorization-enforcement-api-tests.spec.js +208 -0
  10. package/dist/tests/api/v2/batch-operation/batch-operation-api-tests.spec.d.ts +1 -0
  11. package/dist/tests/api/v2/batch-operation/batch-operation-api-tests.spec.js +264 -0
  12. package/dist/tests/api/v2/cluster/cluster-api-tests.spec.d.ts +1 -0
  13. package/dist/tests/api/v2/cluster/cluster-api-tests.spec.js +86 -0
  14. package/dist/tests/api/v2/decision/decision-api-tests.spec.d.ts +1 -0
  15. package/dist/tests/api/v2/decision/decision-api-tests.spec.js +233 -0
  16. package/dist/tests/api/v2/deployment/deployment-api-tests.spec.d.ts +1 -0
  17. package/dist/tests/api/v2/deployment/deployment-api-tests.spec.js +147 -0
  18. package/dist/tests/api/v2/document/document-api-tests.spec.d.ts +9 -0
  19. package/dist/tests/api/v2/document/document-api-tests.spec.js +111 -0
  20. package/dist/tests/api/v2/element-instance/element-instance-api-tests.spec.d.ts +1 -0
  21. package/dist/tests/api/v2/element-instance/element-instance-api-tests.spec.js +127 -0
  22. package/dist/tests/api/v2/flows/end-to-end-flows.spec.d.ts +9 -0
  23. package/dist/tests/api/v2/flows/end-to-end-flows.spec.js +204 -0
  24. package/dist/tests/api/v2/form/form-api-tests.spec.d.ts +1 -0
  25. package/dist/tests/api/v2/form/form-api-tests.spec.js +88 -0
  26. package/dist/tests/api/v2/identity/group-api-tests.spec.d.ts +1 -0
  27. package/dist/tests/api/v2/identity/group-api-tests.spec.js +172 -0
  28. package/dist/tests/api/v2/identity/membership-api-tests.spec.d.ts +10 -0
  29. package/dist/tests/api/v2/identity/membership-api-tests.spec.js +164 -0
  30. package/dist/tests/api/v2/identity/role-api-tests.spec.d.ts +1 -0
  31. package/dist/tests/api/v2/identity/role-api-tests.spec.js +212 -0
  32. package/dist/tests/api/v2/identity/tenant-api-tests.spec.d.ts +1 -0
  33. package/dist/tests/api/v2/identity/tenant-api-tests.spec.js +319 -0
  34. package/dist/tests/api/v2/identity/user-api-tests.spec.d.ts +1 -0
  35. package/dist/tests/api/v2/identity/user-api-tests.spec.js +148 -0
  36. package/dist/tests/api/v2/job/job-api-tests.spec.d.ts +1 -0
  37. package/dist/tests/api/v2/job/job-api-tests.spec.js +260 -0
  38. package/dist/tests/api/v2/message/message-api-tests.spec.d.ts +1 -0
  39. package/dist/tests/api/v2/message/message-api-tests.spec.js +219 -0
  40. package/dist/tests/api/v2/process-definition/process-definition-api-tests.spec.d.ts +1 -0
  41. package/dist/tests/api/v2/process-definition/process-definition-api-tests.spec.js +118 -0
  42. package/dist/tests/api/v2/process-instance/process-instance-api-tests.spec.d.ts +1 -0
  43. package/dist/tests/api/v2/process-instance/process-instance-api-tests.spec.js +335 -0
  44. package/dist/tests/api/v2/runtime/batch-modification-api-tests.spec.d.ts +1 -0
  45. package/dist/tests/api/v2/runtime/batch-modification-api-tests.spec.js +123 -0
  46. package/dist/tests/api/v2/runtime/variable-incident-api-tests.spec.d.ts +1 -0
  47. package/dist/tests/api/v2/runtime/variable-incident-api-tests.spec.js +174 -0
  48. package/dist/tests/api/v2/system/clock-api-tests.spec.d.ts +19 -0
  49. package/dist/tests/api/v2/system/clock-api-tests.spec.js +62 -0
  50. package/dist/tests/api/v2/system/system-api-tests.spec.d.ts +1 -0
  51. package/dist/tests/api/v2/system/system-api-tests.spec.js +183 -0
  52. package/dist/tests/api/v2/user-task/user-task-api-tests.spec.d.ts +1 -0
  53. package/dist/tests/api/v2/user-task/user-task-api-tests.spec.js +258 -0
  54. package/dist/utils/api/assertions.d.ts +50 -0
  55. package/dist/utils/api/assertions.js +142 -0
  56. package/dist/utils/api/auth.d.ts +27 -0
  57. package/dist/utils/api/auth.js +137 -0
  58. package/dist/utils/api/beans.d.ts +46 -0
  59. package/dist/utils/api/beans.js +87 -0
  60. package/dist/utils/api/bpmn.d.ts +50 -0
  61. package/dist/utils/api/bpmn.js +217 -0
  62. package/dist/utils/api/capabilities.d.ts +90 -0
  63. package/dist/utils/api/capabilities.js +198 -0
  64. package/dist/utils/api/cleanup.d.ts +24 -0
  65. package/dist/utils/api/cleanup.js +120 -0
  66. package/dist/utils/api/config.d.ts +103 -0
  67. package/dist/utils/api/config.js +62 -0
  68. package/dist/utils/api/deployments.d.ts +45 -0
  69. package/dist/utils/api/deployments.js +120 -0
  70. package/dist/utils/api/eventually.d.ts +36 -0
  71. package/dist/utils/api/eventually.js +54 -0
  72. package/dist/utils/api/http.d.ts +56 -0
  73. package/dist/utils/api/http.js +244 -0
  74. package/dist/utils/api/identity.d.ts +29 -0
  75. package/dist/utils/api/identity.js +43 -0
  76. package/dist/utils/api/keys.d.ts +37 -0
  77. package/dist/utils/api/keys.js +40 -0
  78. package/dist/utils/api/paths.d.ts +25 -0
  79. package/dist/utils/api/paths.js +167 -0
  80. package/dist/utils/api/tenancy.d.ts +31 -0
  81. package/dist/utils/api/tenancy.js +65 -0
  82. package/package.json +1 -1
  83. package/playwright.config.ts +14 -2
  84. package/dist/resources/test-api-v2-complete.sh +0 -12246
  85. package/resources/test-api-v2-complete.sh +0 -12246
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const api_1 = require("../../../../fixtures/api");
4
+ const test_1 = require("@playwright/test");
5
+ const assertions_1 = require("../../../../utils/api/assertions");
6
+ const deployments_1 = require("../../../../utils/api/deployments");
7
+ const bpmn_1 = require("../../../../utils/api/bpmn");
8
+ const eventually_1 = require("../../../../utils/api/eventually");
9
+ const keys_1 = require("../../../../utils/api/keys");
10
+ /**
11
+ * Deploys a decision for one test and tracks it for deletion.
12
+ *
13
+ * Per test rather than once per file: a definition shared through `beforeAll`
14
+ * outlives the test that needs it, so no single test can clean it up and the
15
+ * tests that evaluate it compete for the same instances — this file already
16
+ * carries two comments about a definition-scoped search returning a sibling
17
+ * test's instance. A private decision id per test removes that competition at
18
+ * the source.
19
+ */
20
+ async function deployTestDecision(api, resources, prefix) {
21
+ const decisionId = (0, bpmn_1.uniqueId)(prefix);
22
+ const deployed = await (0, deployments_1.deployDecision)(api, resources, decisionId, (0, bpmn_1.simpleDecision)(decisionId));
23
+ return { decisionId, deployed };
24
+ }
25
+ api_1.test.describe('Decision definitions and instances', () => {
26
+ (0, api_1.test)('finds the deployed decision by id', async ({ api, resources }) => {
27
+ const { decisionId, deployed } = await deployTestDecision(api, resources, 'decision-api');
28
+ await (0, eventually_1.eventually)(async () => {
29
+ const response = await api.post('/decision-definitions/search', {
30
+ body: { filter: { decisionDefinitionId: decisionId } },
31
+ });
32
+ const page = await (0, assertions_1.assertPaginated)(response, { minItems: 1 });
33
+ const item = page.items[0];
34
+ (0, test_1.expect)(String(item.decisionDefinitionKey)).toBe(deployed.decisionDefinitionKey);
35
+ });
36
+ });
37
+ (0, api_1.test)('returns the decision definition by key', async ({ api, resources }) => {
38
+ const { decisionId, deployed } = await deployTestDecision(api, resources, 'decision-api');
39
+ // `x-eventually-consistent: true` — served from secondary storage, so it
40
+ // can 404 briefly after the deployment.
41
+ await (0, eventually_1.eventually)(async () => {
42
+ const response = await api.get('/decision-definitions/{decisionDefinitionKey}', { params: { decisionDefinitionKey: deployed.decisionDefinitionKey } });
43
+ const definition = (await (0, assertions_1.assertOk)(response));
44
+ (0, assertions_1.assertRequiredFields)(definition, [
45
+ 'decisionDefinitionKey',
46
+ 'decisionDefinitionId',
47
+ 'version',
48
+ 'decisionRequirementsKey',
49
+ ]);
50
+ (0, test_1.expect)(definition.decisionDefinitionId).toBe(decisionId);
51
+ });
52
+ });
53
+ (0, api_1.test)('returns the decision XML by key', async ({ api, resources }) => {
54
+ const { decisionId, deployed } = await deployTestDecision(api, resources, 'decision-api');
55
+ await (0, eventually_1.eventually)(async () => {
56
+ const response = await api.get('/decision-definitions/{decisionDefinitionKey}/xml', { params: { decisionDefinitionKey: deployed.decisionDefinitionKey } });
57
+ // assertOk parses the body as JSON; this endpoint returns XML text.
58
+ await (0, assertions_1.assertStatus)(response, 200);
59
+ const xml = await response.text();
60
+ (0, test_1.expect)(xml).toContain(decisionId);
61
+ });
62
+ });
63
+ (0, api_1.test)('evaluates the decision and returns the matching output', async ({ api, resources, }) => {
64
+ const { deployed } = await deployTestDecision(api, resources, 'decision-api');
65
+ const response = await api.post('/decision-definitions/evaluation', {
66
+ body: {
67
+ decisionDefinitionKey: deployed.decisionDefinitionKey,
68
+ variables: { inputVariable: 'match' },
69
+ },
70
+ tenant: 'root',
71
+ });
72
+ const result = (await (0, assertions_1.assertOk)(response));
73
+ (0, assertions_1.assertRequiredFields)(result, [
74
+ 'decisionDefinitionKey',
75
+ 'decisionEvaluationKey',
76
+ 'output',
77
+ ]);
78
+ // The shell suite accepted `200 400 404` here, so a decision that failed
79
+ // to evaluate passed. The rule table maps "match" to "matched", and
80
+ // `output` carries the JSON encoding of the value, not the bare value.
81
+ (0, test_1.expect)(result.output).toBe('"matched"');
82
+ });
83
+ (0, api_1.test)('evaluates the decision to its default rule', async ({ api, resources, }) => {
84
+ const { deployed } = await deployTestDecision(api, resources, 'decision-api');
85
+ const response = await api.post('/decision-definitions/evaluation', {
86
+ body: {
87
+ decisionDefinitionKey: deployed.decisionDefinitionKey,
88
+ variables: { inputVariable: 'anything-else' },
89
+ },
90
+ tenant: 'root',
91
+ });
92
+ const result = (await (0, assertions_1.assertOk)(response));
93
+ (0, test_1.expect)(result.output).toBe('"default"');
94
+ });
95
+ (0, api_1.test)('records an instance for each evaluation', async ({ api, resources }) => {
96
+ const { decisionId, deployed } = await deployTestDecision(api, resources, 'decision-api');
97
+ const evaluation = await api.post('/decision-definitions/evaluation', {
98
+ body: {
99
+ decisionDefinitionKey: deployed.decisionDefinitionKey,
100
+ variables: { inputVariable: 'match' },
101
+ },
102
+ tenant: 'root',
103
+ });
104
+ const evaluated = (await (0, assertions_1.assertOk)(evaluation));
105
+ const evaluationKey = String(evaluated.decisionEvaluationKey);
106
+ // Filtered by the evaluation, not by the definition: this test evaluates
107
+ // once, but a definition-scoped search would be satisfied by whichever
108
+ // instance is exported first, so as soon as a test evaluates twice
109
+ // `items[0]` is whichever evaluation landed first rather than the one
110
+ // under assertion. That is how it failed when the whole file shared one
111
+ // definition — one flake in run 35606946161, where the search returned a
112
+ // sibling test's instance.
113
+ const instances = await (0, eventually_1.eventuallyGet)(async () => {
114
+ const response = await api.post('/decision-instances/search', {
115
+ body: {
116
+ filter: { decisionEvaluationKey: evaluationKey },
117
+ page: { limit: 10 },
118
+ },
119
+ });
120
+ return (await (0, assertions_1.assertPaginated)(response)).items;
121
+ }, (items) => items.length > 0, { description: `decision instance for evaluation ${evaluationKey}` });
122
+ // The single-instance GET is addressed by `decisionEvaluationInstanceKey`
123
+ // — the compound `<decisionEvaluationKey>-<index>` that identifies one
124
+ // decision inside an evaluation, not the plain numeric evaluation key.
125
+ // Passing the numeric key earns a 400 naming the `^\d+-\d+$` pattern.
126
+ const byKey = await api.get('/decision-instances/{decisionEvaluationInstanceKey}', {
127
+ params: {
128
+ decisionEvaluationInstanceKey: String(instances[0].decisionEvaluationInstanceKey),
129
+ },
130
+ });
131
+ const json = (await (0, assertions_1.assertOk)(byKey));
132
+ (0, assertions_1.assertRequiredFields)(json, [
133
+ 'decisionEvaluationInstanceKey',
134
+ 'decisionDefinitionId',
135
+ 'state',
136
+ ]);
137
+ (0, test_1.expect)(json.decisionDefinitionId).toBe(decisionId);
138
+ });
139
+ (0, api_1.test)('exposes the evaluated inputs and outputs of an instance', async ({ api, resources, }) => {
140
+ const { deployed } = await deployTestDecision(api, resources, 'decision-api');
141
+ const evaluation = await api.post('/decision-definitions/evaluation', {
142
+ body: {
143
+ decisionDefinitionKey: deployed.decisionDefinitionKey,
144
+ variables: { inputVariable: 'match' },
145
+ },
146
+ tenant: 'root',
147
+ });
148
+ const evaluated = (await (0, assertions_1.assertOk)(evaluation));
149
+ const evaluationKey = String(evaluated.decisionEvaluationKey);
150
+ // There are no `/evaluated-inputs` and `/evaluated-outputs`
151
+ // sub-resources: the single-instance GET carries `evaluatedInputs` and
152
+ // `matchedRules` inline, and the v2 spec marks both required on it. That
153
+ // also lets this assert the values rather than only that an array came
154
+ // back.
155
+ //
156
+ // The key comes from the search rather than the evaluation response: the
157
+ // GET is addressed by the compound `<evaluationKey>-<index>`, which the
158
+ // evaluation result does not carry. The search is scoped to this
159
+ // evaluation for the same reason as above — a definition-scoped one can
160
+ // return a sibling test's instance, whose input value differs.
161
+ await (0, eventually_1.eventually)(async () => {
162
+ const search = await api.post('/decision-instances/search', {
163
+ body: {
164
+ filter: { decisionEvaluationKey: evaluationKey },
165
+ page: { limit: 1 },
166
+ },
167
+ });
168
+ const page = await (0, assertions_1.assertPaginated)(search, { minItems: 1 });
169
+ const decisionEvaluationInstanceKey = String(page.items[0]
170
+ .decisionEvaluationInstanceKey);
171
+ const response = await api.get('/decision-instances/{decisionEvaluationInstanceKey}', { params: { decisionEvaluationInstanceKey } });
172
+ const json = (await (0, assertions_1.assertOk)(response));
173
+ (0, test_1.expect)(json.evaluatedInputs).toEqual([
174
+ test_1.expect.objectContaining({ inputValue: '"match"' }),
175
+ ]);
176
+ (0, test_1.expect)(json.matchedRules).toEqual([
177
+ test_1.expect.objectContaining({ ruleId: 'rule_match' }),
178
+ ]);
179
+ });
180
+ });
181
+ (0, api_1.test)('rejects evaluating an absent decision', async ({ api }) => {
182
+ const response = await api.post('/decision-definitions/evaluation', {
183
+ body: { decisionDefinitionKey: keys_1.ABSENT_ROUTABLE_KEY, variables: {} },
184
+ tenant: 'root',
185
+ });
186
+ await (0, assertions_1.assertNotFound)(response);
187
+ });
188
+ (0, api_1.test)('rejects a lookup for an absent decision key', async ({ api }) => {
189
+ const response = await api.get('/decision-definitions/{decisionDefinitionKey}', { params: { decisionDefinitionKey: keys_1.ABSENT_KEY } });
190
+ await (0, assertions_1.assertNotFound)(response);
191
+ });
192
+ (0, api_1.test)('rejects a malformed decision key', async ({ api }) => {
193
+ const response = await api.get('/decision-definitions/{decisionDefinitionKey}', { params: { decisionDefinitionKey: 'not-a-key' } });
194
+ await (0, assertions_1.assertBadRequest)(response);
195
+ });
196
+ });
197
+ api_1.test.describe('Decision requirements', () => {
198
+ (0, api_1.test)('returns the requirements definition by key', async ({ api, resources, }) => {
199
+ const { deployed } = await deployTestDecision(api, resources, 'drd-api');
200
+ await (0, eventually_1.eventually)(async () => {
201
+ const response = await api.get('/decision-requirements/{decisionRequirementsKey}', { params: { decisionRequirementsKey: deployed.decisionRequirementsKey } });
202
+ const json = (await (0, assertions_1.assertOk)(response));
203
+ (0, assertions_1.assertRequiredFields)(json, [
204
+ 'decisionRequirementsKey',
205
+ 'decisionRequirementsId',
206
+ 'version',
207
+ ]);
208
+ });
209
+ });
210
+ (0, api_1.test)('returns the requirements XML by key', async ({ api, resources }) => {
211
+ const { decisionId, deployed } = await deployTestDecision(api, resources, 'drd-api');
212
+ await (0, eventually_1.eventually)(async () => {
213
+ const response = await api.get('/decision-requirements/{decisionRequirementsKey}/xml', { params: { decisionRequirementsKey: deployed.decisionRequirementsKey } });
214
+ await (0, assertions_1.assertStatus)(response, 200);
215
+ (0, test_1.expect)(await response.text()).toContain(decisionId);
216
+ });
217
+ });
218
+ (0, api_1.test)('finds the requirements through search', async ({ api, resources }) => {
219
+ const { deployed } = await deployTestDecision(api, resources, 'drd-api');
220
+ await (0, eventually_1.eventually)(async () => {
221
+ const response = await api.post('/decision-requirements/search', {
222
+ body: {
223
+ filter: { decisionRequirementsKey: deployed.decisionRequirementsKey },
224
+ },
225
+ });
226
+ await (0, assertions_1.assertPaginated)(response, { minItems: 1 });
227
+ });
228
+ });
229
+ (0, api_1.test)('rejects a lookup for absent requirements', async ({ api }) => {
230
+ const response = await api.get('/decision-requirements/{decisionRequirementsKey}', { params: { decisionRequirementsKey: keys_1.ABSENT_KEY } });
231
+ await (0, assertions_1.assertNotFound)(response);
232
+ });
233
+ });
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const api_1 = require("../../../../fixtures/api");
4
+ const test_1 = require("@playwright/test");
5
+ const assertions_1 = require("../../../../utils/api/assertions");
6
+ const deployments_1 = require("../../../../utils/api/deployments");
7
+ const bpmn_1 = require("../../../../utils/api/bpmn");
8
+ const eventually_1 = require("../../../../utils/api/eventually");
9
+ const capabilities_1 = require("../../../../utils/api/capabilities");
10
+ const keys_1 = require("../../../../utils/api/keys");
11
+ api_1.test.describe('Deployments', () => {
12
+ (0, api_1.test)('deploys a single process', async ({ api, resources }) => {
13
+ const processId = (0, bpmn_1.uniqueId)('deploy-single');
14
+ const response = await (0, deployments_1.deployResources)(api, resources, [
15
+ { name: `${processId}.bpmn`, content: (0, bpmn_1.emptyProcess)(processId) },
16
+ ]);
17
+ const json = (await (0, assertions_1.assertOk)(response));
18
+ (0, assertions_1.assertRequiredFields)(json, ['deploymentKey', 'deployments']);
19
+ const deployments = json.deployments;
20
+ (0, test_1.expect)(deployments.length).toBe(1);
21
+ const definition = deployments[0].processDefinition;
22
+ // A deployment result carries `processDefinitionVersion`; only the search
23
+ // and get-by-key results call it `version`.
24
+ (0, assertions_1.assertRequiredFields)(definition, [
25
+ 'processDefinitionKey',
26
+ 'processDefinitionId',
27
+ 'processDefinitionVersion',
28
+ 'resourceName',
29
+ ]);
30
+ (0, test_1.expect)(definition.processDefinitionId).toBe(processId);
31
+ (0, test_1.expect)(definition.processDefinitionVersion).toBe(1);
32
+ });
33
+ (0, api_1.test)('deploys several resources in one request', async ({ api, resources }) => {
34
+ const first = (0, bpmn_1.uniqueId)('deploy-multi-a');
35
+ const second = (0, bpmn_1.uniqueId)('deploy-multi-b');
36
+ const response = await (0, deployments_1.deployResources)(api, resources, [
37
+ { name: `${first}.bpmn`, content: (0, bpmn_1.emptyProcess)(first) },
38
+ {
39
+ name: `${second}.bpmn`,
40
+ content: (0, bpmn_1.linearProcess)(second, bpmn_1.element.serviceTask((0, bpmn_1.uniqueId)('job'))),
41
+ },
42
+ ]);
43
+ const json = (await (0, assertions_1.assertOk)(response));
44
+ const ids = json.deployments.map((entry) => entry.processDefinition
45
+ .processDefinitionId);
46
+ (0, test_1.expect)(ids).toEqual(test_1.expect.arrayContaining([first, second]));
47
+ });
48
+ (0, api_1.test)('deploys a decision model', async ({ api, resources }) => {
49
+ const decisionId = (0, bpmn_1.uniqueId)('deploy-decision');
50
+ const response = await (0, deployments_1.deployResources)(api, resources, [
51
+ { name: `${decisionId}.dmn`, content: (0, bpmn_1.simpleDecision)(decisionId) },
52
+ ]);
53
+ const json = (await (0, assertions_1.assertOk)(response));
54
+ const decision = json.deployments.find((entry) => entry.decisionDefinition !== undefined);
55
+ (0, test_1.expect)(decision, 'deployment should report a decisionDefinition').toBeTruthy();
56
+ (0, assertions_1.assertRequiredFields)(decision.decisionDefinition, [
57
+ 'decisionDefinitionKey',
58
+ 'decisionDefinitionId',
59
+ 'decisionRequirementsKey',
60
+ ]);
61
+ });
62
+ (0, api_1.test)('increments the version when redeploying a changed model', async ({ api, resources, }) => {
63
+ const processId = (0, bpmn_1.uniqueId)('deploy-version');
64
+ const first = await (0, deployments_1.deployResources)(api, resources, [
65
+ { name: `${processId}.bpmn`, content: (0, bpmn_1.emptyProcess)(processId) },
66
+ ]);
67
+ await (0, assertions_1.assertOk)(first);
68
+ const second = await (0, deployments_1.deployResources)(api, resources, [
69
+ {
70
+ name: `${processId}.bpmn`,
71
+ content: (0, bpmn_1.linearProcess)(processId, bpmn_1.element.serviceTask((0, bpmn_1.uniqueId)('job'))),
72
+ },
73
+ ]);
74
+ const json = (await (0, assertions_1.assertOk)(second));
75
+ const definition = json.deployments[0].processDefinition;
76
+ (0, test_1.expect)(definition.processDefinitionVersion).toBe(2);
77
+ });
78
+ (0, api_1.test)('rejects a resource that is not valid BPMN', async ({ api, resources, }) => {
79
+ const response = await (0, deployments_1.deployResources)(api, resources, [
80
+ { name: 'broken.bpmn', content: '<not-bpmn>nonsense</not-bpmn>' },
81
+ ]);
82
+ await (0, assertions_1.assertBadRequest)(response);
83
+ });
84
+ (0, api_1.test)('rejects an unauthenticated deployment', async ({ api }) => {
85
+ api_1.test.skip(capabilities_1.unauthenticatedAccessAllowed !== false, capabilities_1.unauthenticatedAccessAllowed === false
86
+ ? ''
87
+ : capabilities_1.unauthenticatedAccessAllowed);
88
+ const processId = (0, bpmn_1.uniqueId)('deploy-unauth');
89
+ const response = await api.post('/deployments', {
90
+ tenant: 'none',
91
+ authorization: null,
92
+ multipart: {
93
+ resources: {
94
+ name: `${processId}.bpmn`,
95
+ mimeType: 'application/xml',
96
+ buffer: Buffer.from((0, bpmn_1.emptyProcess)(processId), 'utf-8'),
97
+ },
98
+ },
99
+ });
100
+ await (0, assertions_1.assertUnauthorized)(response);
101
+ });
102
+ // There is no POST /v2/deployments/search on any supported version. The
103
+ // test that lived here called it "undocumented on some minors" and accepted
104
+ // `200 404`, so the 404 it always received passed — the same shape of
105
+ // vacuous assertion this suite replaced.
106
+ //
107
+ // Its first replacement read the deployment back through
108
+ // /v2/resources/{key}, which was also wrong: that tree serves standalone
109
+ // resources, and a processDefinitionKey passed to it answers 404. Reading a
110
+ // deployment back is covered by the process-definition get-by-key and
111
+ // search tests, so nothing is owed here.
112
+ });
113
+ api_1.test.describe('Resource deletion', () => {
114
+ (0, api_1.test)('deletes a deployed process definition', async ({ api, resources }) => {
115
+ const processId = (0, bpmn_1.uniqueId)('resource-delete');
116
+ const deployResponse = await (0, deployments_1.deployResources)(api, resources, [
117
+ { name: `${processId}.bpmn`, content: (0, bpmn_1.emptyProcess)(processId) },
118
+ ]);
119
+ const json = (await (0, assertions_1.assertOk)(deployResponse));
120
+ const key = String(json.deployments[0].processDefinition
121
+ .processDefinitionKey);
122
+ const response = await api.post('/resources/{resourceKey}/deletion', {
123
+ params: { resourceKey: key },
124
+ body: {},
125
+ tenant: 'none',
126
+ });
127
+ // The endpoint answers 200 with a `DeleteResourceResponse` body naming
128
+ // the deleted resource (and the batch operation that clears its history),
129
+ // not a bare 204.
130
+ const deletion = (await (0, assertions_1.assertOk)(response));
131
+ (0, test_1.expect)(String(deletion.resourceKey)).toBe(key);
132
+ // The test is the deletion, so cleanup has nothing left to do.
133
+ resources.forget('resource', key);
134
+ await (0, eventually_1.eventually)(async () => {
135
+ const lookup = await api.get('/process-definitions/{processDefinitionKey}', { params: { processDefinitionKey: key } });
136
+ await (0, assertions_1.assertNotFound)(lookup);
137
+ });
138
+ });
139
+ (0, api_1.test)('rejects deleting an absent resource', async ({ api }) => {
140
+ const response = await api.post('/resources/{resourceKey}/deletion', {
141
+ params: { resourceKey: keys_1.ABSENT_ROUTABLE_KEY },
142
+ body: {},
143
+ tenant: 'none',
144
+ });
145
+ await (0, assertions_1.assertNotFound)(response);
146
+ });
147
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Document store endpoints.
3
+ *
4
+ * The shell suite exercised these only from inside its authorization
5
+ * enforcement block, so on any run where that block did not execute — the
6
+ * common case, since it was gated on a token fetch — the document endpoints
7
+ * were never called at all.
8
+ */
9
+ export {};
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ /**
3
+ * Document store endpoints.
4
+ *
5
+ * The shell suite exercised these only from inside its authorization
6
+ * enforcement block, so on any run where that block did not execute — the
7
+ * common case, since it was gated on a token fetch — the document endpoints
8
+ * were never called at all.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ const api_1 = require("../../../../fixtures/api");
12
+ const test_1 = require("@playwright/test");
13
+ const assertions_1 = require("../../../../utils/api/assertions");
14
+ const config_1 = require("../../../../utils/api/config");
15
+ const bpmn_1 = require("../../../../utils/api/bpmn");
16
+ const capabilities_1 = require("../../../../utils/api/capabilities");
17
+ async function upload(api, content, fileName = `${(0, bpmn_1.uniqueId)('doc')}.txt`) {
18
+ const multipart = {
19
+ file: {
20
+ name: fileName,
21
+ mimeType: 'text/plain',
22
+ buffer: Buffer.from(content, 'utf-8'),
23
+ },
24
+ };
25
+ if (config_1.apiConfig.multiTenancy) {
26
+ multipart.tenantId = config_1.apiConfig.tenantId;
27
+ }
28
+ return api.post('/documents', { multipart, tenant: 'none' });
29
+ }
30
+ async function uploadAndTrack(api, content) {
31
+ const response = await upload(api, content);
32
+ await (0, assertions_1.assertStatusIn)(response, [201], 'a stored document is reported as created');
33
+ const json = (await response.json());
34
+ (0, assertions_1.assertRequiredFields)(json, ['documentId', 'contentHash']);
35
+ return {
36
+ documentId: String(json.documentId),
37
+ contentHash: String(json.contentHash),
38
+ };
39
+ }
40
+ api_1.test.describe('Documents', () => {
41
+ (0, api_1.test)('stores a document', async ({ api, resources }) => {
42
+ const document = await uploadAndTrack(api, 'stored by the API suite');
43
+ resources.track('document', document.documentId);
44
+ (0, test_1.expect)(document.documentId).toBeTruthy();
45
+ (0, test_1.expect)(document.contentHash).toBeTruthy();
46
+ });
47
+ (0, api_1.test)('returns the stored content', async ({ api, resources }) => {
48
+ const content = `payload ${(0, bpmn_1.uniqueId)('body')}`;
49
+ const document = await uploadAndTrack(api, content);
50
+ resources.track('document', document.documentId);
51
+ const response = await api.get('/documents/{documentId}', {
52
+ params: { documentId: document.documentId },
53
+ query: { contentHash: document.contentHash },
54
+ tenant: 'none',
55
+ headers: { Accept: 'application/octet-stream' },
56
+ });
57
+ await (0, assertions_1.assertStatusIn)(response, [200], 'a stored document is retrievable');
58
+ // The shell suite checked only the status. A download returning the wrong
59
+ // bytes, or none, would have passed.
60
+ (0, test_1.expect)(await response.text()).toBe(content);
61
+ });
62
+ (0, api_1.test)('rejects a download whose content hash does not match', async ({ api, resources, }) => {
63
+ const document = await uploadAndTrack(api, 'hash check');
64
+ resources.track('document', document.documentId);
65
+ const response = await api.get('/documents/{documentId}', {
66
+ params: { documentId: document.documentId },
67
+ query: { contentHash: 'not-the-right-hash' },
68
+ tenant: 'none',
69
+ });
70
+ await (0, assertions_1.assertStatusIn)(response, [400, 404], 'a mismatched content hash is rejected as a bad request or reported as not found');
71
+ });
72
+ (0, api_1.test)('deletes a document', async ({ api }) => {
73
+ const document = await uploadAndTrack(api, 'to be deleted');
74
+ const response = await api.delete('/documents/{documentId}', {
75
+ params: { documentId: document.documentId },
76
+ tenant: 'none',
77
+ });
78
+ await (0, assertions_1.assertStatusIn)(response, [204], 'deletion is acknowledged');
79
+ const lookup = await api.get('/documents/{documentId}', {
80
+ params: { documentId: document.documentId },
81
+ query: { contentHash: document.contentHash },
82
+ tenant: 'none',
83
+ });
84
+ await (0, assertions_1.assertNotFound)(lookup);
85
+ });
86
+ (0, api_1.test)('rejects a lookup for an absent document', async ({ api }) => {
87
+ const response = await api.get('/documents/{documentId}', {
88
+ params: { documentId: (0, bpmn_1.uniqueId)('absent-document') },
89
+ query: { contentHash: 'irrelevant' },
90
+ tenant: 'none',
91
+ });
92
+ await (0, assertions_1.assertNotFound)(response);
93
+ });
94
+ (0, api_1.test)('rejects an unauthenticated upload', async ({ api }) => {
95
+ api_1.test.skip(capabilities_1.unauthenticatedAccessAllowed !== false, capabilities_1.unauthenticatedAccessAllowed === false
96
+ ? ''
97
+ : capabilities_1.unauthenticatedAccessAllowed);
98
+ const response = await api.post('/documents', {
99
+ tenant: 'none',
100
+ authorization: null,
101
+ multipart: {
102
+ file: {
103
+ name: `${(0, bpmn_1.uniqueId)('doc')}.txt`,
104
+ mimeType: 'text/plain',
105
+ buffer: Buffer.from('unauthenticated', 'utf-8'),
106
+ },
107
+ },
108
+ });
109
+ await (0, assertions_1.assertUnauthorized)(response);
110
+ });
111
+ });
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const api_1 = require("../../../../fixtures/api");
4
+ const test_1 = require("@playwright/test");
5
+ const assertions_1 = require("../../../../utils/api/assertions");
6
+ const deployments_1 = require("../../../../utils/api/deployments");
7
+ const bpmn_1 = require("../../../../utils/api/bpmn");
8
+ const eventually_1 = require("../../../../utils/api/eventually");
9
+ const keys_1 = require("../../../../utils/api/keys");
10
+ async function startAndAwaitElement(api, resources) {
11
+ const processId = (0, bpmn_1.uniqueId)('element-instance-api');
12
+ await (0, deployments_1.deployProcess)(api, resources, processId, (0, bpmn_1.linearProcess)(processId, bpmn_1.element.serviceTask((0, bpmn_1.uniqueId)('job'))));
13
+ const start = await api.post('/process-instances', {
14
+ body: { processDefinitionId: processId },
15
+ tenant: 'root',
16
+ });
17
+ await (0, assertions_1.assertStatusIn)(start, [200], 'instance creation is synchronous');
18
+ const instance = (await start.json());
19
+ const processInstanceKey = String(instance.processInstanceKey);
20
+ const items = await (0, eventually_1.eventuallyGet)(async () => {
21
+ const response = await api.post('/element-instances/search', {
22
+ body: {
23
+ filter: { processInstanceKey, elementId: 'task' },
24
+ page: { limit: 10 },
25
+ },
26
+ });
27
+ const page = await (0, assertions_1.assertPaginated)(response);
28
+ return page.items;
29
+ }, (found) => found.length > 0, { description: `element instances for ${processInstanceKey}` });
30
+ return {
31
+ elementInstanceKey: String(items[0].elementInstanceKey),
32
+ processInstanceKey,
33
+ };
34
+ }
35
+ api_1.test.describe('Element instances', () => {
36
+ (0, api_1.test)('finds the active element of a running instance', async ({ api, resources, }) => {
37
+ const { elementInstanceKey, processInstanceKey } = await startAndAwaitElement(api, resources);
38
+ resources.track('processInstance', processInstanceKey);
39
+ const response = await api.post('/element-instances/search', {
40
+ body: { filter: { processInstanceKey, elementId: 'task' } },
41
+ });
42
+ const page = await (0, assertions_1.assertPaginated)(response, { minItems: 1 });
43
+ const item = page.items[0];
44
+ (0, test_1.expect)(String(item.elementInstanceKey)).toBe(elementInstanceKey);
45
+ (0, test_1.expect)(item.type).toBe('SERVICE_TASK');
46
+ });
47
+ (0, api_1.test)('returns an element instance by key', async ({ api, resources }) => {
48
+ const { elementInstanceKey, processInstanceKey } = await startAndAwaitElement(api, resources);
49
+ resources.track('processInstance', processInstanceKey);
50
+ const response = await api.get('/element-instances/{elementInstanceKey}', {
51
+ params: { elementInstanceKey },
52
+ });
53
+ const json = (await (0, assertions_1.assertOk)(response));
54
+ (0, assertions_1.assertRequiredFields)(json, [
55
+ 'elementInstanceKey',
56
+ 'elementId',
57
+ 'state',
58
+ 'processInstanceKey',
59
+ ]);
60
+ (0, test_1.expect)(json.elementId).toBe('task');
61
+ (0, test_1.expect)(json.state).toBe('ACTIVE');
62
+ });
63
+ (0, api_1.test)('filters element instances by state', async ({ api, resources }) => {
64
+ const { processInstanceKey } = await startAndAwaitElement(api, resources);
65
+ resources.track('processInstance', processInstanceKey);
66
+ const response = await api.post('/element-instances/search', {
67
+ body: { filter: { processInstanceKey, state: 'ACTIVE' }, page: { limit: 20 } },
68
+ });
69
+ const page = await (0, assertions_1.assertPaginated)(response, { minItems: 1 });
70
+ for (const item of page.items) {
71
+ (0, test_1.expect)(item.state).toBe('ACTIVE');
72
+ }
73
+ });
74
+ (0, api_1.test)('sets a variable on an element instance', async ({ api, resources }) => {
75
+ const { elementInstanceKey, processInstanceKey } = await startAndAwaitElement(api, resources);
76
+ resources.track('processInstance', processInstanceKey);
77
+ const response = await api.put('/element-instances/{elementInstanceKey}/variables', {
78
+ params: { elementInstanceKey },
79
+ body: { variables: { scoped: 'value' }, local: true },
80
+ tenant: 'none',
81
+ });
82
+ // The shell suite accepted `200 204 400 404 405 501 503` for this call —
83
+ // seven statuses, including three that mean the endpoint does not exist.
84
+ await (0, assertions_1.assertStatusIn)(response, [204], 'the variable update is acknowledged once the command is written');
85
+ await (0, eventually_1.eventually)(async () => {
86
+ const variables = await api.post('/variables/search', {
87
+ body: {
88
+ filter: { processInstanceKey, name: 'scoped' },
89
+ page: { limit: 10 },
90
+ },
91
+ });
92
+ await (0, assertions_1.assertPaginated)(variables, { minItems: 1 });
93
+ });
94
+ });
95
+ (0, api_1.test)('honours the page size on an element-instance search', async ({ api, resources, }) => {
96
+ const { processInstanceKey } = await startAndAwaitElement(api, resources);
97
+ resources.track('processInstance', processInstanceKey);
98
+ const response = await api.post('/element-instances/search', {
99
+ body: { filter: { processInstanceKey }, page: { limit: 1 } },
100
+ });
101
+ const page = await (0, assertions_1.assertPaginated)(response, { exactItems: 1 });
102
+ (0, test_1.expect)(page.items.length).toBe(1);
103
+ });
104
+ (0, api_1.test)('rejects a lookup for an absent element instance', async ({ api }) => {
105
+ const response = await api.get('/element-instances/{elementInstanceKey}', {
106
+ params: { elementInstanceKey: keys_1.ABSENT_KEY },
107
+ });
108
+ await (0, assertions_1.assertNotFound)(response);
109
+ });
110
+ (0, api_1.test)('rejects setting variables on an absent element instance', async ({ api, }) => {
111
+ // A command, so the key has to reach a real partition — see
112
+ // `ABSENT_ROUTABLE_KEY`. With the query-side key this asserted the
113
+ // gateway's router (503, undeliverable) rather than the handler's 404.
114
+ const response = await api.put('/element-instances/{elementInstanceKey}/variables', {
115
+ params: { elementInstanceKey: keys_1.ABSENT_ROUTABLE_KEY },
116
+ body: { variables: { a: 1 } },
117
+ tenant: 'none',
118
+ });
119
+ await (0, assertions_1.assertNotFound)(response);
120
+ });
121
+ (0, api_1.test)('rejects a variable update carrying no variables', async ({ api, resources, }) => {
122
+ const { elementInstanceKey, processInstanceKey } = await startAndAwaitElement(api, resources);
123
+ resources.track('processInstance', processInstanceKey);
124
+ const response = await api.put('/element-instances/{elementInstanceKey}/variables', { params: { elementInstanceKey }, body: {}, tenant: 'none' });
125
+ await (0, assertions_1.assertBadRequest)(response);
126
+ });
127
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Multi-step flows spanning several endpoints.
3
+ *
4
+ * These correspond to the shell suite's "Integration Test 1-4" (lines
5
+ * 8386-9353), which tracked their own `INTEGRATION_TEST_N_PASSED` booleans and
6
+ * incremented TESTS_PASSED by hand — 50 increment sites against 27 failure
7
+ * sites, so a step could report success with no path that reported failure.
8
+ */
9
+ export {};