-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Testing other dialogues #77
Comments
It absolutely can! The tests were simple to demonstrate usage. If it's possible, I would create a clean instance of the bot for each test or collection of related tests, however this isn't absolutely necessary. If you want a full e2e test of a dialog, you could run an example like this: you could have a function that builds the conversation to that point and seed the relevant test with that. Try running some simple tests with your existing bot to get a feel for what it takes to test certain facets of your bot. It should be relatively straightforward. Lmk if this helps or you need any further insight. |
Hey Matthew,
Thanks for getting back to me. I've gotten some simple tests running and it
looks great. I'm struggling to find a way to use a separate file containing
my test scripts though. Have you done this and if so what would it look
like?
Thank you,
Mike
…On Wed, May 9, 2018 at 4:11 PM, Matthew Schwartz ***@***.***> wrote:
Closed #77 <#77>.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#77 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AWQn0rSoNoZFB7N1EtxY6_QMSYrG57UEks5tw016gaJpZM4T3Tar>
.
|
What do you mean by separate the file containing your tests? From what are you separating it? |
What I'm trying to do is organize our test questions and expected responses
separately in a csv or json file instead of placing them in the test script
within individual .sendMessageToBot functions.
Does that make sense?
…On Fri, May 11, 2018 at 2:05 PM, Matthew Schwartz ***@***.***> wrote:
What do you mean by separate the file containing your tests? From what are
you separating it?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#77 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AWQn0ujZaBOEp-OFoxNOWf-NYeEiYC8Xks5txdLXgaJpZM4T3Tar>
.
|
ahh. Yes. Here's a typescript snippet of a test data provider I wrote for a customer-agent handoff library const bot = {
id: 'bot',
name: 'Bot'
};
const channelId = 'test';
const AGENT_1_USER: IIdentity = {
id: 'agent1Id',
name: 'agent1'
};
const AGENT_2_USER: IIdentity = {
id: 'agent2Id',
name: 'agent2'
};
const AGENT_1_CONVO_1: IAddress = {
bot,
channelId,
user: AGENT_1_USER,
conversation: {
id: 'agent1Convo1'
}
};
const AGENT_1_CONVO_2: IAddress = {
bot,
channelId,
user: AGENT_1_USER,
conversation: {
id: 'agent1Convo2'
}
};
const AGENT_2_CONVO_1: IAddress = {
bot,
channelId,
user: AGENT_2_USER,
conversation: {
id: 'agent2Convo1'
}
};
const AGENT_2_CONVO_2: IAddress = {
bot,
channelId,
user: AGENT_2_USER,
conversation: {
id: 'agent2Convo2'
}
};
const CUSTOMER_1: IAddress = {
bot,
channelId,
user: {
id: 'customer1Id',
name: 'customer1'
},
conversation: {
id: 'customer1ConvoId'
}
};
const CUSTOMER_2: IAddress = {
bot,
channelId,
user: {
id: 'customer2Id',
name: 'customer2'
},
conversation: {
id: 'customer2ConvoId'
}
};
const CUSTOMER_1_MESSAGE_1 = new Message()
.text('customer 1 FIRST message')
.address(CUSTOMER_1)
.toMessage();
const CUSTOMER_2_MESSAGE_1 = new Message()
.text('customer 2 FIRST message')
.address(CUSTOMER_2)
.toMessage();
const CUSTOMER_1_MESSAGE_2 = new Message()
.text('customer 1 SECOND message')
.address(CUSTOMER_1)
.toMessage();
const CUSTOMER_2_MESSAGE_2 = new Message()
.text('customer 2 SECOND message')
.address(CUSTOMER_2)
.toMessage();
const CUSTOMER_1_MESSAGE_3 = new Message()
.text('customer 1 THIRD message')
.address(CUSTOMER_1)
.toMessage();
const CUSTOMER_2_MESSAGE_3 = new Message()
.text('customer 2 THIRD message')
.address(CUSTOMER_2)
.toMessage();
const AGENT_1_CONVO_1_MESSAGE_1 = new Message()
.text('agent 1 convo 1 FIRST message')
.address(AGENT_1_CONVO_1)
.toMessage();
const AGENT_1_CONVO_2_MESSAGE_1 = new Message()
.text('agent 1 convo 2 FIRST message')
.address(AGENT_1_CONVO_2)
.toMessage();
const AGENT_2_CONVO_1_MESSAGE_1 = new Message()
.text('agent 2 convo 1 FIRST message')
.address(AGENT_2_CONVO_1)
.toMessage();
const AGENT_2_CONVO_2_MESSAGE_1 = new Message()
.text('agent 2 convo 2 FIRST message')
.address(AGENT_2_CONVO_2)
.toMessage();
const AGENT_1_CONVO_1_MESSAGE_2 = new Message()
.text('agent 1 convo 1 SECOND message')
.address(AGENT_1_CONVO_1)
.toMessage();
const AGENT_1_CONVO_2_MESSAGE_2 = new Message()
.text('agent 1 convo 2 SECOND message')
.address(AGENT_1_CONVO_2)
.toMessage();
const AGENT_2_CONVO_1_MESSAGE_2 = new Message()
.text('agent 2 convo 1 SECOND message')
.address(AGENT_2_CONVO_1)
.toMessage();
const AGENT_2_CONVO_2_MESSAGE_2 = new Message()
.text('agent 2 convo 2 SECOND message')
.address(AGENT_2_CONVO_2)
.toMessage();
const AGENT_1_CONVO_1_MESSAGE_3 = new Message()
.text('agent 1 convo 1 THIRD message')
.address(AGENT_1_CONVO_1)
.toMessage();
const AGENT_1_CONVO_2_MESSAGE_3 = new Message()
.text('agent 1 convo 2 THIRD message')
.address(AGENT_1_CONVO_2)
.toMessage();
const AGENT_2_CONVO_1_MESSAGE_3 = new Message()
.text('agent 2 convo 1 THIRD message')
.address(AGENT_2_CONVO_1)
.toMessage();
const AGENT_2_CONVO_2_MESSAGE_3 = new Message()
.text('agent 2 convo 2 THIRD message')
.address(AGENT_2_CONVO_2)
.toMessage();
export function getExpectedReceivedMessage(originalMessage: IMessage, expectedAddress: IAddress): IMessage {
return Object.assign({}, originalMessage, { address: expectedAddress });
}
// tslint:disable
// I'm too lazy to build the return type for this ...
function getCustomerEventMessages(customerAddress: IAddress) {
// tslint:enable
return {
toQueue: new QueueEventMessage(customerAddress),
toDequeue: new DequeueEventMessage(customerAddress)
};
}
//tslint:disable
// I'm too lazy to type out the return type
function getAgentEventMessagesForConversation(convoAddress: IAddress) {
//tslint:enable
return {
toConnectTo: {
customer1: new ConnectEventMessage(CUSTOMER_1, convoAddress),
customer2: new ConnectEventMessage(CUSTOMER_2, convoAddress)
},
toDisconnectFrom: {
customer1: new DisconnectEventMessage(CUSTOMER_1, convoAddress),
customer2: new DisconnectEventMessage(CUSTOMER_2, convoAddress)
},
toWatch: {
customer1: new WatchEventMessage(CUSTOMER_1, convoAddress),
customer2: new WatchEventMessage(CUSTOMER_2, convoAddress)
},
toUnwatch: {
customer1: new UnwatchEventMessage(CUSTOMER_1, convoAddress),
customer2: new UnwatchEventMessage(CUSTOMER_2, convoAddress)
}
};
}
export const agent1 = {
user: AGENT_1_USER,
convo1: {
address: AGENT_1_CONVO_1,
message1: AGENT_1_CONVO_1_MESSAGE_1,
message2: AGENT_1_CONVO_1_MESSAGE_2,
message3: AGENT_1_CONVO_1_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_1_CONVO_1)
},
convo2: {
address: AGENT_1_CONVO_2,
message1: AGENT_1_CONVO_2_MESSAGE_1,
message2: AGENT_1_CONVO_2_MESSAGE_2,
message3: AGENT_1_CONVO_2_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_1_CONVO_2)
}
};
export const agent2 = {
user: AGENT_2_USER,
convo1: {
address: AGENT_2_CONVO_1,
message1: AGENT_2_CONVO_1_MESSAGE_1,
message2: AGENT_2_CONVO_1_MESSAGE_2,
message3: AGENT_2_CONVO_1_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_2_CONVO_1)
},
convo2: {
address: AGENT_2_CONVO_2,
message1: AGENT_2_CONVO_2_MESSAGE_1,
message2: AGENT_2_CONVO_2_MESSAGE_2,
message3: AGENT_2_CONVO_2_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_2_CONVO_2)
}
};
export const customer1 = {
address: CUSTOMER_1,
message1: CUSTOMER_1_MESSAGE_1,
message2: CUSTOMER_1_MESSAGE_2,
message3: CUSTOMER_1_MESSAGE_3,
eventMessage: getCustomerEventMessages(CUSTOMER_1)
};
export const customer2 = {
address: CUSTOMER_2,
message1: CUSTOMER_2_MESSAGE_1,
message2: CUSTOMER_2_MESSAGE_2,
message3: CUSTOMER_2_MESSAGE_3,
eventMessage: getCustomerEventMessages(CUSTOMER_2)
}; I use it like this: it('can handover to agents', async () => {
await new BotTester(bot, { defaultAddress: TestDataProvider.customer1.address })
.sendMessageToBotIgnoringResponseOrder(
new ConnectEventMessage(TestDataProvider.customer1.address, TestDataProvider.agent1.convo1.address))
.wait(EVENT_DELAY)
.sendMessageToBot(
TestDataProvider.agent1.convo1.message1,
TestDataProvider.getExpectedReceivedMessage(TestDataProvider.agent1.convo1.message1, TestDataProvider.customer1.address))
.sendMessageToBot(
TestDataProvider.customer1.message2,
TestDataProvider.getExpectedReceivedMessage(TestDataProvider.customer1.message2, TestDataProvider.agent1.convo1.address)
)
.runTest()
.then(() => providerSpy.getAllConversations())
.then((convos: IConversation[]) => {
convos.forEach((convo: IConversation) => {
expect(convo.transcript).not.to.be.empty;
});
});
}); |
Hmmm, You'll have to pardon me, my node is still fresh. Here's what I've
been trying to build so far. Maybe that'll help give you an idea of what
we're doing.
My Checker
function testBot(bot, messages, done) {
function checkStep(message) {
if(count < end -1) {
bot.sendMessageToBot(message.in,message.out)
console.log('THIS IS THE MESSAGE' + JSON.stringify(message))
} else {
console.log('ENDING THE ADDING')
bot.sendMessageToBot(message.in,message.out)
bot.runTest()
}
}
end = messages.length
count = 0
for(let i in messages) {
msg = messages[i]
console.log('count ' + count)
console.log('end ' + end)
console.log(count < end)
checkStep(msg)
count = count += 1
}
}
module.exports = {
testBot
};
My main file
const connector = new builder.ConsoleConnector()
describe('BotTester', () => {
before(function(done) {
Utils.populateMaps()
delay(12000)
.then(() => {
done();
})
})
bot = TestingBot.create(connector)
it('Testing stuff', () => {
const botTesterOptions = {
// the assertionLibrary field can be set in the bot-tester.json, but the
default is mocha/chai. It can be omitted if the desired assertion library
to use is chai.
assertionLibrary: 'chai',
// testContext is not used for chai expectations
}
const botTester = new BotTester(bot, botTesterOptions)
// .sendMessageToBot('jira orange tradeweb','Jira system:
https://support.iontrading.com/rest/api/2/search?jql=JQL: project in
("FICS") and cf[10021] in ("tradeweb")')
// return botTester.runTest()
testTools.testBot(botTester,newTest)
});
});
and How I'm reading in my test cases
module.exports = [
{
'in':'jira orange tradeweb',
'out':"Jira system: https://support.iontrading.com/rest/api/2/search?jql=JQL:
project in (FICS) and cf[10021] in (tradeweb)"
},
{
'in':'hello',
'out':'Hfowdy.'
}
]
Its running the test, but passing every time. Its not actually running my
cases.
Thanks,
Mike
…On Fri, May 11, 2018 at 2:12 PM, Matthew Schwartz ***@***.***> wrote:
ahh. Yes. Here's a typescript snippet of a test data provider I wrote for
a customer-agent handoff library
const bot = {
id: 'bot',
name: 'Bot'
};
const channelId = 'test';const AGENT_1_USER: IIdentity = {
id: 'agent1Id',
name: 'agent1'
};
const AGENT_2_USER: IIdentity = {
id: 'agent2Id',
name: 'agent2'
};
const AGENT_1_CONVO_1: IAddress = {
bot,
channelId,
user: AGENT_1_USER,
conversation: {
id: 'agent1Convo1'
}
};
const AGENT_1_CONVO_2: IAddress = {
bot,
channelId,
user: AGENT_1_USER,
conversation: {
id: 'agent1Convo2'
}
};
const AGENT_2_CONVO_1: IAddress = {
bot,
channelId,
user: AGENT_2_USER,
conversation: {
id: 'agent2Convo1'
}
};
const AGENT_2_CONVO_2: IAddress = {
bot,
channelId,
user: AGENT_2_USER,
conversation: {
id: 'agent2Convo2'
}
};
const CUSTOMER_1: IAddress = {
bot,
channelId,
user: {
id: 'customer1Id',
name: 'customer1'
},
conversation: {
id: 'customer1ConvoId'
}
};
const CUSTOMER_2: IAddress = {
bot,
channelId,
user: {
id: 'customer2Id',
name: 'customer2'
},
conversation: {
id: 'customer2ConvoId'
}
};
const CUSTOMER_1_MESSAGE_1 = new Message()
.text('customer 1 FIRST message')
.address(CUSTOMER_1)
.toMessage();
const CUSTOMER_2_MESSAGE_1 = new Message()
.text('customer 2 FIRST message')
.address(CUSTOMER_2)
.toMessage();
const CUSTOMER_1_MESSAGE_2 = new Message()
.text('customer 1 SECOND message')
.address(CUSTOMER_1)
.toMessage();
const CUSTOMER_2_MESSAGE_2 = new Message()
.text('customer 2 SECOND message')
.address(CUSTOMER_2)
.toMessage();
const CUSTOMER_1_MESSAGE_3 = new Message()
.text('customer 1 THIRD message')
.address(CUSTOMER_1)
.toMessage();
const CUSTOMER_2_MESSAGE_3 = new Message()
.text('customer 2 THIRD message')
.address(CUSTOMER_2)
.toMessage();
const AGENT_1_CONVO_1_MESSAGE_1 = new Message()
.text('agent 1 convo 1 FIRST message')
.address(AGENT_1_CONVO_1)
.toMessage();
const AGENT_1_CONVO_2_MESSAGE_1 = new Message()
.text('agent 1 convo 2 FIRST message')
.address(AGENT_1_CONVO_2)
.toMessage();
const AGENT_2_CONVO_1_MESSAGE_1 = new Message()
.text('agent 2 convo 1 FIRST message')
.address(AGENT_2_CONVO_1)
.toMessage();
const AGENT_2_CONVO_2_MESSAGE_1 = new Message()
.text('agent 2 convo 2 FIRST message')
.address(AGENT_2_CONVO_2)
.toMessage();
const AGENT_1_CONVO_1_MESSAGE_2 = new Message()
.text('agent 1 convo 1 SECOND message')
.address(AGENT_1_CONVO_1)
.toMessage();
const AGENT_1_CONVO_2_MESSAGE_2 = new Message()
.text('agent 1 convo 2 SECOND message')
.address(AGENT_1_CONVO_2)
.toMessage();
const AGENT_2_CONVO_1_MESSAGE_2 = new Message()
.text('agent 2 convo 1 SECOND message')
.address(AGENT_2_CONVO_1)
.toMessage();
const AGENT_2_CONVO_2_MESSAGE_2 = new Message()
.text('agent 2 convo 2 SECOND message')
.address(AGENT_2_CONVO_2)
.toMessage();
const AGENT_1_CONVO_1_MESSAGE_3 = new Message()
.text('agent 1 convo 1 THIRD message')
.address(AGENT_1_CONVO_1)
.toMessage();
const AGENT_1_CONVO_2_MESSAGE_3 = new Message()
.text('agent 1 convo 2 THIRD message')
.address(AGENT_1_CONVO_2)
.toMessage();
const AGENT_2_CONVO_1_MESSAGE_3 = new Message()
.text('agent 2 convo 1 THIRD message')
.address(AGENT_2_CONVO_1)
.toMessage();
const AGENT_2_CONVO_2_MESSAGE_3 = new Message()
.text('agent 2 convo 2 THIRD message')
.address(AGENT_2_CONVO_2)
.toMessage();
export function getExpectedReceivedMessage(originalMessage: IMessage, expectedAddress: IAddress): IMessage {
return Object.assign({}, originalMessage, { address: expectedAddress });
}
// tslint:disable// I'm too lazy to build the return type for this ...function getCustomerEventMessages(customerAddress: IAddress) {// tslint:enable return {
toQueue: new QueueEventMessage(customerAddress),
toDequeue: new DequeueEventMessage(customerAddress)
};
}
//tslint:disable// I'm too lazy to type out the return typefunction getAgentEventMessagesForConversation(convoAddress: IAddress) {//tslint:enable return {
toConnectTo: {
customer1: new ConnectEventMessage(CUSTOMER_1, convoAddress),
customer2: new ConnectEventMessage(CUSTOMER_2, convoAddress)
},
toDisconnectFrom: {
customer1: new DisconnectEventMessage(CUSTOMER_1, convoAddress),
customer2: new DisconnectEventMessage(CUSTOMER_2, convoAddress)
},
toWatch: {
customer1: new WatchEventMessage(CUSTOMER_1, convoAddress),
customer2: new WatchEventMessage(CUSTOMER_2, convoAddress)
},
toUnwatch: {
customer1: new UnwatchEventMessage(CUSTOMER_1, convoAddress),
customer2: new UnwatchEventMessage(CUSTOMER_2, convoAddress)
}
};
}
export const agent1 = {
user: AGENT_1_USER,
convo1: {
address: AGENT_1_CONVO_1,
message1: AGENT_1_CONVO_1_MESSAGE_1,
message2: AGENT_1_CONVO_1_MESSAGE_2,
message3: AGENT_1_CONVO_1_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_1_CONVO_1)
},
convo2: {
address: AGENT_1_CONVO_2,
message1: AGENT_1_CONVO_2_MESSAGE_1,
message2: AGENT_1_CONVO_2_MESSAGE_2,
message3: AGENT_1_CONVO_2_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_1_CONVO_2)
}
};
export const agent2 = {
user: AGENT_2_USER,
convo1: {
address: AGENT_2_CONVO_1,
message1: AGENT_2_CONVO_1_MESSAGE_1,
message2: AGENT_2_CONVO_1_MESSAGE_2,
message3: AGENT_2_CONVO_1_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_2_CONVO_1)
},
convo2: {
address: AGENT_2_CONVO_2,
message1: AGENT_2_CONVO_2_MESSAGE_1,
message2: AGENT_2_CONVO_2_MESSAGE_2,
message3: AGENT_2_CONVO_2_MESSAGE_3,
eventMessage: getAgentEventMessagesForConversation(AGENT_2_CONVO_2)
}
};
export const customer1 = {
address: CUSTOMER_1,
message1: CUSTOMER_1_MESSAGE_1,
message2: CUSTOMER_1_MESSAGE_2,
message3: CUSTOMER_1_MESSAGE_3,
eventMessage: getCustomerEventMessages(CUSTOMER_1)
};
export const customer2 = {
address: CUSTOMER_2,
message1: CUSTOMER_2_MESSAGE_1,
message2: CUSTOMER_2_MESSAGE_2,
message3: CUSTOMER_2_MESSAGE_3,
eventMessage: getCustomerEventMessages(CUSTOMER_2)
};
I use it like this:
it('can handover to agents', async () => {
await new BotTester(bot, { defaultAddress: TestDataProvider.customer1.address })
.sendMessageToBotIgnoringResponseOrder(
new ConnectEventMessage(TestDataProvider.customer1.address, TestDataProvider.agent1.convo1.address))
.wait(EVENT_DELAY)
.sendMessageToBot(
TestDataProvider.agent1.convo1.message1,
TestDataProvider.getExpectedReceivedMessage(TestDataProvider.agent1.convo1.message1, TestDataProvider.customer1.address))
.sendMessageToBot(
TestDataProvider.customer1.message2,
TestDataProvider.getExpectedReceivedMessage(TestDataProvider.customer1.message2, TestDataProvider.agent1.convo1.address)
)
.runTest()
.then(() => providerSpy.getAllConversations())
.then((convos: IConversation[]) => {
convos.forEach((convo: IConversation) => {
expect(convo.transcript).not.to.be.empty;
});
});
});
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#77 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AWQn0sswhFe-Jwp16XC_byWe19tKBMAfks5txdSogaJpZM4T3Tar>
.
|
Would you mind formatting? I'm having trouble reading it in it's current layout |
Hello,
We have a fairly complex bot set up with many dialogues, middleware, etc... I'd love a simple way of having a set of questions and answers that i can run through this test harness, but it appears as though every dialogue in the documentation is created inside of the harness. Is it straightforward to have the harness use the full extent of dialogues we've created?
Thanks
The text was updated successfully, but these errors were encountered: