diff --git a/web/src/App.test.js b/web/src/App.test.js deleted file mode 100644 index e5a5b7d..0000000 --- a/web/src/App.test.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import App from './App'; - -it('renders without crashing', () => { - shallow(); -}); \ No newline at end of file diff --git a/web/src/components/IntentDetails.js b/web/src/components/IntentDetails.js index ff5827f..6be2bf3 100644 --- a/web/src/components/IntentDetails.js +++ b/web/src/components/IntentDetails.js @@ -157,14 +157,14 @@ class IntentDetails extends Component { } handleQuestionEdit (e, index) { - if (e.length === QUESTION_MAX_LENGTH || !/^[a-z,.' ]*$/i.test (e)) return; + if (e.length >= QUESTION_MAX_LENGTH || !/^[a-z,.' ]*$/i.test (e)) return; let newIntent = this.state.intent; newIntent.questions[index] = e; this.setState ({intent: newIntent}); } handleIntentExplanationEdit (e, index) { - if (e.length === INTENT_EXPLANATION_MAX_LENGTH || !/^[a-z,.' ]*$/i.test (e)) + if (e.length >= INTENT_EXPLANATION_MAX_LENGTH || !/^[a-z,.' ]*$/i.test (e)) return; let newIntent = this.state.intent; newIntent.intentExplanation = e; @@ -172,21 +172,21 @@ class IntentDetails extends Component { } handleAnswerEdit (e) { - if (e.length === ANSWER_MAX_LENGTH || !/^[a-z,.' ]*$/i.test (e)) return; + if (e.length >= ANSWER_MAX_LENGTH || !/^[a-z,.' ]*$/i.test (e)) return; let newIntent = this.state.intent; newIntent.answer = e; this.setState ({intent: newIntent}); } handleAnswerSourceEdit (e) { - if (e.length === ANSWER_MAX_LENGTH) return; + if (e.length >= ANSWER_MAX_LENGTH) return; let newIntent = this.state.intent; newIntent.externalAnswerSource = e; this.setState ({intent: newIntent}); } handleIntentNameEdit (e) { - if (e.length === INTENT_NAME_MAX_LENGTH || !/^[a-z]*$/i.test (e)) return; + if (e.length >= INTENT_NAME_MAX_LENGTH || !/^[a-z]*$/i.test (e)) return; let newIntent = this.state.intent; newIntent.intentName = e; this.setState ({intent: newIntent}); diff --git a/web/src/components/__tests__/IntentDetails.test.js b/web/src/components/__tests__/IntentDetails.test.js index 977fc97..09c79c4 100644 --- a/web/src/components/__tests__/IntentDetails.test.js +++ b/web/src/components/__tests__/IntentDetails.test.js @@ -1,10 +1,290 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import {shallow, mount} from 'enzyme'; import IntentDetails from '../IntentDetails'; +import { + QUESTION_MAX_LENGTH, + ANSWER_MAX_LENGTH, + INTENT_NAME_MAX_LENGTH, + INTENT_EXPLANATION_MAX_LENGTH, + ANSWER_TYPE, +} from '../../config/constants'; -it('renders without crashing', () => { - let dummyIntent = { - questions:['q1','q2'] - } - shallow(); +it ('renders without crashing', () => { + const dummyIntent = { + questions: ['q1', 'q2'], + }; + shallow (); +}); + +describe('complete testing', () => { + + let wrapper; + let newIntent; + beforeEach(()=>{ + newIntent = { + intentName: '', + intentExplanation: '', + questions: [''], + answer: '', + answerType: ANSWER_TYPE.PREDEFINED, + externalAnswerSource: '', + }; + + wrapper = mount(); + expect(wrapper.state('intent')).toEqual(newIntent); + }); + + it ('snapshot', () =>{ + expect(wrapper).toMatchSnapshot(); + }); + + it ('renders correctly for new intent input when empty intent is sent', () => { + expect(wrapper.find('TextField').length).toBe(4); + expect(wrapper.find('Button').length).toBe(4); + + expect(wrapper.find('TextField').at(0).props().id).toEqual('intent explanation'); + expect(wrapper.find('TextField').at(1).props().id).toEqual('intent name'); + expect(wrapper.find('TextField').at(2).props().id).toEqual('intent question'); + expect(wrapper.find('TextField').at(3).props().id).toEqual('intent answer'); + + expect(wrapper.find('Button').at(0).props().children).toEqual('add'); + expect(wrapper.find('Button').at(1).props().children).toEqual('Answer type'); + expect(wrapper.find('Button').at(2).props().children).toEqual('Save'); + expect(wrapper.find('Button').at(3).props().children).toEqual('Delete'); + }); + + it ('receives correct props for non empty intent with predefined answer', () => { + newIntent = { + intentName: 'Dummy intent', + intentExplanation: 'Dummy explanation', + questions: ['Dummy question'], + answer: 'dummy answer', + answerType: ANSWER_TYPE.PREDEFINED, + externalAnswerSource: '', + }; + + wrapper = mount(); + expect(wrapper.state('intent')).toEqual(newIntent); + }); + + it ('receives correct props for non empty intent with external source for answer', () => { + newIntent = { + intentName: 'Dummy intent', + intentExplanation: 'Dummy explanation', + questions: ['Dummy question'], + answer: '', + answerType: ANSWER_TYPE.EXTERNAL_SOURCE_WP_NEWS, + externalAnswerSource: 'http://sarajevotimes.com', + }; + + wrapper = mount(); + expect(wrapper.state('intent')).toEqual(newIntent); + }); + + it ('adds text field when add button is clicked', () => { + const addButton = wrapper.find('button').at(0); + addButton.simulate('click'); + expect(wrapper.find('TextField').length).toBe(5); + addButton.simulate('click'); + expect(wrapper.find('TextField').length).toBe(6); + + expect(wrapper.find('TextField').at(0).props().id).toEqual('intent explanation'); + expect(wrapper.find('TextField').at(1).props().id).toEqual('intent name'); + expect(wrapper.find('TextField').at(2).props().id).toEqual('intent question'); + expect(wrapper.find('TextField').at(3).props().id).toEqual('intent question'); + expect(wrapper.find('TextField').at(4).props().id).toEqual('intent question'); + expect(wrapper.find('TextField').at(5).props().id).toEqual('intent answer'); + + expect(wrapper.state('intent').questions.length).toBe(3); + + }); + + xit ('removes correct text field when delete button on text field is clicked', () => { + const addButton = wrapper.find('button').at(0); + addButton.simulate('click'); + addButton.simulate('click'); + const firstQuestionTextField = wrapper.find('TextField').at(2); + const secondQuestionTextField = wrapper.find('TextField').at(3); + const thirdQuestionTextField = wrapper.find('TextField').at(4); + expect(firstQuestionTextField.props().id).toEqual('intent question'); + expect(secondQuestionTextField.props().id).toEqual('intent question'); + expect(thirdQuestionTextField.props().id).toEqual('intent question'); + //TODO: simulate click on delete icon inside text field and check if text field is removed + }); + + it ('accepts text without special characters for intent explanation', () => { + let explanationTextField = wrapper.find('TextField').at(0); + let validExplanationText = 'to get latest news, say '; + explanationTextField.instance().props.onChange(validExplanationText); + expect(wrapper.state('intent').intentExplanation).toEqual(validExplanationText); + expect(explanationTextField.instance().value).toEqual(validExplanationText); + }); + + it ('does not accept text with special characters for intent explanation', () => { + let explanationTextField = wrapper.find('TextField').at(0); + let invalidExplanationText = '554to get latest news, say #$ '; + explanationTextField.instance().props.onChange(invalidExplanationText); + expect(wrapper.state('intent').intentExplanation).toEqual(''); + expect(explanationTextField.instance().value).toEqual(''); + }); + + it ('does not accept too long text for intent explanation', () => { + let explanationTextField = wrapper.find('TextField').at(0); + let invalidExplanationText = new Array(INTENT_EXPLANATION_MAX_LENGTH + 10).join('A'); + explanationTextField.instance().props.onChange(invalidExplanationText); + expect(wrapper.state('intent').intentExplanation).toEqual(''); + expect(explanationTextField.instance().value).toEqual(''); + }); + + it ('accepts text without special characters for intent name', () => { + let intentNameTextField = wrapper.find('TextField').at(1); + let validIntentNameText = 'intentName'; + intentNameTextField.instance().props.onChange(validIntentNameText); + expect(wrapper.state('intent').intentName).toEqual(validIntentNameText); + expect(intentNameTextField.instance().value).toEqual(validIntentNameText); + }); + + it ('does not accept text with speces characters for intent name', () => { + let intentNameTextField = wrapper.find('TextField').at(1); + let invalidIntentNameText = 'intentName with space'; + intentNameTextField.instance().props.onChange(invalidIntentNameText); + expect(wrapper.state('intent').intentName).toEqual(''); + expect(intentNameTextField.instance().value).toEqual(''); + }); + + it ('does not accept text with special characters for intent name', () => { + let intentNameTextField = wrapper.find('TextField').at(1); + let invalidIntentNameText = 'intentName23!'; + intentNameTextField.instance().props.onChange(invalidIntentNameText); + expect(wrapper.state('intent').intentName).toEqual(''); + expect(intentNameTextField.instance().value).toEqual(''); + }); + + it ('does not accept too long text for intent name', () => { + let intentNameTextField = wrapper.find('TextField').at(1); + let invalidIntentNameText = new Array(INTENT_NAME_MAX_LENGTH + 10).join('A'); + intentNameTextField.instance().props.onChange(invalidIntentNameText); + expect(wrapper.state('intent').intentName).toEqual(''); + expect(intentNameTextField.instance().value).toEqual(''); + }); + + it ('accepts text without special characters for question text', () => { + let questionTextField = wrapper.find('TextField').at(2); + let validQuestionText = 'read me latest news' + questionTextField.instance().props.onChange(validQuestionText); + expect(wrapper.state('intent').questions).toEqual([validQuestionText]); + expect(questionTextField.instance().value).toEqual(validQuestionText); + }); + + it ('does not accept text with special characters for question text', () => { + let questionTextField = wrapper.find('TextField').at(2); + let invalidQuestionText = 'read m3 1at35t news #' + questionTextField.instance().props.onChange(invalidQuestionText); + expect(wrapper.state('intent').questions).toEqual(['']); + expect(questionTextField.instance().value).toEqual(''); + }); + + it ('does not accept too long text for question text', () => { + let questionTextField = wrapper.find('TextField').at(2); + let invalidQuestionText = new Array(QUESTION_MAX_LENGTH + 10).join('A'); + questionTextField.instance().props.onChange(invalidQuestionText); + expect(wrapper.state('intent').questions).toEqual(['']); + expect(questionTextField.instance().value).toEqual(''); + }); + + it ('accepts text without special characters for answer text', () => { + let answerTextField = wrapper.find('TextField').at(3); + let validAnswerText = 'this is valid answer.' + answerTextField.instance().props.onChange(validAnswerText); + expect(wrapper.state('intent').answer).toEqual(validAnswerText); + expect(answerTextField.instance().value).toEqual(validAnswerText); + }); + + it ('does not accept text with special characters for answer text', () => { + let answerTextField = wrapper.find('TextField').at(3); + let invalidAnswerText = 'this is invalid answer.0123' + answerTextField.instance().props.onChange(invalidAnswerText); + expect(wrapper.state('intent').answer).toEqual(''); + expect(answerTextField.instance().value).toEqual(''); + }); + + it ('does not accept too long text for answer text', () => { + let answerTextField = wrapper.find('TextField').at(3); + let invalidAnswerText = new Array(ANSWER_MAX_LENGTH + 10).join('A'); + answerTextField.instance().props.onChange(invalidAnswerText); + expect(wrapper.state('intent').answer).toEqual(''); + expect(answerTextField.instance().value).toEqual(''); + }); + + it ('accepts text for external source as answer', () => { + newIntent = { + intentName: '', + intentExplanation: '', + questions: [''], + answer: '', + answerType: ANSWER_TYPE.EXTERNAL_SOURCE_WP_NEWS, + externalAnswerSource: '', + }; + + wrapper = mount(); + + let answerTextField = wrapper.find('TextField').at(3); + let validAnswerText = 'http://sarajevotimes.com' + answerTextField.instance().props.onChange(validAnswerText); + expect(wrapper.state('intent').externalAnswerSource).toEqual(validAnswerText); + expect(answerTextField.instance().value).toEqual(validAnswerText); + }); + + it ('does not accept too long text for external source as answer', () => { + newIntent = { + intentName: '', + intentExplanation: '', + questions: [''], + answer: '', + answerType: ANSWER_TYPE.EXTERNAL_SOURCE_WP_NEWS, + externalAnswerSource: '', + }; + + wrapper = mount(); + + let answerTextField = wrapper.find('TextField').at(3); + let invalidAnswerText = new Array(ANSWER_MAX_LENGTH + 10).join('A'); + answerTextField.instance().props.onChange(invalidAnswerText); + expect(wrapper.state('intent').answer).toEqual(''); + expect(answerTextField.instance().value).toEqual(''); + }); + + it ('calls function with correct data on save button click', () => { + newIntent = { + intentName: 'Dummy intent', + intentExplanation: 'Dummy explanation', + questions: ['Dummy question'], + answer: 'Dummy answer', + answerType: ANSWER_TYPE.PREDEFINED, + externalAnswerSource: '', + }; + const onSaveFunction = jest.fn(); + + wrapper = mount(); + wrapper.find('Button').at(2).simulate('click'); + expect(onSaveFunction).toBeCalledWith(newIntent); + }); + + it ('calls function with correct data on delete button click', () => { + newIntent = { + intentName: 'Dummy intent', + intentExplanation: 'Dummy explanation', + questions: ['Dummy question'], + answer: 'Dummy answer', + answerType: ANSWER_TYPE.PREDEFINED, + externalAnswerSource: '', + }; + const onSaveFunction = jest.fn(); + + wrapper = mount(); + wrapper.find('Button').at(3).simulate('click'); + expect(onSaveFunction).toBeCalledWith(newIntent); + }); + + }); diff --git a/web/src/components/__tests__/__snapshots__/IntentDetails.test.js.snap b/web/src/components/__tests__/__snapshots__/IntentDetails.test.js.snap new file mode 100644 index 0000000..03a966c --- /dev/null +++ b/web/src/components/__tests__/__snapshots__/IntentDetails.test.js.snap @@ -0,0 +1,898 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`complete testing snapshot 1`] = ` + +
+
+
+ + In introduction, Alexa will help users to ask her the right questions about your business. For Example, she will say : "To ask us about our services, say : What do you do ? ". What do you do ? is defined in question field. Alexa will use first variation of question in intro. +
+ + remove_red_eye + + } + placeholder="To ask us about our services, say " + rightIconStateful={true} + type="text" + value="" + > +
+ + + + + + +
+
+
+ +
+ + +
+ 0 / 70 +
+
+
+
+
+
+
+ + remove_red_eye + + } + rightIconStateful={true} + type="text" + value="" + > +
+ + + + + + + + +
+
+
+ +
+ + +
+ 0 / 30 +
+
+
+
+
+
+
+
+ Question variants +
+
+ + remove_red_eye + + } + placeholder="Question" + rightIcon={ + + + + + + } + rightIconStateful={true} + type="text" + value="" + > +
+ +
+
+ + + + + +
+
+
+
+ + + + + + + +
+ +
+ + +
+ 0 / 150 +
+
+
+
+
+
+
+ + + } + onClick={[Function]} + primary={true} + > + + + + + +
+ + + } + onClick={[Function]} + primary={true} + > + + + + +
+
+ +
+ + remove_red_eye + + } + placeholder="Answer" + rightIconStateful={true} + type="text" + value="" + > +
+ + + + + + + + +
+
+
+ +
+ + +
+ 0 / 150 +
+
+
+
+
+
+
+
+ + + } + onClick={[Function]} + primary={true} + swapTheming={true} + > + + + + + + + } + onClick={[Function]} + primary={true} + > + + + + +
+
+`;