wingbot 3.76.15 → 3.76.17
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 +25 -4
- package/src/Request.js +25 -5
- 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
|
@@ -116,6 +116,8 @@ const LLMDispatcher = require('./LLMDispatcher');
|
|
|
116
116
|
* @prop {number} [sessionDuration] - Session duration for analytic purposes
|
|
117
117
|
* @prop {LLMGlobalConfig} [llm] - LLM model configuration
|
|
118
118
|
* @prop {Preloader<R>} [preloader]
|
|
119
|
+
* @prop {string[]} [allowedPostBacks]
|
|
120
|
+
* @prop {boolean} [allowRefs]
|
|
119
121
|
*/
|
|
120
122
|
|
|
121
123
|
/**
|
|
@@ -208,7 +210,9 @@ class Processor extends EventEmitter {
|
|
|
208
210
|
autoSeen: false,
|
|
209
211
|
redirectLimit: 20,
|
|
210
212
|
nameFromState: NAME_FROM_STATE,
|
|
211
|
-
sessionDuration: 1800000 // 30 minutes
|
|
213
|
+
sessionDuration: 1800000, // 30 minutes,
|
|
214
|
+
allowedPostBacks: [],
|
|
215
|
+
allowRefs: false
|
|
212
216
|
};
|
|
213
217
|
|
|
214
218
|
Object.assign(this.options, options);
|
|
@@ -533,8 +537,9 @@ class Processor extends EventEmitter {
|
|
|
533
537
|
? Request.text('none', text)
|
|
534
538
|
: text;
|
|
535
539
|
// @ts-ignore
|
|
536
|
-
const dispatcher = new LLMDispatcher(Ai.ai, this.reducer.routing, {
|
|
537
|
-
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
|
|
538
543
|
});
|
|
539
544
|
const req = new Request(request, { lang }, pageId, dispatcher);
|
|
540
545
|
await dispatcher.dispatch(req);
|
|
@@ -641,7 +646,8 @@ class Processor extends EventEmitter {
|
|
|
641
646
|
}
|
|
642
647
|
|
|
643
648
|
const dispatcher = new LLMDispatcher(Ai.ai, this.reducer.routing, llm, {
|
|
644
|
-
log: this.options.log
|
|
649
|
+
log: this.options.log,
|
|
650
|
+
allowRefs: this.options.allowRefs
|
|
645
651
|
});
|
|
646
652
|
req = new Request(
|
|
647
653
|
message,
|
|
@@ -657,6 +663,21 @@ class Processor extends EventEmitter {
|
|
|
657
663
|
configuration
|
|
658
664
|
);
|
|
659
665
|
|
|
666
|
+
const reqActionNorm = req.action()?.replace(/^\/?/, '/');
|
|
667
|
+
if (req.isPostBack()
|
|
668
|
+
&& fromEvent
|
|
669
|
+
&& reqActionNorm
|
|
670
|
+
&& !responderData.passPostbacks
|
|
671
|
+
&& this.options.allowedPostBacks.length > 0
|
|
672
|
+
&& !req.postBackHasObscuredPayload()
|
|
673
|
+
&& !this.options.allowedPostBacks.some((pb) => {
|
|
674
|
+
const norm = pb.replace(/^\/?/, '/');
|
|
675
|
+
return norm === reqActionNorm;
|
|
676
|
+
})) {
|
|
677
|
+
|
|
678
|
+
throw Object.assign(new Error(`Invalid postback error "${req.action()}"`), { code: 400 });
|
|
679
|
+
}
|
|
680
|
+
|
|
660
681
|
// process session
|
|
661
682
|
if (fromEvent) {
|
|
662
683
|
let {
|
package/src/Request.js
CHANGED
|
@@ -175,7 +175,20 @@ class Request {
|
|
|
175
175
|
|
|
176
176
|
this.message = event.message || null;
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
let usePostBack;
|
|
179
|
+
if (!event.postback) {
|
|
180
|
+
usePostBack = null;
|
|
181
|
+
} else if (this.postBackHasObscuredPayload()) {
|
|
182
|
+
const { payload, ...rest } = event.postback;
|
|
183
|
+
usePostBack = {
|
|
184
|
+
payload: state[`_PB${event.postback.payload}`],
|
|
185
|
+
...rest
|
|
186
|
+
};
|
|
187
|
+
} else {
|
|
188
|
+
usePostBack = event.postback;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.postback = usePostBack;
|
|
179
192
|
|
|
180
193
|
this.referral = (this.postback && this.postback.referral)
|
|
181
194
|
|| event.referral
|
|
@@ -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
|
*/
|
|
@@ -1532,10 +1550,12 @@ It looks like the bot isn't connected to class BotApp or the Processor is used w
|
|
|
1532
1550
|
message: {
|
|
1533
1551
|
text: action,
|
|
1534
1552
|
quick_reply: {
|
|
1535
|
-
payload:
|
|
1536
|
-
action
|
|
1537
|
-
|
|
1538
|
-
|
|
1553
|
+
payload: data === null
|
|
1554
|
+
? action
|
|
1555
|
+
: JSON.stringify({
|
|
1556
|
+
action,
|
|
1557
|
+
data
|
|
1558
|
+
})
|
|
1539
1559
|
}
|
|
1540
1560
|
}
|
|
1541
1561
|
};
|
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;
|