gratifyguy / botkit-mock Goto Github PK
View Code? Open in Web Editor NEWWrite tests for Botkit.
License: MIT License
Write tests for Botkit.
License: MIT License
It would be great if this mock library could also support the replyAndUpdate
function from botkit.
Thanks for the library!
I usually would like to set depends on the callback function of hears.
botkit-mock/lib/BotmockWorker.js
Line 106 in 40179b2
is this library still maintained? i am using the your test framework to test against slack. Wondering if i can add bot.whisper to your interface as i am using it and its part of botkit now
Hi,
I am struggling to setup a test for the example skill (I found it here) below. Currently I am trying to get into the Conversation Testing Thing. I also checked your convo-tests but did not succeed. Can you please help me?
module.exports = function(controller) {
controller.hears(['cookies'], 'message_received', function(bot, message) {
bot.startConversation(message, function(err, convo) {
if (!err) {
// if the user does not answer within this time, we end the conversation
convo.setTimeout(5000);
convo.say('Did someone say cookies!?!!');
convo.ask('What is your favorite type of cookie?', function(response, convo) {
convo.say(`Golly, I love ${response.text} too!!!`);
convo.next();
});
}
});
});
};
Hi folks,
Botkit 4.5.
Noticed while trying to build out integration tests that we kept getting a little blurb like this:
{ Error: An API error occurred: invalid_auth at Object.platformErrorFromResult (.../@slack/web-api/dist/errors.js:50:33) at WebClient.apiCall (.../node_modules/@slack/web-api/dist/WebClient.js:407:28) at process._tickCallback (internal/process/next_tick.js:68:7) code: 'slack_webapi_platform_error', data: { ok: false, error: 'invalid_auth', response_metadata: {} } }
I was able to remove this invalid_auth by stubbing out WebClient.prototype.makeRequest BEFORE the instantiation of the SlackAdapter with fake information. Wondering if the @slack/web-api dependency in botbuilder-adapter-slack has been accomodated for (or there are plans to) in this library?
In https://github.com/gratifyguy/botkit-mock/blob/master/examples/convo-bot/indexController.js lines 2 and 3 and 33-43 should be indented one less.
Hi guys,
I have again a question. How can I test (no clue yet) features of the Facebook Bot, such as this onecontroller.api.messenger_profile.get_messenger_code
(there are other controller.api.*
features as well).
Based on the examples of you readme, I was not able to run a test like this:
it('the bot\'s get_messenger_code should be a function', () => {
this.controller.api.messenger_profile.get_messenger_code.should.be.a.Function();
});
This is the skill (basically the example from the botkit repo):
module.exports = function(controller) {
// returns the bot's messenger code image
controller.hears(['code'], 'message_received,facebook_postback', function(bot, message) {
controller.api.messenger_profile.get_messenger_code(2000, function(err, url) {
if (!err) {
const image = {
attachment: {
type: 'image',
payload: {
url,
},
},
};
bot.replyWithTyping(message, image);
}
});
});
};
How to test conversations, I have a controller which asks the ques to user on "Who am I", if user haven't already given his name asks the user his name, Then if user provides the name then it confirms with user and then it ends the conversation. Is it possible to test conversations, any leads would be really helpful.
Pseudo Code
controller.hears("who am i", function(bot, message)) {
bot.startConversation(message, function(err, convo) {
convo.ask('What should I call you?', function(response, convo) {
convo.ask('You want me to call you `' + response.text + '`?', [
{
pattern: 'yes',
callback: function(response, convo) {
convo.next();
}
},
{
pattern: 'no',
callback: function(response, convo) {
convo.stop();
}
},
{
default: true,
callback: function(response, convo) {
convo.repeat();
convo.next();
}
}
]);
convo.next();
}, {'key': 'nickname'}); // store the results in a field called nickname
convo.on('end', function(convo) {
//Some odd logic here
}
});
}
Seems similar to #28 for Facebook. bot.identity
doesn't appear to be mocked so when I try to use it, I get a Slack API auth error because it's trying to use the Slack API with my dummy test credentials.
I keep getting undefined
for message.text
.
This is my code:
const assert = require('assert')
const botmock = require('botkit-mock')
const skill = require('../../server/skills/profile')
describe('[skill]: profile', function () {
afterEach(function () {
this.controller.shutdown()
})
beforeEach(function () {
this.userInfo = {
slackId: 'user123',
channel: 'channel123'
}
this.controller = botmock({
stats_optout: true,
debug: false
})
this.bot = this.controller.spawn({
type: 'slack'
})
skill(this.controller)
})
describe('hears profile', function () {
beforeEach(function () {
this.term = 'profile'
})
describe('as direct message', function () {
beforeEach(function() {
this.sequence = [
{
type: 'direct_message',
user: this.userInfo.slackId,
channel: this.userInfo.channel,
messages: [
{
text: this.term,
isAssertion: true
}
]
}
]
})
describe('with [1] trigger and [1] convos', function () {
beforeEach(function () {
this.bot.receive({ type: 'heard_trigger' })
this.bot.receive({type: 'conversationStarted'})
})
it (`should return text: "Here's your preferences"`, function () {
return this.bot.usersInput(this.sequence).then((message) => {
console.log(this)
return assert.equal(
message.text.indexOf(`Here's your profile preferences`) > -1,
true
)
})
})
})
})
})
})
Did I miss anything? I'm following the botkit-starter-slack example
You messed up the initialUserMessage() method in line 146 of BotMock, so it does not work with actual regular expressions. You take a RegEx, convert it into a String and then convert it back to a RegEx. So if I use a RegEx: /someRegEx/ it is converted to //someRegEx//i.
So I solved it like this:
let p = obj.pattern;
if (Array.isArray(obj.pattern)) {
for (let i = 0;i < p.length;i++) {
if ((message.text || message).match(new RegExp(p[i], 'i'))) {
message.match = (message.text || message).match(p);
return (message.text || message).match(new RegExp(p[i], 'i'));
}
}
} else {
if ((message.text || message).match(new RegExp(p, 'i'))) {
message.match = (message.text || message).match(new RegExp(p, 'i'))
}
}
return (message.text || message).match(new RegExp(p, 'i'));
BotMock.js does not support simple_storage:
If you want to support that just add the simple_storage.js to your requirements, then you only have to add:
memory_store: {
users: {
},
channels: {
},
teams: {
},
}
to line 11:
line 11:
this.botkit = {
tasks: [],
log: function(){}
};
Additionally, if you want to access the storage with your Bot you have to add the team_id or user_id to the call back:
See this example:
add
this.convo.sourceMessage.username = message.username;
to
this.convo.sourceMessage.user = message.user;
this.convo.sourceMessage.channel = message.user;
in line line 77, 78
and
to line 245
channel: this.sourceMessage.channel
add:
user: this.sourceMessage.username
Would it possible to silent debug messages when you use BotMock with a testing framework like mocha?
Hi guys.
Manually updating the botkit dependency to the most recent version squishes botkit-mock
and it rejects running tests. And of course, testing my bot's skills with the old version defeats the purpose.
How can I help get this going for the new version of Botkit? You guys already working on it?
In this repo, you have no license listed, but on npm you have MIT.
https://www.npmjs.com/package/botkit-mock
Can you sort out a license for this repo, please?
Hi
It would be nice if you provided a complete working example of using your mock with. Can it be used with jasmine?
No issue, just a question. Thanks!
I'm trying to create test cases for a predefined dialog I've created with botkit.
The dialog creation code, in botkit's main file (bot.js
) looks a bit like this -
function createServiceDialog() {
const MY_DIALOG_ID = 'my-dialog-name-constant';
let convo = new BotkitConversation(MY_DIALOG_ID, controller);
convo.say('Howdy!');
... // I've omitted most of the dialog for brevity's sake
}
controller.addDialog(createServiceDialog());
I later use this dialog like so -
const { SlackDialog } = require('botbuilder-adapter-slack');
const { BotkitConversation } = require('botkit');
const MY_DIALOG_ID = 'my-dialog-name-constant';
module.exports = function(controller) {
controller.hears('create_service', 'message', async(bot, message) => {
await bot.startConversationInThread(message.channel, message.user, message.incoming_message.channelData.ts);
await bot.beginDialog(MY_DIALOG_ID);
});
}
If I try testing this file with hard coded messages, the tests pass just fine.
When I try to use this predefined dialog, I'm getting the following error -
(node:62437) UnhandledPromiseRejectionWarning: Error: DialogContext.beginDialog(): A dialog with an id of 'my-dialog-name-constant:botkit-wrapper' wasn't found.
I've tried porting the dialog definition into the file being tested, but that didn't work nor felt like the right approach.
How should I go about implementing such a test case?
Oh, I almost forgot, here's the test suite I'm trying to execute -
'use strict';
const assert = require('assert');
const {BotMock, SlackApiMock} = require('botkit-mock');
const {SlackAdapter, SlackMessageTypeMiddleware, SlackEventMiddleware} = require('botbuilder-adapter-slack');
const fileBeingTested = require('../features/create_service');
async function setTimeoutAsync(timeout = 100) {
return new Promise((r) => setTimeout(r, timeout));
}
describe('create_service file slack-feature', () => {
const initController = () => {
const adapter = new SlackAdapter({
clientSigningSecret: "some secret",
botToken: "some token",
debug: true,
});
adapter.use(new SlackEventMiddleware());
adapter.use(new SlackMessageTypeMiddleware());
this.controller = new BotMock({
adapter: adapter,
});
SlackApiMock.bindMockApi(this.controller);
fileBeingTested(this.controller);
};
beforeEach(() => {
this.userInfo = {
slackId: 'user123',
channel: 'channel123',
};
});
describe('create_service', () => {
beforeEach(() => {
initController();
});
it(`should reply in a correct sequence through message`, async () => {
const reply = await this.controller.usersInput([
{
type: 'message',
user: this.userInfo.slackId, //user required for each direct message
channel: this.userInfo.channel, // user channel required for direct message
messages: [
{
text: 'create_service',
isAssertion: true,
}
]
}
]);
assert.strictEqual(this.controller.detailed_answers[this.userInfo.channel][0].text, `Howdy!`);
});
});
});
Thanks!
I love the idea of this project. Is it going to be updated for bot.createConversation and other botkit 4.x changes?
If I run it as written I get the following:
Error: Resolution method is overspecified. Specify a callback or return a Promise; not both.
it('should return `help message` if user types `help`', (done)=>{
var self = this;
return self.controller.usersInput([{
first:true,
user: self.slackId,
messages:[{text: 'help', isAssertion:true}]
}]).then((text)=>{
assert.equal(text, 'help message')
done()
})
});
If I remove the done and just return the promise it's fine. Also, suggest adding a catch and return rejection or you miss out on important errors
it('should return `help message` if user types `help`', ()=>{
var self = this;
return self.controller.usersInput([{
first:true,
user: self.slackId,
messages:[{text: 'help', isAssertion:true}]
}])
.catch((err) => {
return Promise.reject(err);
}).then((text) => {
assert.equal(text, 'help message')
})
});
Hey everyone. Excellent work on this mock module.
I just try to use it and it seems that atm if I use replyWithTyping
it doesn't work.
Looking at the source code is not supported. Should I create a new PR or is it something you are currently working on?
Hey all,
I am building a bot for Microsoft environments via Botkit (since they now support the Bot Framework), but I am unsure of how to test properly. Do you mind providing me a very basic example? Thanks!
Hello,
Facebook messenger doesn't support direct mention, so when i want to test some facebook conversations with this awesome botkit-mock, i got this error :
// BotmockWorker.js:66 -> var direct_mention = new RegExp('^\<\@' + bot.identity.id + '\>', 'i');
TypeError: Cannot read property 'id' of undefined
In BotmockWorker.js you try to prune off the bot's name and trim whitespaces, in my case bot.identity is undefined so bot.identity.id throw an error.
// Example of code
beforeEach(() => {
let controller = Botmock({});
bot = controller.spawn({type: 'facebook'});
controller.hears(['hi'], 'direct_message', function(bot, message){
bot.startConversation(message, function(response, convo){
convo.ask('hello there', function(response, convo){
convo.say('..user typed any text after `hi`');
convo.ask('here a question', function(response, convo){
convo.say('here an answer');
convo.next();
});
convo.next();
});
})
});
});
it('should return `help message` if user types `help`', (done) => {
let sequence = [
{
type: null, // direct_message, message_received, interactive_message_callback, defaults to direct_message
user: 'someUserId', // this.userInfo.slackId
channel: 'someChannel', //his.userInfo.channel
messages:[
{
text: 'hi',
},
{
text: 'its true',
deep: 1,
isAssertion:true,
}
]
}
];
bot.usersInput(sequence).then((message) => {
console.log(message);
expect(message.text).toBe('help message');
done();
});
});
I am using Watson Conversation in my bot and 100ms timeout (hardcoded here) is not enough.
Manually editing the file to change timeout to 1000ms makes it work, but it makes all tests slower so it isn't a good solution.
Also I want to do some processing which takes multiple seconds before sending the response.
Would it be possible to handle messages with callback on reply instead of setting a timeout? That way quick responses would be processed quickly and slow responses would get more time without making everything slow.
would like to test how the bot hears the message ...
Hi guys,
We're trying to send multiple messages through a mock adapter. First message instantiates some controller events for interactive components, then we need to fake button pushes and assert against the way the bot responds. However, this.controller.detailed_answers
don't populate beyond the first message sent through the controller, and we've tried it several ways. Here's how we just tried it:
it("should respond with appropriate verbiage on thumbsup click", async () => {
this.middlewareStub.returns([{ answer: "This is a test response." }]);
const message = await this.controller.usersInput([
{
type: "message",
user: "someUserId",
channel: "someChannel",
ts: "1234.45",
messages: [
{
text: "A qna question?",
isAssertion: true
}
]
},
{
type: "block_actions",
user: "someUserId",
channel: "someChannel",
messages: [
{
actions: [{ action_id: "qna_answered_question_undefined" }],
response_url: "flerpity_floop",
isAssertion: true
}
]
}
]);
return assert.strictEqual(
JSON.stringify(
this.controller.detailed_answers.someChannel[1].channelData.blocks[1]
),
JSON.stringify("poop")
);
});
And we've also done it this way:
it("should respond with appropriate verbiage on thumbsup click", async () => {
this.middlewareStub.returns([{ answer: "This is a test response." }]);
const message = await this.controller.usersInput([
{
type: "message",
user: "someUserId",
channel: "someChannel",
ts: "1234.45",
messages: [
{
text: "A qna question?",
isAssertion: true
},
{
actions: [{ action_id: "qna_answered_question_undefined" }],
response_url: "flerpity_floop",
isAssertion: true
}
]
}
]);
return assert.strictEqual(
JSON.stringify(
this.controller.detailed_answers.someChannel[1].channelData.blocks[1]
),
JSON.stringify("poop")
);
});
We've also just plain ol' called this.controller.usersInput()
a second time with a message of type block_actions
with no effect.
What are we doing wrong? Happy to put this in SO if you prefer.
Would be nice if it was submitted to NPM so it could be properly versioned, auto-udpated as a dependency, simpler installation, etc. ๐ธ
I tried to setup the botkit-mock and I am a bit confused where "this" comes from
describe("controller tests",()=>{
beforeEach(()=>{
this.controller = Botmock({}); // is unndefined
I tried it also to just define controller and bot as variables in the test, but my testbot is still not responding.
Hi folks,
I'd like to be able to configure the baseUrl of the underlying Axios adapter (using axios-mock-adapter) so that it hits a local endpoint spun up to use yakbak, a VCR technology so I can stub out API requests. Is that possible? I'm looking through source and I'm not seeing anywhere without monkey patching the source. Thanks.
Hi! Please feel free to point me another direction, but I was reading through this project and interested in using it for a botkit project using Twilio, and I saw a note in the README asking about folks interested in adding support for other adapters. I'm only just reading so this issue is more a question/ ๐ . This looks like a very helpful library!
Currently the package.json specifies the 0.x line, which means if the application uses 4.x then two versions of botkit are installed. It would be great to permit use of the 4.x version to avoid this duplication and to shrink the size of node_modules
What I'm doing:
Calling this.controller.loadModule against a feature that I've created in Botkit 4.5 to instantiate a controller with its details.
What's I expect:
this.controller._events
should have registered events custom defined in a feature with controller.on(<event_name>)
What I get:
Not that. controller._events
is {}
.
maybe I'm missing something?
do you guys support mocking middlewares? it doesn't look like it right now, if not do you want to?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.