Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: juice-shop/juicy-chat-bot
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e1e438fc2a2dd17df7886079ed1ca27795ca9c6e
Choose a base ref
...
head repository: juice-shop/juicy-chat-bot
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c841eb0c9c1cb31a3f07431212457a47ee6af436
Choose a head ref

Commits on Sep 7, 2020

  1. Copy the full SHA
    9fa4298 View commit details
  2. Auto-fix linting issues

    Signed-off-by: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com>
    JuiceShopBot committed Sep 7, 2020
    Copy the full SHA
    ea5c311 View commit details
  3. Copy the full SHA
    7de8942 View commit details
  4. Copy the full SHA
    107fd04 View commit details
  5. Copy the full SHA
    81afa9a View commit details

Commits on Nov 16, 2020

  1. strip down node-nlp

    Signed-off-by: Scar26 <mmatty26@gmail.com>
    Scar26 committed Nov 16, 2020
    Copy the full SHA
    7136340 View commit details
  2. Auto-fix linting issues

    Signed-off-by: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com>
    JuiceShopBot committed Nov 16, 2020
    Copy the full SHA
    8e8d832 View commit details
  3. remove builtin-microsoft and duckling dependencies

    Signed-off-by: Scar26 <mmatty26@gmail.com>
    Scar26 committed Nov 16, 2020
    Copy the full SHA
    3e9eb89 View commit details
  4. Merge pull request #11 from bkimminich/strip-nlp

    Extract relevant functions from node-nlp
    bkimminich authored Nov 16, 2020
    Copy the full SHA
    b68f404 View commit details
  5. Bump to v0.6.0

    bkimminich committed Nov 16, 2020
    Copy the full SHA
    6e62e01 View commit details

Commits on Dec 14, 2020

  1. Copy the full SHA
    62b764c View commit details
  2. Copy the full SHA
    d013fc6 View commit details
  3. Copy the full SHA
    816dee9 View commit details
  4. Copy the full SHA
    49bd973 View commit details
  5. Copy the full SHA
    114f6f5 View commit details
  6. Bump to v0.6.2

    bkimminich committed Dec 14, 2020
    Copy the full SHA
    213c64c View commit details
  7. Ignore release builds

    bkimminich committed Dec 14, 2020
    Copy the full SHA
    882d391 View commit details
  8. Bump to v0.6.3

    bkimminich committed Dec 14, 2020
    Copy the full SHA
    bae848f View commit details
  9. Copy the full SHA
    354507e View commit details
  10. Copy the full SHA
    6ebe615 View commit details
  11. Amend name of linting step

    bkimminich committed Dec 14, 2020
    Copy the full SHA
    5e38a4a View commit details

Commits on Dec 19, 2020

  1. Add copyright headers

    bkimminich committed Dec 19, 2020
    Copy the full SHA
    2b786c8 View commit details
  2. Copy the full SHA
    33425b0 View commit details

Commits on May 2, 2021

  1. Copy the full SHA
    0790670 View commit details
  2. Auto-fix linting issues

    Signed-off-by: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com>
    JuiceShopBot committed May 2, 2021
    Copy the full SHA
    b677c56 View commit details
  3. Copy the full SHA
    c3bae73 View commit details
  4. Auto-fix linting issues

    Signed-off-by: JuiceShopBot <61591748+JuiceShopBot@users.noreply.github.com>
    JuiceShopBot committed May 2, 2021
    Copy the full SHA
    c841eb0 View commit details
Showing with 560 additions and 62 deletions.
  1. +72 −0 .github/workflows/ci.yml
  2. +28 −0 .github/workflows/release.yml
  3. +0 −47 .travis.yml
  4. +1 −1 LICENSE
  5. +6 −5 README.md
  6. +5 −0 factory.js
  7. +6 −1 index.js
  8. +250 −0 nlp/index.js
  9. +48 −0 nlp/sentiment-analyzer.js
  10. +80 −0 nlp/sentiment.js
  11. +12 −7 package.json
  12. +52 −1 test/initialize-spec.js
72 changes: 72 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: "CI Pipeline"
on:
push:
branches:
- '*'
paths-ignore:
- '*.md'
- 'LICENSE'
tags-ignore:
- '*'
pull_request:
branches:
- develop
paths-ignore:
- '*.md'
- 'LICENSE'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: "Check out Git repository"
uses: actions/checkout@v2
- name: "Use Node.js 14"
uses: actions/setup-node@v1
with:
node-version: 14
- name: "Install application"
run: npm install --ignore-scripts
- name: "Lint code"
run: npm run lint
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10, 12, 14]
steps:
- name: "Check out Git repository"
uses: actions/checkout@v2
- name: "Use Node.js ${{ matrix.node-version }}"
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: "Cache Node.js modules"
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.OS }}-node-${{ hashFiles('**/package.json') }}
restore-keys: |
${{ runner.OS }}-node-
${{ runner.OS }}-
- name: "Install application"
run: npm install
- name: "Execute unit tests"
run: npm test
- name: "Publish coverage to Coveralls"
if: github.event_name == 'push' && matrix.node-version == '14'
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./build/reports/coverage/lcov.info
notify-slack:
if: github.event_name == 'push' && (success() || failure())
needs:
- lint
- test
runs-on: ubuntu-latest
steps:
- name: "Slack workflow notification"
uses: Gamesight/slack-workflow-status@master
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "Release Pipeline"
on:
push:
tags:
- v*
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 14
- run: npm install
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
notify-slack:
if: always()
needs:
- publish
runs-on: ubuntu-latest
steps:
- name: "Slack workflow notification"
uses: Gamesight/slack-workflow-status@master
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
47 changes: 0 additions & 47 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 Björn Kimminich
Copyright (c) 2020-2021 Björn Kimminich & the OWASP Juice Shop contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# ![Juice Shop CTF Logo](https://github.com/bkimminich/juicy-chat-bot/raw/master/JuicyChatBot.png) Juicy Chat Bot
# ![Juice Shop CTF Logo](https://github.com/juice-shop/juicy-chat-bot/raw/master/JuicyChatBot.png) Juicy Chat Bot

[![npm Downloads](https://img.shields.io/npm/dm/juicy-chat-bot.svg)](https://www.npmjs.com/package/juicy-chat-bot)
[![Build Status](https://travis-ci.com/bkimminich/juicy-chat-bot.svg?branch=master)](https://travis-ci.com/bkimminich/juicy-chat-bot)
[![Coverage Status](https://coveralls.io/repos/github/bkimminich/juicy-chat-bot/badge.svg?branch=master)](https://coveralls.io/github/bkimminich/juicy-chat-bot?branch=master)
[![CI Pipeline](https://github.com/juice-shop/juicy-chat-bot/actions/workflows/ci.yml/badge.svg)](https://github.com/juice-shop/juicy-chat-bot/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/juice-shop/juicy-chat-bot/badge.svg?branch=master)](https://coveralls.io/github/juice-shop/juicy-chat-bot?branch=master)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)

Smart, friendly and helpful chat bot for OWASP Juice Shop.

## Licensing [![license](https://img.shields.io/github/license/bkimminich/juicy-chat-bot.svg)](LICENSE)
## Licensing [![license](https://img.shields.io/github/license/juice-shop/juicy-chat-bot.svg)](LICENSE)

This program is free software: you can redistribute it and/or modify it
under the terms of the [MIT license](LICENSE). Juicy Chat Bot and any
contributions are Copyright © by Bjoern Kimminich 2020.
contributions are Copyright © by Bjoern Kimminich & the OWASP Juice Shop
contributors 2020-2021.

---

5 changes: 5 additions & 0 deletions factory.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright (c) 2020-2021 Bjoern Kimminich & the OWASP Juice Shop contributors.
* SPDX-License-Identifier: MIT
*/

/* eslint-disable no-unused-vars */
/* global Nlp, training */
var trainingSet = training.data
7 changes: 6 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
/*
* Copyright (c) 2020-2021 Bjoern Kimminich & the OWASP Juice Shop contributors.
* SPDX-License-Identifier: MIT
*/

const { VM } = require('vm2')
const fs = require('fs')
const path = require('path') // eslint-disable-line no-unused-vars
const ctx = fs.readFileSync(`${__dirname}/factory.js`).toString()
const { NlpManager } = require('node-nlp')
const NlpManager = require('./nlp')

class Bot {
constructor (name, greeting, trainingSet, defaultResponse) {
250 changes: 250 additions & 0 deletions nlp/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/*
* Copyright (c) AXA Group Operations Spain S.A.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

const fs = require('fs')
const { containerBootstrap } = require('@nlpjs/core-loader')
const { Language } = require('@nlpjs/language')
const { LangAll } = require('@nlpjs/lang-all')
const { Nlp } = require('@nlpjs/nlp')
const { Evaluator, Template } = require('@nlpjs/evaluator')
const { fs: requestfs } = require('@nlpjs/request')
const SentimentManager = require('./sentiment')

class NlpManager {
constructor (settings = {}) {
this.settings = settings
if (!this.settings.container) {
this.settings.container = containerBootstrap()
}
this.container = this.settings.container
this.container.registerConfiguration('ner', {
entityPreffix: '%',
entitySuffix: '%'
})
this.container.register('fs', requestfs)
this.container.register('Language', Language, false)
this.container.use(LangAll)
this.container.use(Evaluator)
this.container.use(Template)
this.nlp = new Nlp(this.settings)
this.sentimentManager = new SentimentManager()
}

addDocument (locale, utterance, intent) {
return this.nlp.addDocument(locale, utterance, intent)
}

removeDocument (locale, utterance, intent) {
return this.nlp.removeDocument(locale, utterance, intent)
}

addLanguage (locale) {
return this.nlp.addLanguage(locale)
}

assignDomain (locale, intent, domain) {
return this.nlp.assignDomain(locale, intent, domain)
}

getIntentDomain (locale, intent) {
return this.nlp.getIntentDomain(locale, intent)
}

getDomains () {
return this.nlp.getDomains()
}

guessLanguage (text) {
return this.nlp.guessLanguage(text)
}

addAction (intent, action, parameters, fn) {
if (!fn) {
fn = this.settings.action ? this.settings.action[action] : undefined
}
return this.nlp.addAction(intent, action, parameters, fn)
}

getActions (intent) {
return this.nlp.getActions(intent)
}

removeAction (intent, action, parameters) {
return this.nlp.removeAction(intent, action, parameters)
}

removeActions (intent) {
return this.nlp.removeActions(intent)
}

addAnswer (locale, intent, answer, opts) {
return this.nlp.addAnswer(locale, intent, answer, opts)
}

removeAnswer (locale, intent, answer, opts) {
return this.nlp.removeAnswer(locale, intent, answer, opts)
}

findAllAnswers (locale, intent) {
return this.nlp.findAllAnswers(locale, intent)
}

async getSentiment (locale, utterance) {
const sentiment = await this.nlp.getSentiment(locale, utterance)
return this.sentimentManager.translate(sentiment.sentiment)
}

addNamedEntityText (entityName, optionName, languages, texts) {
return this.nlp.addNerRuleOptionTexts(
languages,
entityName,
optionName,
texts
)
}

removeNamedEntityText (entityName, optionName, languages, texts) {
return this.nlp.removeNerRuleOptionTexts(
languages,
entityName,
optionName,
texts
)
}

addRegexEntity (entityName, languages, regex) {
return this.nlp.addNerRegexRule(languages, entityName, regex)
}

addBetweenCondition (locale, name, left, right, opts) {
return this.nlp.addNerBetweenCondition(locale, name, left, right, opts)
}

addPositionCondition (locale, name, position, words, opts) {
return this.nlp.addNerPositionCondition(
locale,
name,
position,
words,
opts
)
}

addAfterCondition (locale, name, words, opts) {
return this.nlp.addNerAfterCondition(locale, name, words, opts)
}

addAfterFirstCondition (locale, name, words, opts) {
return this.nlp.addNerAfterFirstCondition(locale, name, words, opts)
}

addAfterLastCondition (locale, name, words, opts) {
return this.nlp.addNerAfterLastCondition(locale, name, words, opts)
}

addBeforeCondition (locale, name, words, opts) {
return this.nlp.addNerBeforeCondition(locale, name, words, opts)
}

addBeforeFirstCondition (locale, name, words, opts) {
return this.nlp.addNerBeforeFirstCondition(locale, name, words, opts)
}

addBeforeLastCondition (locale, name, words, opts) {
return this.ner.addNerBeforeLastCondition(locale, name, words, opts)
}

describeLanguage (locale, name) {
return this.nlp.describeLanguage(locale, name)
}

beginEdit () {}

train () {
return this.nlp.train()
}

classify (locale, utterance, settings) {
return this.nlp.classify(locale, utterance, settings)
}

async process (locale, utterance, context, settings) {
const result = await this.nlp.process(locale, utterance, context, settings)
if (this.settings.processTransformer) {
return this.settings.processTransformer(result)
}
return result
}

extractEntities (locale, utterance, context, settings) {
return this.nlp.extractEntities(locale, utterance, context, settings)
}

toObj () {
return this.nlp.toJSON()
}

fromObj (obj) {
return this.nlp.fromJSON(obj)
}

/**
* Export NLP manager information as a string.
* @param {Boolean} minified If true, the returned JSON will have no spacing or indentation.
* @returns {String} NLP manager information as a JSON string.
*/
export (minified = false) {
const clone = this.toObj()
return minified ? JSON.stringify(clone) : JSON.stringify(clone, null, 2)
}

/**
* Load NLP manager information from a string.
* @param {String|Object} data JSON string or object to load NLP manager information from.
*/
import (data) {
const clone = typeof data === 'string' ? JSON.parse(data) : data
this.fromObj(clone)
}

/**
* Save the NLP manager information into a file.
* @param {String} srcFileName Filename for saving the NLP manager.
*/
save (srcFileName, minified = false) {
const fileName = srcFileName || 'model.nlp'
fs.writeFileSync(fileName, this.export(minified), 'utf8')
}

/**
* Load the NLP manager information from a file.
* @param {String} srcFilename Filename for loading the NLP manager.
*/
load (srcFileName) {
const fileName = srcFileName || 'model.nlp'
const data = fs.readFileSync(fileName, 'utf8')
this.import(data)
}
}

module.exports = NlpManager
48 changes: 48 additions & 0 deletions nlp/sentiment-analyzer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) AXA Group Operations Spain S.A.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

const {
SentimentAnalyzer: SentimentAnalyzerBase
} = require('@nlpjs/sentiment')
const { LangAll } = require('@nlpjs/lang-all')
const { Nlu } = require('@nlpjs/nlu')

class SentimentAnalyzer extends SentimentAnalyzerBase {
constructor (settings = {}, container) {
super(settings, container)
this.container.use(LangAll)
this.container.use(Nlu)
}

async getSentiment (utterance, locale = 'en', settings = {}) {
const input = {
utterance,
locale,
...settings
}
const result = await this.process(input)
return result.sentiment
}
}

module.exports = SentimentAnalyzer
80 changes: 80 additions & 0 deletions nlp/sentiment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) AXA Group Operations Spain S.A.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

const SentimentAnalyzer = require('./sentiment-analyzer')

/**
* Class for the sentiment anlysis manager, able to manage
* several different languages at the same time.
*/
class SentimentManager {
/**
* Constructor of the class.
*/
constructor (settings) {
this.settings = settings || {}
this.languages = {}
this.analyzer = new SentimentAnalyzer()
}

addLanguage () {
// do nothing
}

translate (sentiment) {
let vote
if (sentiment.score > 0) {
vote = 'positive'
} else if (sentiment.score < 0) {
vote = 'negative'
} else {
vote = 'neutral'
}
return {
score: sentiment.score,
comparative: sentiment.average,
vote,
numWords: sentiment.numWords,
numHits: sentiment.numHits,
type: sentiment.type,
language: sentiment.locale
}
}

/**
* Process a phrase of a given locale, calculating the sentiment analysis.
* @param {String} locale Locale of the phrase.
* @param {String} phrase Phrase to calculate the sentiment.
* @returns {Promise.Object} Promise sentiment analysis of the phrase.
*/
async process (locale, phrase) {
const sentiment = await this.analyzer.getSentiment(
phrase,
locale,
this.settings
)
return this.translate(sentiment)
}
}

module.exports = SentimentManager
19 changes: 12 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "juicy-chat-bot",
"version": "0.5.0",
"description": "A light weight and totally secure library to easily deploy simple chatbots",
"version": "0.6.4",
"description": "A light-weight and totally \"secure\" library to easily deploy simple chat bots",
"keywords": [
"npm",
"chatbot",
@@ -10,11 +10,11 @@
],
"homepage": "https://owasp-juice.shop",
"bugs": {
"url": "https://github.com/bkimminich/juicy-chat-bot/issues"
"url": "https://github.com/juice-shop/juicy-chat-bot/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/bkimminich/juicy-chat-bot.git"
"url": "git+https://github.com/juice-shop/juicy-chat-bot.git"
},
"license": "MIT",
"author": "Björn Kimminich <bjoern.kimminich@owasp.org> (https://kimminich.de)",
@@ -24,7 +24,6 @@
],
"main": "index.js",
"scripts": {
"coverage": "nyc report --reporter=text-lcov | coveralls",
"lint": "standard",
"lint:fix": "standard --fix",
"test": "nyc mocha test"
@@ -41,12 +40,18 @@
]
},
"dependencies": {
"node-nlp": "^4.10.5",
"@nlpjs/core-loader": "^4.4.0",
"@nlpjs/evaluator": "^4.4.0",
"@nlpjs/lang-all": "^4.4.0",
"@nlpjs/language": "^4.3.0",
"@nlpjs/nlp": "^4.4.0",
"@nlpjs/nlu": "^4.4.0",
"@nlpjs/request": "^4.4.0",
"@nlpjs/sentiment": "^4.4.0",
"vm2": "^3.9.2"
},
"devDependencies": {
"chai": "^4.2.0",
"coveralls": "^3.0.9",
"mocha": "^7.1.0",
"nyc": "^15.0.0",
"standard": "^14.3.1"
53 changes: 52 additions & 1 deletion test/initialize-spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright (c) 2020-2021 Bjoern Kimminich & the OWASP Juice Shop contributors.
* SPDX-License-Identifier: MIT
*/

const chai = require('chai')
const expect = chai.expect
const juice = require('../index')
@@ -31,6 +36,22 @@ const trainingSet = {
body: 'Hello <customer-name>'
}
]
},
{
intent: 'jokes.chucknorris',
utterances: [
'tell me a chuck norris joke'
],
answers: [
{
action: 'response',
body: 'Chuck Norris has two speeds: Walk and Kill.'
},
{
action: 'response',
body: 'Time waits for no man. Unless that man is Chuck Norris.'
}
]
}
]
}
@@ -39,7 +60,7 @@ describe('Initialize', () => {
let bot

beforeEach(() => {
bot = new juice.Bot('Jeff', 'Ma Nemma <bot-name>', JSON.stringify(trainingSet))
bot = new juice.Bot('Jeff', 'Ma Nemma <bot-name>', JSON.stringify(trainingSet), 'lalala')
expect(() => bot.addUser('123', 'test-user')).to.not.throw()
})

@@ -63,6 +84,7 @@ describe('Initialize', () => {
it('should register new user with corresponsing token', async () => {
await bot.train()
expect(() => bot.addUser('1234', 'user2')).to.not.throw()
expect(await bot.getUser('1234')).to.equal('user2')
expect(await bot.respond('hi bot', '1234')).to.deep.equal({
action: 'response',
body: 'Hello user2'
@@ -76,4 +98,33 @@ describe('Initialize', () => {
body: 'Ok Cya'
})
})

it('should respond randomly from multiple available answers', async () => {
const responseCounter = { 'Chuck Norris has two speeds: Walk and Kill.': 0, 'Time waits for no man. Unless that man is Chuck Norris.': 0 }
await bot.train()
for (let i = 0; i < 100; i++) {
const response = await bot.respond('tell me a chuck norris joke', '123')
expect([
{
action: 'response',
body: 'Chuck Norris has two speeds: Walk and Kill.'
},
{
action: 'response',
body: 'Time waits for no man. Unless that man is Chuck Norris.'
}
]).to.deep.include(response)
responseCounter[response.body]++
}
expect(responseCounter['Chuck Norris has two speeds: Walk and Kill.']).to.be.greaterThan(20)
expect(responseCounter['Time waits for no man. Unless that man is Chuck Norris.']).to.be.greaterThan(20)
})

it('should respond with default response to unrecognized query', async () => {
await bot.train()
expect(await bot.respond('blabla blubb blubb', '123')).to.deep.equal({
action: 'response',
body: 'lalala'
})
})
})