wingbot 3.76.16 → 3.76.18
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/package.json +1 -1
- package/src/BotApp.js +1 -1
- package/src/LLMDispatcher.js +26 -5
- package/src/Processor.js +10 -4
- package/src/Request.js +36 -14
- package/src/Responder.js +35 -11
- package/src/Tester.js +12 -7
- package/src/templates/BaseTemplate.js +3 -1
- package/src/templates/ButtonTemplate.js +13 -1
- package/src/templates/GenericTemplate.js +1 -11
- package/src/testTools/AnyResponseAssert.js +6 -5
- package/src/testTools/ResponseAssert.js +3 -2
- package/src/testTools/asserts.js +17 -4
package/package.json
CHANGED
package/src/BotApp.js
CHANGED
|
@@ -418,7 +418,7 @@ class BotApp {
|
|
|
418
418
|
|
|
419
419
|
const sender = new BotAppSender(options, senderId, message, this._senderLogger);
|
|
420
420
|
const res = await this._processor
|
|
421
|
-
.processMessage(message, pageId, sender, { ...data, appId });
|
|
421
|
+
.processMessage(message, pageId, sender, { passPostbacks: true, ...data, appId });
|
|
422
422
|
|
|
423
423
|
return res;
|
|
424
424
|
}
|
package/src/LLMDispatcher.js
CHANGED
|
@@ -48,6 +48,7 @@ const BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{
|
|
|
48
48
|
/**
|
|
49
49
|
* @typedef {object} DispatcherOptions
|
|
50
50
|
* @prop {Logger} [log]
|
|
51
|
+
* @prop {boolean} [allowRefs]
|
|
51
52
|
*/
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -76,7 +77,8 @@ class LLMDispatcher {
|
|
|
76
77
|
actionList: [],
|
|
77
78
|
router: null,
|
|
78
79
|
byAction: new Map(),
|
|
79
|
-
routes: []
|
|
80
|
+
routes: [],
|
|
81
|
+
structuredOutput: null
|
|
80
82
|
},
|
|
81
83
|
locals: new Map()
|
|
82
84
|
};
|
|
@@ -98,6 +100,16 @@ class LLMDispatcher {
|
|
|
98
100
|
this._dispatched = false;
|
|
99
101
|
|
|
100
102
|
this._overrideAction = null;
|
|
103
|
+
|
|
104
|
+
this._allowRefs = !!options.allowRefs;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
*
|
|
109
|
+
* @param {boolean} [allow]
|
|
110
|
+
*/
|
|
111
|
+
allowRefs (allow = true) {
|
|
112
|
+
this._allowRefs = allow;
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
/**
|
|
@@ -137,7 +149,8 @@ class LLMDispatcher {
|
|
|
137
149
|
*/
|
|
138
150
|
async _postbackAction (responder = null) {
|
|
139
151
|
let res;
|
|
140
|
-
|
|
152
|
+
// @todo vypnout
|
|
153
|
+
if (this._allowRefs && this._req.referral !== null && this._req.referral.ref) {
|
|
141
154
|
res = parseActionPayload({ payload: this._req.referral.ref });
|
|
142
155
|
}
|
|
143
156
|
|
|
@@ -145,16 +158,24 @@ class LLMDispatcher {
|
|
|
145
158
|
res = parseActionPayload(this._req.postback);
|
|
146
159
|
}
|
|
147
160
|
|
|
148
|
-
if (!res && this._req.optin !== null && this._req.optin.ref) {
|
|
161
|
+
if (this._allowRefs && !res && this._req.optin !== null && this._req.optin.ref) {
|
|
149
162
|
res = this._base64Ref(this._req.optin);
|
|
150
163
|
}
|
|
151
164
|
|
|
152
|
-
if (!res && this._req.optin !== null && this._req.optin.payload) {
|
|
165
|
+
if (this._allowRefs && !res && this._req.optin !== null && this._req.optin.payload) {
|
|
153
166
|
res = parseActionPayload(this._req.optin);
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
if (!res && this._req.message !== null && this._req.message.quick_reply) {
|
|
157
|
-
|
|
170
|
+
const { payload, ...rest } = this._req.message.quick_reply;
|
|
171
|
+
const { _qrsPaylMap: payloadMap = {} } = this._req.state;
|
|
172
|
+
|
|
173
|
+
if (payload && payloadMap[payload]) {
|
|
174
|
+
res = parseActionPayload({
|
|
175
|
+
...rest,
|
|
176
|
+
payload: payloadMap[payload]
|
|
177
|
+
});
|
|
178
|
+
}
|
|
158
179
|
}
|
|
159
180
|
|
|
160
181
|
/**
|
package/src/Processor.js
CHANGED
|
@@ -117,6 +117,7 @@ const LLMDispatcher = require('./LLMDispatcher');
|
|
|
117
117
|
* @prop {LLMGlobalConfig} [llm] - LLM model configuration
|
|
118
118
|
* @prop {Preloader<R>} [preloader]
|
|
119
119
|
* @prop {string[]} [allowedPostBacks]
|
|
120
|
+
* @prop {boolean} [allowRefs]
|
|
120
121
|
*/
|
|
121
122
|
|
|
122
123
|
/**
|
|
@@ -210,7 +211,8 @@ class Processor extends EventEmitter {
|
|
|
210
211
|
redirectLimit: 20,
|
|
211
212
|
nameFromState: NAME_FROM_STATE,
|
|
212
213
|
sessionDuration: 1800000, // 30 minutes,
|
|
213
|
-
allowedPostBacks: []
|
|
214
|
+
allowedPostBacks: [],
|
|
215
|
+
allowRefs: false
|
|
214
216
|
};
|
|
215
217
|
|
|
216
218
|
Object.assign(this.options, options);
|
|
@@ -535,8 +537,9 @@ class Processor extends EventEmitter {
|
|
|
535
537
|
? Request.text('none', text)
|
|
536
538
|
: text;
|
|
537
539
|
// @ts-ignore
|
|
538
|
-
const dispatcher = new LLMDispatcher(Ai.ai, this.reducer.routing, {
|
|
539
|
-
log: this.options.log
|
|
540
|
+
const dispatcher = new LLMDispatcher(Ai.ai, this.reducer.routing, null, {
|
|
541
|
+
log: this.options.log,
|
|
542
|
+
allowRefs: this.options.allowRefs
|
|
540
543
|
});
|
|
541
544
|
const req = new Request(request, { lang }, pageId, dispatcher);
|
|
542
545
|
await dispatcher.dispatch(req);
|
|
@@ -643,7 +646,8 @@ class Processor extends EventEmitter {
|
|
|
643
646
|
}
|
|
644
647
|
|
|
645
648
|
const dispatcher = new LLMDispatcher(Ai.ai, this.reducer.routing, llm, {
|
|
646
|
-
log: this.options.log
|
|
649
|
+
log: this.options.log,
|
|
650
|
+
allowRefs: this.options.allowRefs
|
|
647
651
|
});
|
|
648
652
|
req = new Request(
|
|
649
653
|
message,
|
|
@@ -663,7 +667,9 @@ class Processor extends EventEmitter {
|
|
|
663
667
|
if (req.isPostBack()
|
|
664
668
|
&& fromEvent
|
|
665
669
|
&& reqActionNorm
|
|
670
|
+
&& !responderData.passPostbacks
|
|
666
671
|
&& this.options.allowedPostBacks.length > 0
|
|
672
|
+
&& !req.postBackHasObscuredPayload()
|
|
667
673
|
&& !this.options.allowedPostBacks.some((pb) => {
|
|
668
674
|
const norm = pb.replace(/^\/?/, '/');
|
|
669
675
|
return norm === reqActionNorm;
|
package/src/Request.js
CHANGED
|
@@ -173,9 +173,27 @@ class Request {
|
|
|
173
173
|
*/
|
|
174
174
|
this.params = {};
|
|
175
175
|
|
|
176
|
+
/**
|
|
177
|
+
* @type {S} current state of the conversation
|
|
178
|
+
*/
|
|
179
|
+
this.state = state;
|
|
180
|
+
|
|
176
181
|
this.message = event.message || null;
|
|
177
182
|
|
|
178
|
-
|
|
183
|
+
let usePostBack;
|
|
184
|
+
if (!event.postback) {
|
|
185
|
+
usePostBack = null;
|
|
186
|
+
} else if (this.postBackHasObscuredPayload()) {
|
|
187
|
+
const { payload, ...rest } = event.postback;
|
|
188
|
+
usePostBack = {
|
|
189
|
+
payload: state[`_PB${event.postback.payload}`],
|
|
190
|
+
...rest
|
|
191
|
+
};
|
|
192
|
+
} else {
|
|
193
|
+
usePostBack = event.postback;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this.postback = usePostBack;
|
|
179
197
|
|
|
180
198
|
this.referral = (this.postback && this.postback.referral)
|
|
181
199
|
|| event.referral
|
|
@@ -209,11 +227,6 @@ class Request {
|
|
|
209
227
|
*/
|
|
210
228
|
this.pageId = pageId;
|
|
211
229
|
|
|
212
|
-
/**
|
|
213
|
-
* @type {S} current state of the conversation
|
|
214
|
-
*/
|
|
215
|
-
this.state = state;
|
|
216
|
-
|
|
217
230
|
/**
|
|
218
231
|
* @type {string[]} features supported messaging features
|
|
219
232
|
*/
|
|
@@ -292,6 +305,11 @@ class Request {
|
|
|
292
305
|
this.configuration = configuration;
|
|
293
306
|
}
|
|
294
307
|
|
|
308
|
+
postBackHasObscuredPayload () {
|
|
309
|
+
return typeof this._event.postback?.payload === 'string'
|
|
310
|
+
&& this.state?.[`_PB${this._event.postback.payload}`];
|
|
311
|
+
}
|
|
312
|
+
|
|
295
313
|
/**
|
|
296
314
|
* @returns {LLMDispatcher}
|
|
297
315
|
*/
|
|
@@ -1335,10 +1353,12 @@ It looks like the bot isn't connected to class BotApp or the Processor is used w
|
|
|
1335
1353
|
features = [FEATURE_TEXT]
|
|
1336
1354
|
) {
|
|
1337
1355
|
const postback = {
|
|
1338
|
-
payload:
|
|
1339
|
-
action
|
|
1340
|
-
|
|
1341
|
-
|
|
1356
|
+
payload: data === null
|
|
1357
|
+
? action
|
|
1358
|
+
: {
|
|
1359
|
+
action,
|
|
1360
|
+
data
|
|
1361
|
+
}
|
|
1342
1362
|
};
|
|
1343
1363
|
if (refAction) {
|
|
1344
1364
|
Object.assign(postback, {
|
|
@@ -1532,10 +1552,12 @@ It looks like the bot isn't connected to class BotApp or the Processor is used w
|
|
|
1532
1552
|
message: {
|
|
1533
1553
|
text: action,
|
|
1534
1554
|
quick_reply: {
|
|
1535
|
-
payload:
|
|
1536
|
-
action
|
|
1537
|
-
|
|
1538
|
-
|
|
1555
|
+
payload: data === null
|
|
1556
|
+
? action
|
|
1557
|
+
: JSON.stringify({
|
|
1558
|
+
action,
|
|
1559
|
+
data
|
|
1560
|
+
})
|
|
1539
1561
|
}
|
|
1540
1562
|
}
|
|
1541
1563
|
};
|
package/src/Responder.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
|
+
const crypto = require('crypto');
|
|
6
7
|
const Ai = require('./Ai');
|
|
7
8
|
const ReceiptTemplate = require('./templates/ReceiptTemplate');
|
|
8
9
|
const ButtonTemplate = require('./templates/ButtonTemplate');
|
|
@@ -944,17 +945,36 @@ class Responder {
|
|
|
944
945
|
};
|
|
945
946
|
}
|
|
946
947
|
|
|
947
|
-
if (qrs.length
|
|
948
|
-
|
|
949
|
-
Object.assign(messageData.message, {
|
|
950
|
-
quick_replies: qrs
|
|
951
|
-
});
|
|
952
|
-
|
|
953
|
-
this._addExpectedIntents(expectedKeywords);
|
|
954
|
-
this._quickReplyCollector = [];
|
|
948
|
+
if (qrs.length === 0) {
|
|
949
|
+
return qrs;
|
|
955
950
|
}
|
|
956
951
|
|
|
957
|
-
|
|
952
|
+
const qrsPaylMap = {};
|
|
953
|
+
|
|
954
|
+
const mappedQrs = qrs.map((qr, i) => {
|
|
955
|
+
if (!qr.payload) {
|
|
956
|
+
return qr;
|
|
957
|
+
}
|
|
958
|
+
const payload = crypto.randomBytes(16).toString('hex') + (i % 36).toString(36);
|
|
959
|
+
qrsPaylMap[payload] = qr.payload;
|
|
960
|
+
return {
|
|
961
|
+
...qr,
|
|
962
|
+
payload
|
|
963
|
+
};
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
this.setState({
|
|
967
|
+
_qrsPaylMap: qrsPaylMap
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
this.finalMessageSent = true;
|
|
971
|
+
Object.assign(messageData.message, {
|
|
972
|
+
quick_replies: mappedQrs
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
this._addExpectedIntents(expectedKeywords);
|
|
976
|
+
this._quickReplyCollector = [];
|
|
977
|
+
return mappedQrs;
|
|
958
978
|
}
|
|
959
979
|
|
|
960
980
|
/**
|
|
@@ -1697,7 +1717,8 @@ class Responder {
|
|
|
1697
1717
|
*/
|
|
1698
1718
|
button (text) {
|
|
1699
1719
|
const btn = new ButtonTemplate(
|
|
1700
|
-
(payload) => {
|
|
1720
|
+
(payload, setState) => {
|
|
1721
|
+
this.setState(setState);
|
|
1701
1722
|
this._textResponses.push(text);
|
|
1702
1723
|
this.template(payload);
|
|
1703
1724
|
},
|
|
@@ -1729,7 +1750,10 @@ class Responder {
|
|
|
1729
1750
|
*/
|
|
1730
1751
|
genericTemplate (shareable = false, isSquare = false) {
|
|
1731
1752
|
return new GenericTemplate(
|
|
1732
|
-
(payload) =>
|
|
1753
|
+
(payload, setState) => {
|
|
1754
|
+
this.setState(setState);
|
|
1755
|
+
this.template(payload);
|
|
1756
|
+
},
|
|
1733
1757
|
this._createContext(),
|
|
1734
1758
|
shareable,
|
|
1735
1759
|
isSquare
|
package/src/Tester.js
CHANGED
|
@@ -110,6 +110,7 @@ class Tester {
|
|
|
110
110
|
llm: {
|
|
111
111
|
...processorOptions.llm
|
|
112
112
|
},
|
|
113
|
+
allowRefs: true,
|
|
113
114
|
...processorOptions
|
|
114
115
|
}));
|
|
115
116
|
|
|
@@ -248,7 +249,9 @@ class Tester {
|
|
|
248
249
|
messageSender.simulatesOptIn = true;
|
|
249
250
|
|
|
250
251
|
const res = await this.processor
|
|
251
|
-
.processMessage(message, pageId, messageSender, {
|
|
252
|
+
.processMessage(message, pageId, messageSender, {
|
|
253
|
+
passPostbacks: false, ...data, ...this.testData
|
|
254
|
+
});
|
|
252
255
|
this._acquireResponseActions(res, messageSender);
|
|
253
256
|
|
|
254
257
|
return res;
|
|
@@ -290,7 +293,7 @@ class Tester {
|
|
|
290
293
|
assert.fail(`Response ${index} does not exists. There are ${this.responses.length} responses`);
|
|
291
294
|
}
|
|
292
295
|
|
|
293
|
-
return new ResponseAssert(this.responses[index]);
|
|
296
|
+
return new ResponseAssert(this.responses[index], this.getState());
|
|
294
297
|
}
|
|
295
298
|
|
|
296
299
|
/**
|
|
@@ -301,7 +304,7 @@ class Tester {
|
|
|
301
304
|
* @memberOf Tester
|
|
302
305
|
*/
|
|
303
306
|
any () {
|
|
304
|
-
return new AnyResponseAssert(this.responses);
|
|
307
|
+
return new AnyResponseAssert(this.responses, this.getState());
|
|
305
308
|
}
|
|
306
309
|
|
|
307
310
|
/**
|
|
@@ -315,7 +318,7 @@ class Tester {
|
|
|
315
318
|
if (this.responses.length === 0) {
|
|
316
319
|
assert.fail('Theres no response');
|
|
317
320
|
}
|
|
318
|
-
return new ResponseAssert(this.responses[this.responses.length - 1]);
|
|
321
|
+
return new ResponseAssert(this.responses[this.responses.length - 1], this.getState());
|
|
319
322
|
}
|
|
320
323
|
|
|
321
324
|
_actionMatches (botAction, path) {
|
|
@@ -612,7 +615,7 @@ class Tester {
|
|
|
612
615
|
quickReply (action, data = {}) {
|
|
613
616
|
if (this.responses.length !== 0) {
|
|
614
617
|
const last = this.responses[this.responses.length - 1];
|
|
615
|
-
const quickReplys = asserts.getQuickReplies(last);
|
|
618
|
+
const quickReplys = asserts.getQuickReplies(last, this.getState());
|
|
616
619
|
const res = quickReplys
|
|
617
620
|
.filter((reply) => {
|
|
618
621
|
const { action: route } = parseActionPayload(reply, true);
|
|
@@ -620,8 +623,10 @@ class Tester {
|
|
|
620
623
|
});
|
|
621
624
|
|
|
622
625
|
if (res[0]) {
|
|
623
|
-
const { title, payload } = res[0];
|
|
624
|
-
return this.processMessage(
|
|
626
|
+
const { title, payload, _origPayload: origPayload } = res[0];
|
|
627
|
+
return this.processMessage(
|
|
628
|
+
Request.quickReplyText(this.senderId, title, origPayload || payload)
|
|
629
|
+
);
|
|
625
630
|
}
|
|
626
631
|
}
|
|
627
632
|
|
|
@@ -38,6 +38,8 @@ class BaseTemplate {
|
|
|
38
38
|
Object.assign(this.context, context);
|
|
39
39
|
|
|
40
40
|
this._t = this.context.translator;
|
|
41
|
+
|
|
42
|
+
this._setState = {};
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
getTemplate () {
|
|
@@ -45,7 +47,7 @@ class BaseTemplate {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
send () {
|
|
48
|
-
this.onDone(this.getTemplate());
|
|
50
|
+
this.onDone(this.getTemplate(), this._setState);
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
_imageUrl (image) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
|
+
const crypto = require('crypto');
|
|
6
7
|
const BaseTemplate = require('./BaseTemplate');
|
|
7
8
|
const { makeAbsolute } = require('../utils');
|
|
8
9
|
|
|
@@ -138,7 +139,7 @@ class ButtonTemplate extends BaseTemplate {
|
|
|
138
139
|
_createPayload (action, data, setState = null) {
|
|
139
140
|
const hasSetState = setState && Object.keys(setState).length !== 0;
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
const actionData = JSON.stringify({
|
|
142
143
|
action: makeAbsolute(action, this.context.path),
|
|
143
144
|
data: {
|
|
144
145
|
_ca: this.context.currentAction,
|
|
@@ -146,6 +147,17 @@ class ButtonTemplate extends BaseTemplate {
|
|
|
146
147
|
},
|
|
147
148
|
...(hasSetState ? { setState } : {})
|
|
148
149
|
});
|
|
150
|
+
|
|
151
|
+
const payload = crypto
|
|
152
|
+
.createHash('shake256', { outputLength: 16 })
|
|
153
|
+
.update(actionData)
|
|
154
|
+
.digest('hex');
|
|
155
|
+
|
|
156
|
+
Object.assign(this._setState, {
|
|
157
|
+
[`_PB${payload}`]: actionData
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return payload;
|
|
149
161
|
}
|
|
150
162
|
|
|
151
163
|
/**
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
const ButtonTemplate = require('./ButtonTemplate');
|
|
7
|
-
const { makeAbsolute } = require('../utils');
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Generic template utility
|
|
@@ -84,19 +83,10 @@ class GenericTemplate extends ButtonTemplate {
|
|
|
84
83
|
* @memberOf GenericTemplate
|
|
85
84
|
*/
|
|
86
85
|
setElementActionPostback (action, data = {}, setState = null) {
|
|
87
|
-
const hasSetState = setState && Object.keys(setState).length !== 0;
|
|
88
|
-
|
|
89
86
|
Object.assign(this._element, {
|
|
90
87
|
default_action: {
|
|
91
88
|
type: 'postback',
|
|
92
|
-
payload:
|
|
93
|
-
action: makeAbsolute(action, this.context.path),
|
|
94
|
-
data: {
|
|
95
|
-
_ca: this.context.currentAction,
|
|
96
|
-
...data
|
|
97
|
-
},
|
|
98
|
-
...(hasSetState ? { setState } : {})
|
|
99
|
-
})
|
|
89
|
+
payload: this._createPayload(action, data, setState)
|
|
100
90
|
}
|
|
101
91
|
});
|
|
102
92
|
return this;
|
|
@@ -15,8 +15,9 @@ const m = asserts.ex;
|
|
|
15
15
|
*/
|
|
16
16
|
class AnyResponseAssert {
|
|
17
17
|
|
|
18
|
-
constructor (responses = []) {
|
|
18
|
+
constructor (responses = [], state = {}) {
|
|
19
19
|
this.responses = responses;
|
|
20
|
+
this.state = state;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -69,10 +70,10 @@ class AnyResponseAssert {
|
|
|
69
70
|
*/
|
|
70
71
|
quickReplyAction (action) {
|
|
71
72
|
const ok = this.responses
|
|
72
|
-
.some((res) => asserts.quickReplyAction(res, action, false));
|
|
73
|
+
.some((res) => asserts.quickReplyAction(res, action, false, this.state));
|
|
73
74
|
if (!ok) {
|
|
74
75
|
const actual = this.responses
|
|
75
|
-
.map((res) => asserts.getQuickReplies(res))
|
|
76
|
+
.map((res) => asserts.getQuickReplies(res, this.state))
|
|
76
77
|
.filter((replies) => !!replies)
|
|
77
78
|
.reduce((a, replies) => {
|
|
78
79
|
for (const reply of replies) {
|
|
@@ -98,10 +99,10 @@ class AnyResponseAssert {
|
|
|
98
99
|
*/
|
|
99
100
|
quickReplyTextContains (search) {
|
|
100
101
|
const ok = this.responses
|
|
101
|
-
.some((res) => asserts.quickReplyText(res, search, false));
|
|
102
|
+
.some((res) => asserts.quickReplyText(res, search, false, this.state));
|
|
102
103
|
if (!ok) {
|
|
103
104
|
const actual = this.responses
|
|
104
|
-
.map((res) => asserts.getQuickReplies(res))
|
|
105
|
+
.map((res) => asserts.getQuickReplies(res, this.state))
|
|
105
106
|
.filter((replies) => !!replies)
|
|
106
107
|
.reduce((a, replies) => {
|
|
107
108
|
for (const { title } of replies) {
|
|
@@ -12,8 +12,9 @@ const asserts = require('./asserts');
|
|
|
12
12
|
*/
|
|
13
13
|
class ResponseAssert {
|
|
14
14
|
|
|
15
|
-
constructor (response = {}) {
|
|
15
|
+
constructor (response = {}, state = {}) {
|
|
16
16
|
this.response = response;
|
|
17
|
+
this.state = state;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
waiting () {
|
|
@@ -43,7 +44,7 @@ class ResponseAssert {
|
|
|
43
44
|
* @memberOf ResponseAssert
|
|
44
45
|
*/
|
|
45
46
|
quickReplyAction (action) {
|
|
46
|
-
asserts.quickReplyAction(this.response, action);
|
|
47
|
+
asserts.quickReplyAction(this.response, action, undefined, this.state);
|
|
47
48
|
return this;
|
|
48
49
|
}
|
|
49
50
|
|
package/src/testTools/asserts.js
CHANGED
|
@@ -65,8 +65,20 @@ function getText (response) {
|
|
|
65
65
|
return null;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
function getQuickReplies (response) {
|
|
69
|
-
|
|
68
|
+
function getQuickReplies (response, state = {}) {
|
|
69
|
+
const { state: { _qrsPaylMap: qrMap = {} } = {} } = state;
|
|
70
|
+
const qrs = (response.message && response.message.quick_replies) || [];
|
|
71
|
+
return qrs.map((qr) => {
|
|
72
|
+
// eslint-disable-next-line prefer-const
|
|
73
|
+
let { payload, ...rst } = qr;
|
|
74
|
+
if (!payload) return rst;
|
|
75
|
+
if (qrMap[payload]) payload = qrMap[payload];
|
|
76
|
+
return {
|
|
77
|
+
_origPayload: qr.payload,
|
|
78
|
+
...rst,
|
|
79
|
+
payload
|
|
80
|
+
};
|
|
81
|
+
});
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
function getAttachment (response) {
|
|
@@ -187,10 +199,11 @@ function llmContains (llmMsg, search, message = 'Should contain a text') {
|
|
|
187
199
|
* @param {object} response
|
|
188
200
|
* @param {string} action
|
|
189
201
|
* @param {string|false} [message='Should contain the action'] - use false for no asserts
|
|
202
|
+
* @param {{}} [state={}] - bot state to replace qrs
|
|
190
203
|
* @returns {boolean}
|
|
191
204
|
*/
|
|
192
|
-
function quickReplyAction (response, action, message = 'Should contain the action') {
|
|
193
|
-
const replies = getQuickReplies(response);
|
|
205
|
+
function quickReplyAction (response, action, message = 'Should contain the action', state = {}) {
|
|
206
|
+
const replies = getQuickReplies(response, state);
|
|
194
207
|
const hasItems = replies.length > 0;
|
|
195
208
|
if (message === false && !hasItems) {
|
|
196
209
|
return false;
|