<commit_before>'use strict';

require('dotenv').config();
const test = require('ava');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const httpMocks = require('node-mocks-http');
const underscore = require('underscore');

const DraftSubmission = require('../../../../app/models/DraftSubmission');
const helpers = require('../../../../lib/helpers');
const logger = require('../../../../lib/logger');
const stubs = require('../../../helpers/stubs');
const campaignFactory = require('../../../helpers/factories/campaign');
const draftSubmissionFactory = require('../../../helpers/factories/draftSubmission');
const conversationFactory = require('../../../helpers/factories/conversation');
const topicFactory = require('../../../helpers/factories/topic');
const userFactory = require('../../../helpers/factories/user');

const config = require('../../../../config/lib/helpers/request');

chai.should();
chai.use(sinonChai);

// module to be tested
const requestHelper = require('../../../../lib/helpers/request');

const sandbox = sinon.sandbox.create();

const campaignId = stubs.getCampaignId();
const userId = stubs.getUserId();
const platformUserId = stubs.getMobileNumber();
// TODO: Add signup factory and refactor tests that reference this signupId const.
const signupId = stubs.getCampaignId();
const conversation = conversationFactory.getValidConversation();
const message = conversation.lastOutboundMessage;
const topic = topicFactory.getValidTopic();

test.beforeEach((t) => {
  stubs.stubLogger(sandbox, logger);
  sandbox.stub(helpers.analytics, 'addCustomAttributes')
    .returns(underscore.noop);
  t.context.req = httpMocks.createRequest();
});

test.afterEach((t) => {
  t.context.req = {};
  // reset stubs, spies, and mocks
  sandbox.restore();
});

// changeTopic
test('changeTopic does not call setTopic if not a topic change', async (t) => {
  sandbox.stub(requestHelper, 'setTopic')
    .returns(underscore.noop);
  sandbox.stub(conversation, 'setTopic')
    .returns(Promise.resolve(true));
  t.context.req.conversation = conversation;
  t.context.req.currentTopicId = topic.id;

  await requestHelper.changeTopic(t.context.req, topic);
  requestHelper.setTopic.should.have.been.calledWith(t.context.req, topic);
  conversation.setTopic.should.not.have.been.called;
});

test('changeTopic calls setTopic when topic arg is not equal to req.currentTopicId', async (t) => {
  sandbox.stub(requestHelper, 'setTopic')
    .returns(underscore.noop);
  sandbox.stub(conversation, 'setTopic')
    .returns(Promise.resolve());
  t.context.req.conversation = conversation;
  t.context.req.currentTopicId = 'abc';

  await requestHelper.changeTopic(t.context.req, topic);
  requestHelper.setTopic.should.have.been.calledWith(t.context.req, topic);
  conversation.setTopic.should.have.been.calledWith(topic);
});

// createDraftSubmission
test('createDraftSubmission returns DraftSubmission for conversationId and topicId', async (t) => {
  t.context.req.conversation = conversationFactory.getValidConversation();
  t.context.req.topic = topicFactory.getValidTopic();
  const draft = draftSubmissionFactory.getValidNewDraftSubmission();
  sandbox.stub(t.context.req.conversation, 'createDraftSubmission')
    .returns(Promise.resolve(draft));

  const result = await requestHelper.createDraftSubmission(t.context.req);
  t.context.req.conversation.createDraftSubmission
    .should.have.been.calledWith(t.context.req.topic.id);
  result.should.deep.equal(draft);
});

// deleteDraftSubmission
test('deleteDraftSubmission deletes the DB document for req.draftSubmission.id', async (t) => {
  const draft = draftSubmissionFactory.getValidNewDraftSubmission();
  sandbox.stub(DraftSubmission, 'deleteOne')
    .returns(Promise.resolve());
  t.context.req.draftSubmission = draft;

  await requestHelper.deleteDraftSubmission(t.context.req);
  DraftSubmission.deleteOne.should.have.been.calledWith({ _id: draft._id });
});

// executeInboundTopicChange
test('executeInboundTopicChange get topic, create signup if topic has active campaign, and return changeTopic', async (t) => {
  const keyword = 'dragon';
  const platform = stubs.getPlatform();
  t.context.req.rivescriptReplyTopicId = stubs.getContentfulId();
  t.context.req.macro = stubs.getRandomWord();
  t.context.req.platform = platform;
  sandbox.stub(requestHelper, 'changeTopic')
    .returns(Promise.resolve(true));
  sandbox.stub(helpers.topic, 'hasActiveCampaign')
    .returns(true);
  sandbox.stub(helpers.user, 'fetchOrCreateSignup')
    .returns(Promise.resolve(stubs.getSignup()));
  t.context.req.user = userFactory.getValidUser();
  t.context.req.conversation = conversation;

  await requestHelper.executeInboundTopicChange(t.context.req, topic, keyword);

  helpers.user.fetchOrCreateSignup
    .should.have.been.calledWith(t.context.req.user, topic.campaign, platform, keyword);
  requestHelper.changeTopic
    .should.have.been.calledWith(t.context.req, topic);
});

test('executeInboundTopicChange does not create signup if topic does not have active campaign', async (t) => {
  const keyword = 'dragon';
  t.context.req.rivescriptReplyTopicId = stubs.getContentfulId();
  t.context.req.macro = stubs.getRandomWord();
  t.context.req.platform = stubs.getPlatform();
  sandbox.stub(requestHelper, 'changeTopic')
    .returns(Promise.resolve(true));
  sandbox.stub(helpers.topic, 'hasActiveCampaign')
    .returns(false);
  sandbox.stub(helpers.user, 'fetchOrCreateSignup')
    .returns(Promise.resolve(stubs.getSignup()));
  t.context.req.user = userFactory.getValidUser();
  t.context.req.conversation = conversation;

  await requestHelper.executeInboundTopicChange(t.context.req, topic, keyword);

  helpers.user.fetchOrCreateSignup.should.not.have.been.called;
  requestHelper.changeTopic
    .should.have.been.calledWith(t.context.req, topic);
});

// getDraftSubmission
test('getDraftSubmission returns DraftSubmission for conversationId and topicId if exists', async (t) => {
  t.context.req.conversation = conversationFactory.getValidConversation();
  t.context.req.topic = topicFactory.getValidTopic();
  const draft = draftSubmissionFactory.getValidCompletePhotoPostDraftSubmission();
  sandbox.stub(t.context.req.conversation, 'getDraftSubmission')
    .returns(Promise.resolve(draft));

  const result = await requestHelper.getDraftSubmission(t.context.req);
  t.context.req.conversation.getDraftSubmission.should.have.been.calledWith(t.context.req.topic.id);
  result.should.deep.equal(draft);
});

// getRivescriptReply
test('getRivescriptReply should call helpers.rivescript.getBotReply with req vars', async (t) => {
  t.context.req.userId = userId;
  t.context.req.conversation = conversation;
  t.context.req.currentTopicId = stubs.getContentfulId();
  t.context.req.inboundMessageText = stubs.getRandomMessageText();
  // TODO: This should be renamed as default topic the way we're using it -- stub getDefaultTopicId.
  const mockRivescriptTopicId = 'random';
  const mockRivescriptTopic = { id: mockRivescriptTopicId };
  const botReply = { text: stubs.getRandomMessageText(), match: '@hello' };
  sandbox.stub(helpers.rivescript, 'getBotReply')
    .returns(Promise.resolve(botReply));
  sandbox.stub(helpers.topic, 'getRivescriptTopicById')
    .returns(mockRivescriptTopic);
  const result = await requestHelper.getRivescriptReply(t.context.req);
  helpers.rivescript.getBotReply.should.have.been
    .calledWith(userId, mockRivescriptTopicId, t.context.req.inboundMessageText);
  result.text.should.equal(botReply.text);
  result.match.should.equal(botReply.match);
  // TODO: Add tests for various topic changes.
  // result.topicId.should.deep.equal(mockRivescriptTopic);
});

// hasCampaign<commit_msg>Adds test for getRivescriptReply when bot is not ready<commit_after>'use strict';

require('dotenv').config();
const test = require('ava');
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const httpMocks = require('node-mocks-http');
const underscore = require('underscore');

const DraftSubmission = require('../../../../app/models/DraftSubmission');
const helpers = require('../../../../lib/helpers');
const logger = require('../../../../lib/logger');
const stubs = require('../../../helpers/stubs');
const campaignFactory = require('../../../helpers/factories/campaign');
const draftSubmissionFactory = require('../../../helpers/factories/draftSubmission');
const conversationFactory = require('../../../helpers/factories/conversation');
const topicFactory = require('../../../helpers/factories/topic');
const userFactory = require('../../../helpers/factories/user');

const config = require('../../../../config/lib/helpers/request');

chai.should();
chai.use(sinonChai);

// module to be tested
const requestHelper = require('../../../../lib/helpers/request');

const sandbox = sinon.sandbox.create();

const campaignId = stubs.getCampaignId();
const userId = stubs.getUserId();
const platformUserId = stubs.getMobileNumber();
// TODO: Add signup factory and refactor tests that reference this signupId const.
const signupId = stubs.getCampaignId();
const conversation = conversationFactory.getValidConversation();
const message = conversation.lastOutboundMessage;
const topic = topicFactory.getValidTopic();

test.beforeEach((t) => {
  stubs.stubLogger(sandbox, logger);
  sandbox.stub(helpers.analytics, 'addCustomAttributes')
    .returns(underscore.noop);
  t.context.req = httpMocks.createRequest();
});

test.afterEach((t) => {
  t.context.req = {};
  // reset stubs, spies, and mocks
  sandbox.restore();
});

// changeTopic
test('changeTopic does not call setTopic if not a topic change', async (t) => {
  sandbox.stub(requestHelper, 'setTopic')
    .returns(underscore.noop);
  sandbox.stub(conversation, 'setTopic')
    .returns(Promise.resolve(true));
  t.context.req.conversation = conversation;
  t.context.req.currentTopicId = topic.id;

  await requestHelper.changeTopic(t.context.req, topic);
  requestHelper.setTopic.should.have.been.calledWith(t.context.req, topic);
  conversation.setTopic.should.not.have.been.called;
});

test('changeTopic calls setTopic when topic arg is not equal to req.currentTopicId', async (t) => {
  sandbox.stub(requestHelper, 'setTopic')
    .returns(underscore.noop);
  sandbox.stub(conversation, 'setTopic')
    .returns(Promise.resolve());
  t.context.req.conversation = conversation;
  t.context.req.currentTopicId = 'abc';

  await requestHelper.changeTopic(t.context.req, topic);
  requestHelper.setTopic.should.have.been.calledWith(t.context.req, topic);
  conversation.setTopic.should.have.been.calledWith(topic);
});

// createDraftSubmission
test('createDraftSubmission returns DraftSubmission for conversationId and topicId', async (t) => {
  t.context.req.conversation = conversationFactory.getValidConversation();
  t.context.req.topic = topicFactory.getValidTopic();
  const draft = draftSubmissionFactory.getValidNewDraftSubmission();
  sandbox.stub(t.context.req.conversation, 'createDraftSubmission')
    .returns(Promise.resolve(draft));

  const result = await requestHelper.createDraftSubmission(t.context.req);
  t.context.req.conversation.createDraftSubmission
    .should.have.been.calledWith(t.context.req.topic.id);
  result.should.deep.equal(draft);
});

// deleteDraftSubmission
test('deleteDraftSubmission deletes the DB document for req.draftSubmission.id', async (t) => {
  const draft = draftSubmissionFactory.getValidNewDraftSubmission();
  sandbox.stub(DraftSubmission, 'deleteOne')
    .returns(Promise.resolve());
  t.context.req.draftSubmission = draft;

  await requestHelper.deleteDraftSubmission(t.context.req);
  DraftSubmission.deleteOne.should.have.been.calledWith({ _id: draft._id });
});

// executeInboundTopicChange
test('executeInboundTopicChange get topic, create signup if topic has active campaign, and return changeTopic', async (t) => {
  const keyword = 'dragon';
  const platform = stubs.getPlatform();
  t.context.req.rivescriptReplyTopicId = stubs.getContentfulId();
  t.context.req.macro = stubs.getRandomWord();
  t.context.req.platform = platform;
  sandbox.stub(requestHelper, 'changeTopic')
    .returns(Promise.resolve(true));
  sandbox.stub(helpers.topic, 'hasActiveCampaign')
    .returns(true);
  sandbox.stub(helpers.user, 'fetchOrCreateSignup')
    .returns(Promise.resolve(stubs.getSignup()));
  t.context.req.user = userFactory.getValidUser();
  t.context.req.conversation = conversation;

  await requestHelper.executeInboundTopicChange(t.context.req, topic, keyword);

  helpers.user.fetchOrCreateSignup
    .should.have.been.calledWith(t.context.req.user, topic.campaign, platform, keyword);
  requestHelper.changeTopic
    .should.have.been.calledWith(t.context.req, topic);
});

test('executeInboundTopicChange does not create signup if topic does not have active campaign', async (t) => {
  const keyword = 'dragon';
  t.context.req.rivescriptReplyTopicId = stubs.getContentfulId();
  t.context.req.macro = stubs.getRandomWord();
  t.context.req.platform = stubs.getPlatform();
  sandbox.stub(requestHelper, 'changeTopic')
    .returns(Promise.resolve(true));
  sandbox.stub(helpers.topic, 'hasActiveCampaign')
    .returns(false);
  sandbox.stub(helpers.user, 'fetchOrCreateSignup')
    .returns(Promise.resolve(stubs.getSignup()));
  t.context.req.user = userFactory.getValidUser();
  t.context.req.conversation = conversation;

  await requestHelper.executeInboundTopicChange(t.context.req, topic, keyword);

  helpers.user.fetchOrCreateSignup.should.not.have.been.called;
  requestHelper.changeTopic
    .should.have.been.calledWith(t.context.req, topic);
});

// getDraftSubmission
test('getDraftSubmission returns DraftSubmission for conversationId and topicId if exists', async (t) => {
  t.context.req.conversation = conversationFactory.getValidConversation();
  t.context.req.topic = topicFactory.getValidTopic();
  const draft = draftSubmissionFactory.getValidCompletePhotoPostDraftSubmission();
  sandbox.stub(t.context.req.conversation, 'getDraftSubmission')
    .returns(Promise.resolve(draft));

  const result = await requestHelper.getDraftSubmission(t.context.req);
  t.context.req.conversation.getDraftSubmission.should.have.been.calledWith(t.context.req.topic.id);
  result.should.deep.equal(draft);
});

// getRivescriptReply
test('getRivescriptReply should call helpers.rivescript.getBotReply with req vars', async (t) => {
  t.context.req.userId = userId;
  t.context.req.conversation = conversation;
  t.context.req.currentTopicId = stubs.getContentfulId();
  t.context.req.inboundMessageText = stubs.getRandomMessageText();
  // TODO: This should be renamed as default topic the way we're using it -- stub getDefaultTopicId.
  const mockRivescriptTopicId = 'random';
  const mockRivescriptTopic = { id: mockRivescriptTopicId };
  const botReply = { text: stubs.getRandomMessageText(), match: '@hello' };
  sandbox.stub(helpers.rivescript, 'isBotReady')
    .returns(true);
  sandbox.stub(helpers.rivescript, 'loadBot')
    .returns(Promise.resolve());
  sandbox.stub(helpers.rivescript, 'getBotReply')
    .returns(Promise.resolve(botReply));
  sandbox.stub(helpers.topic, 'getRivescriptTopicById')
    .returns(mockRivescriptTopic);

  const result = await requestHelper.getRivescriptReply(t.context.req);
  helpers.rivescript.getBotReply.should.have.been
    .calledWith(userId, mockRivescriptTopicId, t.context.req.inboundMessageText);
  result.text.should.equal(botReply.text);
  result.match.should.equal(botReply.match);
  helpers.rivescript.loadBot.should.not.have.been.called;
  // TODO: Add tests for various topic changes.
  // result.topicId.should.deep.equal(mockRivescriptTopic);
});

test('getRivescriptReply should call helpers.rivescript.loadBot if bot is not ready', async (t) => {
  t.context.req.userId = userId;
  t.context.req.conversation = conversation;
  t.context.req.currentTopicId = stubs.getContentfulId();
  t.context.req.inboundMessageText = stubs.getRandomMessageText();
  // TODO: This should be renamed as default topic the way we're using it -- stub getDefaultTopicId.
  const mockRivescriptTopicId = 'random';
  const mockRivescriptTopic = { id: mockRivescriptTopicId };
  const botReply = { text: stubs.getRandomMessageText(), match: '@hello' };
  sandbox.stub(helpers.rivescript, 'isBotReady')
    .returns(false);
  sandbox.stub(helpers.rivescript, 'loadBot')
    .returns(Promise.resolve());
  sandbox.stub(helpers.rivescript, 'getBotReply')
    .returns(Promise.resolve(botReply));
  sandbox.stub(helpers.topic, 'getRivescriptTopicById')
    .returns(mockRivescriptTopic);

  await requestHelper.getRivescriptReply(t.context.req);
  helpers.rivescript.loadBot.should.have.been.called;
});

// hasCampaign
{'fraction_non_alphanumeric': 0.1442078972407231, 'fraction_numerical': 0.0, 'mean_word_length': 5.075505780346821, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '964920', 'n_tokens_mistral': 5199, 'n_tokens_neox': 5204, 'n_words': 908}