bpmn-client 1.3.26 → 1.4.0
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.
- package/cli.js +2 -2
- package/cli.ts +2 -2
- package/package.json +1 -1
- package/remote-import.js +5 -1
- package/remote-import.ts +7 -1
- package/src/BPMNClient.js +16 -5
- package/src/BPMNClient.ts +14 -5
- package/src/WebService.js +2 -2
- package/src/WebService.ts +2 -3
- package/src/interfaces/BPMNClient.js +2 -0
- package/src/interfaces/BPMNClient.ts +29 -0
- package/src/interfaces/DataObjects.ts +6 -5
- package/src/interfaces/Enums.js +4 -4
- package/src/interfaces/Enums.ts +2 -2
- package/test/feature/.env +3 -2
- package/test/feature/car.js +123 -0
- package/test/feature/carServer.js +8 -7
package/cli.js
CHANGED
|
@@ -118,10 +118,10 @@ function start() {
|
|
|
118
118
|
function findItems(query) {
|
|
119
119
|
return __awaiter(this, void 0, void 0, function* () {
|
|
120
120
|
var items = yield server.datastore.findItems(query);
|
|
121
|
-
console.log(
|
|
121
|
+
console.log(`processName item.name item.elementId instanceId item.id`);
|
|
122
122
|
for (var i = 0; i < items.length; i++) {
|
|
123
123
|
let item = items[i];
|
|
124
|
-
console.log(`${item.name}
|
|
124
|
+
console.log(`${item['processName']} ${item.name} ${item.elementId} ${item['instanceId']} ${item.id}`);
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
127
|
}
|
package/cli.ts
CHANGED
|
@@ -127,10 +127,10 @@ async function start()
|
|
|
127
127
|
async function findItems(query) {
|
|
128
128
|
var items = await server.datastore.findItems(query);
|
|
129
129
|
|
|
130
|
-
console.log(
|
|
130
|
+
console.log(`processName item.name item.elementId instanceId item.id`);
|
|
131
131
|
for (var i = 0; i < items.length; i++) {
|
|
132
132
|
let item = items[i];
|
|
133
|
-
console.log(`${item.name}
|
|
133
|
+
console.log(`${item['processName']} ${item.name} ${item.elementId} ${item['instanceId']} ${item.id}`);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
}
|
package/package.json
CHANGED
package/remote-import.js
CHANGED
|
@@ -42,7 +42,11 @@ function fromClientLib() {
|
|
|
42
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
43
43
|
console.log('from client lib');
|
|
44
44
|
try {
|
|
45
|
-
const server = new
|
|
45
|
+
// const server = new BPMNClient('localhost', 3000, '12345');
|
|
46
|
+
const dotenv = require('dotenv');
|
|
47
|
+
dotenv.config();
|
|
48
|
+
console.log('env:', process.env.HOST, process.env.PORT, process.env.API_KEY);
|
|
49
|
+
const server = new _1.BPMNClient(process.env.HOST, process.env.PORT, process.env.API_KEY);
|
|
46
50
|
var name = 'test-import';
|
|
47
51
|
var file = '..\\WebApp\\processes\\Trans.bpmn';
|
|
48
52
|
var file2 = '..\\WebApp\\processes\\Trans.svg';
|
package/remote-import.ts
CHANGED
|
@@ -43,7 +43,13 @@ async function fromClientLib() {
|
|
|
43
43
|
|
|
44
44
|
console.log('from client lib');
|
|
45
45
|
try {
|
|
46
|
-
const server = new BPMNClient('localhost', 3000, '12345');
|
|
46
|
+
// const server = new BPMNClient('localhost', 3000, '12345');
|
|
47
|
+
|
|
48
|
+
const dotenv = require('dotenv');
|
|
49
|
+
dotenv.config();
|
|
50
|
+
console.log('env:',process.env.HOST, process.env.PORT, process.env.API_KEY);
|
|
51
|
+
|
|
52
|
+
const server = new BPMNClient(process.env.HOST, process.env.PORT, process.env.API_KEY);
|
|
47
53
|
|
|
48
54
|
var name = 'test-import';
|
|
49
55
|
var file = '..\\WebApp\\processes\\Trans.bpmn';
|
package/src/BPMNClient.js
CHANGED
|
@@ -88,9 +88,9 @@ class ClientEngine {
|
|
|
88
88
|
constructor(client) {
|
|
89
89
|
this.client = client;
|
|
90
90
|
}
|
|
91
|
-
start(name, data = {}, startNodeId = null, options = {}) {
|
|
91
|
+
start(name, data = {}, startNodeId = null, userId = null, options = {}) {
|
|
92
92
|
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
-
const ret = yield this.client.post('engine/start', { name, data, startNodeId, options });
|
|
93
|
+
const ret = yield this.client.post('engine/start', { name, data, startNodeId, userId, options });
|
|
94
94
|
if (ret['errors']) {
|
|
95
95
|
console.log(ret['errors']);
|
|
96
96
|
throw new Error(ret['errors']);
|
|
@@ -99,9 +99,20 @@ class ClientEngine {
|
|
|
99
99
|
return instance;
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
|
-
invoke(query, data) {
|
|
102
|
+
invoke(query, data, userId = null) {
|
|
103
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
-
const ret = yield this.client.put('engine/invoke', { query, data });
|
|
104
|
+
const ret = yield this.client.put('engine/invoke', { query, data, userId });
|
|
105
|
+
if (ret['errors']) {
|
|
106
|
+
console.log(ret['errors']);
|
|
107
|
+
throw new Error(ret['errors']);
|
|
108
|
+
}
|
|
109
|
+
const instance = ret['instance'];
|
|
110
|
+
return instance;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
assign(query, data, userId = null, assignment) {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
const ret = yield this.client.put('engine/assign', { query, data, userId, assignment });
|
|
105
116
|
if (ret['errors']) {
|
|
106
117
|
console.log(ret['errors']);
|
|
107
118
|
throw new Error(ret['errors']);
|
|
@@ -194,7 +205,7 @@ class ClientDefinitions {
|
|
|
194
205
|
return __awaiter(this, void 0, void 0, function* () {
|
|
195
206
|
var options = {
|
|
196
207
|
'method': 'POST',
|
|
197
|
-
'
|
|
208
|
+
'host': this.client.host,
|
|
198
209
|
'port': this.client.port,
|
|
199
210
|
'path': '/api/definitions/import/' + name,
|
|
200
211
|
'headers': {
|
package/src/BPMNClient.ts
CHANGED
|
@@ -94,9 +94,9 @@ class ClientEngine {
|
|
|
94
94
|
constructor(client) {
|
|
95
95
|
this.client = client;
|
|
96
96
|
}
|
|
97
|
-
async start(name, data = {}, startNodeId = null, options = {}): Promise<IInstanceData> {
|
|
97
|
+
async start(name, data = {}, startNodeId = null, userId= null,options = {}): Promise<IInstanceData> {
|
|
98
98
|
const ret = await this.client.post('engine/start',
|
|
99
|
-
{ name, data, startNodeId, options });
|
|
99
|
+
{ name, data, startNodeId, userId, options });
|
|
100
100
|
if (ret['errors']) {
|
|
101
101
|
console.log(ret['errors']);
|
|
102
102
|
throw new Error(ret['errors']);
|
|
@@ -104,8 +104,17 @@ class ClientEngine {
|
|
|
104
104
|
const instance = ret as IInstanceData;
|
|
105
105
|
return instance;
|
|
106
106
|
}
|
|
107
|
-
async invoke(query, data): Promise<IInstanceData> {
|
|
108
|
-
const ret = await this.client.put('engine/invoke', { query, data });
|
|
107
|
+
async invoke(query, data, userId= null): Promise<IInstanceData> {
|
|
108
|
+
const ret = await this.client.put('engine/invoke', { query, data , userId });
|
|
109
|
+
if (ret['errors']) {
|
|
110
|
+
console.log(ret['errors']);
|
|
111
|
+
throw new Error(ret['errors']);
|
|
112
|
+
}
|
|
113
|
+
const instance = ret['instance'] as IInstanceData;
|
|
114
|
+
return instance;
|
|
115
|
+
}
|
|
116
|
+
async assign(query, data, userId= null,assignment): Promise<IInstanceData> {
|
|
117
|
+
const ret = await this.client.put('engine/assign', { query, data , userId,assignment });
|
|
109
118
|
if (ret['errors']) {
|
|
110
119
|
console.log(ret['errors']);
|
|
111
120
|
throw new Error(ret['errors']);
|
|
@@ -190,7 +199,7 @@ class ClientDefinitions {
|
|
|
190
199
|
|
|
191
200
|
var options = {
|
|
192
201
|
'method': 'POST',
|
|
193
|
-
'
|
|
202
|
+
'host': this.client.host,
|
|
194
203
|
'port': this.client.port,
|
|
195
204
|
'path': '/api/definitions/import/' + name,
|
|
196
205
|
'headers': {
|
package/src/WebService.js
CHANGED
|
@@ -43,7 +43,7 @@ class WebService {
|
|
|
43
43
|
upload(fileName, path, path2, options) {
|
|
44
44
|
return __awaiter(this, void 0, void 0, function* () {
|
|
45
45
|
const title = fileName;
|
|
46
|
-
var url = 'http://' + options.
|
|
46
|
+
var url = 'http://' + options.host + ':' + options.port + options.path;
|
|
47
47
|
if (options.port == 443)
|
|
48
48
|
url = 'https://' + options.host + options.path;
|
|
49
49
|
const form = new FormData();
|
|
@@ -62,7 +62,7 @@ class WebService {
|
|
|
62
62
|
return response.data;
|
|
63
63
|
}
|
|
64
64
|
catch (error) {
|
|
65
|
-
console.log('upload failed:', error
|
|
65
|
+
console.log('upload failed:', error);
|
|
66
66
|
throw new Error(error.message);
|
|
67
67
|
/*
|
|
68
68
|
if (error.response) { // get response with a status code not in range 2xx
|
package/src/WebService.ts
CHANGED
|
@@ -44,11 +44,10 @@ class WebService {
|
|
|
44
44
|
|
|
45
45
|
const title = fileName;
|
|
46
46
|
|
|
47
|
-
var url = 'http://'+options.
|
|
47
|
+
var url = 'http://'+options.host+':'+options.port+options.path;
|
|
48
48
|
|
|
49
49
|
if (options.port == 443)
|
|
50
50
|
url = 'https://'+options.host+options.path;
|
|
51
|
-
|
|
52
51
|
|
|
53
52
|
const form = new FormData();
|
|
54
53
|
form.append('title', title);
|
|
@@ -71,7 +70,7 @@ class WebService {
|
|
|
71
70
|
|
|
72
71
|
}
|
|
73
72
|
catch (error) {
|
|
74
|
-
console.log('upload failed:',error
|
|
73
|
+
console.log('upload failed:',error);
|
|
75
74
|
throw new Error(error.message);
|
|
76
75
|
/*
|
|
77
76
|
if (error.response) { // get response with a status code not in range 2xx
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IInstanceData, IItemData , IDefinitionData} from './DataObjects';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export interface IBPMNClient {
|
|
5
|
+
engine: IClientEngine;
|
|
6
|
+
datastore: IClientDatastore;
|
|
7
|
+
definitions: IClientDefinitions;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface IClientEngine {
|
|
11
|
+
start(name, data , startNodeId , userId,options ): Promise<IInstanceData>;
|
|
12
|
+
invoke(query, data, userId): Promise<IInstanceData> ;
|
|
13
|
+
assign(query, data, userId,assignment): Promise<IInstanceData>;
|
|
14
|
+
throwMessage(messageId, data, messageMatchingKey);
|
|
15
|
+
throwSignal(signalId, data, messageMatchingKey);
|
|
16
|
+
status();
|
|
17
|
+
}
|
|
18
|
+
export interface IClientDatastore {
|
|
19
|
+
findItems(query): Promise<IItemData[]>;
|
|
20
|
+
findInstances(query): Promise<IInstanceData[]>;
|
|
21
|
+
deleteInstances(query);
|
|
22
|
+
}
|
|
23
|
+
export interface IClientDefinitions {
|
|
24
|
+
import(name, pathToBPMN,pathToSVG);
|
|
25
|
+
list(): Promise<string[]>;
|
|
26
|
+
delete(name) ;
|
|
27
|
+
rename(name,newName);
|
|
28
|
+
load(name): Promise<IDefinitionData>;
|
|
29
|
+
}
|
|
@@ -17,10 +17,13 @@ interface IItemData {
|
|
|
17
17
|
data: any;
|
|
18
18
|
messageId;
|
|
19
19
|
signalId;
|
|
20
|
-
assignments;
|
|
21
|
-
authorizations;
|
|
22
|
-
notifications;
|
|
23
20
|
vars;
|
|
21
|
+
assignee;
|
|
22
|
+
candidateGroups;
|
|
23
|
+
candidateUsers;
|
|
24
|
+
dueDate;
|
|
25
|
+
followUpDate;
|
|
26
|
+
priority;
|
|
24
27
|
}
|
|
25
28
|
interface IInstanceData {
|
|
26
29
|
id;
|
|
@@ -36,8 +39,6 @@ interface IInstanceData {
|
|
|
36
39
|
tokens;
|
|
37
40
|
loops;
|
|
38
41
|
parentItemId; // used for subProcess Calls
|
|
39
|
-
involvements;
|
|
40
|
-
authorizations;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
|
package/src/interfaces/Enums.js
CHANGED
|
@@ -65,15 +65,15 @@ var EXECUTION_EVENT;
|
|
|
65
65
|
/*
|
|
66
66
|
* possible actions by node
|
|
67
67
|
*/
|
|
68
|
-
// must be same as above
|
|
69
68
|
var NODE_ACTION;
|
|
70
69
|
(function (NODE_ACTION) {
|
|
71
70
|
NODE_ACTION[NODE_ACTION["continue"] = 1] = "continue";
|
|
72
71
|
NODE_ACTION[NODE_ACTION["wait"] = 2] = "wait";
|
|
73
72
|
NODE_ACTION[NODE_ACTION["end"] = 3] = "end";
|
|
74
|
-
NODE_ACTION[NODE_ACTION["
|
|
75
|
-
NODE_ACTION[NODE_ACTION["
|
|
76
|
-
NODE_ACTION[NODE_ACTION["
|
|
73
|
+
NODE_ACTION[NODE_ACTION["cancel"] = 4] = "cancel";
|
|
74
|
+
NODE_ACTION[NODE_ACTION["stop"] = 5] = "stop";
|
|
75
|
+
NODE_ACTION[NODE_ACTION["error"] = 6] = "error";
|
|
76
|
+
NODE_ACTION[NODE_ACTION["abort"] = 7] = "abort";
|
|
77
77
|
})(NODE_ACTION || (exports.NODE_ACTION = NODE_ACTION = {}));
|
|
78
78
|
;
|
|
79
79
|
var ITEM_STATUS;
|
package/src/interfaces/Enums.ts
CHANGED
|
@@ -49,8 +49,8 @@ enum EXECUTION_EVENT {
|
|
|
49
49
|
/*
|
|
50
50
|
* possible actions by node
|
|
51
51
|
*/
|
|
52
|
-
|
|
53
|
-
enum NODE_ACTION { continue = 1, wait, end , stop , error , abort };
|
|
52
|
+
|
|
53
|
+
enum NODE_ACTION { continue = 1, wait, end , cancel, stop , error , abort };
|
|
54
54
|
|
|
55
55
|
enum ITEM_STATUS {
|
|
56
56
|
enter = 'enter',
|
package/test/feature/.env
CHANGED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const { BPMNClient } = require("../../src/");
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const API_KEY = '12345';
|
|
6
|
+
const HOST = 'localhost';
|
|
7
|
+
const PORT = '3000';
|
|
8
|
+
//const HOST = 'test.omniworkflow.com';
|
|
9
|
+
//const PORT = '443';
|
|
10
|
+
|
|
11
|
+
const BASE_URL = 'api';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
console.log('-------- carServer.js -----------');
|
|
15
|
+
|
|
16
|
+
const server = new BPMNClient(HOST, PORT, API_KEY);
|
|
17
|
+
|
|
18
|
+
var caseId = Math.floor(Math.random() * 10000);
|
|
19
|
+
|
|
20
|
+
let name = 'Buy Used Car';
|
|
21
|
+
let process;
|
|
22
|
+
let response;
|
|
23
|
+
let instanceId;
|
|
24
|
+
let userId='user1';
|
|
25
|
+
|
|
26
|
+
Feature('Buy Used Car- clean and repair', () => {
|
|
27
|
+
Scenario('Simple', () => {
|
|
28
|
+
Given('Start Buy Used Car Process',async () => {
|
|
29
|
+
response = await server.engine.start(name, {caseId: caseId},null,userId);
|
|
30
|
+
console.log('**instanceId', response.id);
|
|
31
|
+
instanceId = response.id;
|
|
32
|
+
console.log('data:',response.data);
|
|
33
|
+
console.log('item',getItem('task_Buy'));
|
|
34
|
+
|
|
35
|
+
// console.log(' after start ', response.instance.caseId);
|
|
36
|
+
});
|
|
37
|
+
Then('check for output', () => {
|
|
38
|
+
expect(response.data.starterUserId).equals(userId);
|
|
39
|
+
expect(response.data.caseId).equals(caseId);
|
|
40
|
+
expect(getItem('task_Buy').status).equals('wait');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
When('assignTask', async () => {
|
|
44
|
+
const query = {id: instanceId ,"items.elementId": 'task_Buy' };
|
|
45
|
+
const assignment = {assignee: userId,
|
|
46
|
+
candidateUsers: ['employee1','manager1'],
|
|
47
|
+
dueDate :new Date() , priority: 7
|
|
48
|
+
};
|
|
49
|
+
response = await server.engine.assign(query,null,userId,assignment);
|
|
50
|
+
|
|
51
|
+
const itm=getItem('task_Buy');
|
|
52
|
+
|
|
53
|
+
console.log(itm);
|
|
54
|
+
|
|
55
|
+
expect(itm.priority).equals(7);
|
|
56
|
+
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
When('a process defintion is executed', async () => {
|
|
62
|
+
|
|
63
|
+
const data = { needsCleaning: "Yes", needsRepairs: "Yes" };
|
|
64
|
+
const query ={
|
|
65
|
+
id: instanceId ,
|
|
66
|
+
"items.elementId": 'task_Buy'
|
|
67
|
+
};
|
|
68
|
+
// console.log(query);
|
|
69
|
+
response= await server.engine.invoke(query ,data );
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
When('engine get', async () => {
|
|
73
|
+
const query = {id: instanceId };
|
|
74
|
+
|
|
75
|
+
response = await server.engine.get(query);
|
|
76
|
+
|
|
77
|
+
expect(response.id).equals(instanceId);
|
|
78
|
+
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
Then('check for output to have engine', () => {
|
|
83
|
+
expect(getItem('task_Buy').status).equals('end');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
and('Clean it', async () => {
|
|
87
|
+
|
|
88
|
+
const query = {
|
|
89
|
+
"data.caseId": caseId ,
|
|
90
|
+
"items.elementId": 'task_clean'
|
|
91
|
+
};
|
|
92
|
+
// console.log(query);
|
|
93
|
+
await server.engine.invoke(query, {});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
and('Repair it', async () => {
|
|
97
|
+
const query = { id: instanceId ,"items.elementId": 'task_repair'};
|
|
98
|
+
response = await server.engine.invoke(query, {});
|
|
99
|
+
});
|
|
100
|
+
and('Drive it 1', async () => {
|
|
101
|
+
const query = {
|
|
102
|
+
id: instanceId ,
|
|
103
|
+
"items.elementId": 'task_Drive'};
|
|
104
|
+
response=await server.engine.invoke(query, {});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
and('Case Complete', async () => {
|
|
108
|
+
|
|
109
|
+
// console.log(response.instance.status);
|
|
110
|
+
// console.log(response.execution.status);
|
|
111
|
+
expect(response.status).equals('end');
|
|
112
|
+
expect(getItem('task_Drive').status).equals('end');
|
|
113
|
+
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
function getItem(id)
|
|
121
|
+
{
|
|
122
|
+
return response.items.filter(item => { return item.elementId == id; })[0];
|
|
123
|
+
}
|
|
@@ -11,7 +11,7 @@ const PORT = '3000';
|
|
|
11
11
|
const BASE_URL = 'api';
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
console.log('--------
|
|
14
|
+
console.log('-------- carServer.js -----------');
|
|
15
15
|
|
|
16
16
|
const server = new BPMNClient(HOST, PORT, API_KEY);
|
|
17
17
|
|
|
@@ -25,10 +25,11 @@ let instanceId;
|
|
|
25
25
|
Feature('Buy Used Car- clean and repair', () => {
|
|
26
26
|
Scenario('Simple', () => {
|
|
27
27
|
Given('Start Buy Used Car Process', async () => {
|
|
28
|
-
response = await server.engine.start(name, { caseId: caseId });
|
|
28
|
+
response = await server.engine.start(name, { caseId: caseId },null, 'remoteUser1');
|
|
29
29
|
instanceId = response.id;
|
|
30
|
-
|
|
31
|
-
console.log('
|
|
30
|
+
|
|
31
|
+
//console.log('**instanceId', response.id, instanceId);
|
|
32
|
+
//console.log(' after start ', response.data.caseId);
|
|
32
33
|
});
|
|
33
34
|
Then('check for output', () => {
|
|
34
35
|
expect(response.data.caseId).equals(caseId);
|
|
@@ -43,7 +44,7 @@ Feature('Buy Used Car- clean and repair', () => {
|
|
|
43
44
|
"items.elementId": 'task_Buy'
|
|
44
45
|
};
|
|
45
46
|
console.log(query);
|
|
46
|
-
response = await server.engine.invoke(query, data);
|
|
47
|
+
response = await server.engine.invoke(query, data,'RemoteUser2');
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
When('engine get', async () => {
|
|
@@ -67,7 +68,7 @@ Feature('Buy Used Car- clean and repair', () => {
|
|
|
67
68
|
"items.elementId": 'task_clean'
|
|
68
69
|
};
|
|
69
70
|
console.log(query);
|
|
70
|
-
await server.engine.invoke(query, {});
|
|
71
|
+
await server.engine.invoke(query, {},'remoteUser3');
|
|
71
72
|
});
|
|
72
73
|
|
|
73
74
|
and('Repair it', async () => {
|
|
@@ -79,7 +80,7 @@ Feature('Buy Used Car- clean and repair', () => {
|
|
|
79
80
|
id: instanceId,
|
|
80
81
|
"items.elementId": 'task_Drive'
|
|
81
82
|
};
|
|
82
|
-
response = await server.engine.invoke(query, {});
|
|
83
|
+
response = await server.engine.invoke(query, {},'remote_user4');
|
|
83
84
|
});
|
|
84
85
|
|
|
85
86
|
and('Case Complete', async () => {
|