Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
388 changes: 345 additions & 43 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
]
},
"devDependencies": {
"enzyme": "^3.10.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.4.0"
},
Expand Down
10 changes: 10 additions & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,14 @@ export const removeUser = () => ({
export const hasErrored = errorMsg => ({
type: 'HAS_ERRORED',
errorMsg
})

export const submitMessage = (message, isUser) => ({
type: 'SUBMIT_MESSAGE',
message,
isUser
})

export const deleteMessages = () => ({
type: 'DELETE_MESSAGES'
})
23 changes: 23 additions & 0 deletions src/actions/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as actions from './index';

describe('actions testing', () => {
it('should have a type of SUBMIT_MESSAGE', () => {
const message = "HALP";
const expectedAction = {
type: 'SUBMIT_MESSAGE',
message: "HALP",
isUser: true
};
const result = actions.submitMessage(message, true);
expect(result).toEqual(expectedAction);
});

it('should have a type of DELETE_MESSAGES', () => {
const expectedAction = {
type: 'DELETE_MESSAGES'
};
const result = actions.deleteMessages();
expect(result).toEqual(expectedAction);
});
});

17 changes: 16 additions & 1 deletion src/apiCalls.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,27 @@ export const startConversation = async feeling => {
}

const data = await response.json();
console.log(data)
return data;
}

export const postMessage = async newMessage => {
const messageInfo = { newMessage };

const options = {
method: 'POST',
body: JSON.stringify(messageInfo),
headers: {'Content-Type': 'application/json'}
};

const response = await fetch('https://drwatson-api.herokuapp.com/api/message', options);

if (!response.ok) {
throw new Error('Dr Watson is currently down. Please try again later.');
};

const reply = await response.json();

return reply;
}

export const endConversation = async () => {
Expand Down
52 changes: 52 additions & 0 deletions src/apiCalls.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,56 @@ describe('endConversation', () => {

expect(endConversation()).rejects.toEqual(Error('fetch failed.'));
});

describe('postMessage', () => {
let mockMessage = 'Last hulp';
let mockResolve = {
newMessage: 'Last hulp'
}

beforeEach(() => {
window.fetch = jest.fn().mockImplementation(() => {
return Promise.resolve({
ok: true,
json: () => Promise.resolve(mockResolve)
});
});
});

it('should fetch with the correct arguments', () => {
const expected = [ 'https://drwatson-api.herokuapp.com/api/message', {
method: 'POST',
body: JSON.stringify(mockResolve),
headers: {
'Content-Type': 'application/json'
}
}]
postMessage(mockMessage);

expect(window.fetch).toHaveBeenCalledWith(...expected)
});

it('should return a new response message (HAPPY)', () => {
expect(postMessage(mockMessage)).resolves.toEqual(mockResolve);
});

it('should return an error (SAD)', () => {
window.fetch = jest.fn().mockImplementation(() => {
return Promise.resolve({
ok: false,
json: () => Promise.resolve(mockResolve)
});
});

expect(postMessage(mockMessage)).rejects.toEqual(Error('Dr Watson is currently down. Please try again later.'))
});

it('should return an error if promise rejects (SAD)', () => {
window.fetch = jest.fn().mockImplementation(() => {
return Promise.reject(Error('fetch failed.'))
});

expect(postMessage(mockMessage)).rejects.toEqual(Error('fetch failed.'))
});
});
});
3 changes: 2 additions & 1 deletion src/containers/App/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
}

.App {
background-color: #282c34;
/* background-color: #282c34; */
background: url('https://ca.slack-edge.com/T029P2S9M-U0S2QJD42-62348d5b08d9-512');
min-height: 100vh;
display: flex;
flex-direction: column;
Expand Down
21 changes: 6 additions & 15 deletions src/containers/App/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,13 @@ import { bindActionCreators } from 'redux';
import Header from '../Header/Header';
import WelcomeModal from '../WelcomeModal/WelcomeModal';
import ChatBox from '../ChatBox/ChatBox';
import { removeUser, hasErrored } from '../../actions';
import { removeUser, hasErrored, submitMessage, deleteMessages } from '../../actions';
import { endConversation } from '../../apiCalls';
import './App.css';

export class App extends Component {
constructor() {
super();
this.state = {
messages: []
}
}

addMessage = (message, isUser) => {
const { messages } = this.state;
this.setState({ messages: [...messages, { message, isUser }]});
this.props.submitMessage(message, isUser);
}

clearMessages = () => {
Expand All @@ -37,21 +29,20 @@ export class App extends Component {

render() {
const { user } = this.props;
const { messages } = this.state;
return (
<div className="App">
<Header signOut={this.signOut} />
{!user && <WelcomeModal addMessage={this.addMessage} />}
{user && <ChatBox addMessage={this.addMessage} messages={messages} />}
{!user && <WelcomeModal type='button' addMessage={this.addMessage} />}
{user && <ChatBox addMessage={this.addMessage} />}
</div>
);
}
}

export const mapStateToProps = ({ user }) => ({
user,
user
});

export const mapDispatchToProps = dispatch => bindActionCreators({ removeUser, hasErrored }, dispatch);
export const mapDispatchToProps = dispatch => bindActionCreators({ removeUser, hasErrored, submitMessage, deleteMessages }, dispatch);

export default connect(mapStateToProps, mapDispatchToProps)(App);
28 changes: 27 additions & 1 deletion src/containers/App/App.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import { shallow } from 'enzyme';
import { App, mapStateToProps, mapDispatchToProps } from './App';
import { removeUser, hasErrored } from '../../actions';
import { removeUser, hasErrored, submitMessage, deleteMessages } from '../../actions';
import { endConversation } from '../../apiCalls';

jest.mock('../../apiCalls');

describe('App component', () => {
const mockRemoveUser = jest.fn();
const mockHasErrored = jest.fn();
const mocksubmitMessage = jest.fn();
const mockDeleteMessages = jest.fn();
let wrapper;

beforeEach(() => {
Expand All @@ -23,6 +25,8 @@ describe('App component', () => {
user={mockUser}
removeUser={mockRemoveUser}
hasErrored={mockHasErrored}
submitMessage={mocksubmitMessage}
deletemessages={mockDeleteMessages}
/>);
});

Expand All @@ -35,6 +39,8 @@ describe('App component', () => {
user={null}
removeUser={mockRemoveUser}
hasErrored={mockHasErrored}
submitMessage={mocksubmitMessage}
deletemessages={mockDeleteMessages}
/>);

expect(wrapper).toMatchSnapshot();
Expand Down Expand Up @@ -106,4 +112,24 @@ describe('mapDispatchToProps', () => {

expect(mockDispatch).toHaveBeenCalledWith(actionToDispatch);
});

it('calls dispatch with a submitMessage action when submitMessage is called', () => {
const mockDispatch = jest.fn();
const actionToDispatch = submitMessage();

const mappedProps = mapDispatchToProps(mockDispatch);
mappedProps.submitMessage();

expect(mockDispatch).toHaveBeenCalledWith(actionToDispatch);
});

it('calls dispatch with a deleteMessages action when deleteMessages is called', () => {
const mockDispatch = jest.fn();
const actionToDispatch = deleteMessages();

const mappedProps = mapDispatchToProps(mockDispatch);
mappedProps.deleteMessages();

expect(mockDispatch).toHaveBeenCalledWith(actionToDispatch);
});
});
2 changes: 1 addition & 1 deletion src/containers/App/__snapshots__/App.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ exports[`App component should match the snapshot with a ChatBox if the user has
/>
<Connect(ChatBox)
addMessage={[Function]}
messages={Array []}
/>
</div>
`;
Expand All @@ -23,6 +22,7 @@ exports[`App component should match the snapshot with a WelcomeModal if the user
/>
<Connect(WelcomeModal)
addMessage={[Function]}
type="button"
/>
</div>
`;
3 changes: 2 additions & 1 deletion src/containers/ChatBox/ChatBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ export class ChatBox extends Component {
}
}

export const mapStateToProps = ({ errorMsg }) => ({
export const mapStateToProps = ({ messages, errorMsg }) => ({
messages,
errorMsg
})

Expand Down
6 changes: 5 additions & 1 deletion src/containers/ChatBox/ChatBox.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ describe('mapStateToProps', () => {
errorMsg: ''
};
const expected = {
errorMsg: ''
errorMsg: '',
messages: [{
message: 'Hi there, my name is Dr. Watson. I understand that you have been feeling happy. That is super exciting to hear!',
isUser: false,
}]
};
const mappedProps = mapStateToProps(mockState);

Expand Down
6 changes: 4 additions & 2 deletions src/containers/WelcomeModal/WelcomeModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export class WelcomeModal extends Component {

handleSubmit = e => {
const { firstName, lastName, feeling } = this.state;
e.preventDefault();
if (firstName === '' || lastName === '' || feeling === '') {
return this.setState({error: "Please make sure you've filled everything out!"});
}
this.props.createUser({
id: Date.now(),
firstName,
Expand Down Expand Up @@ -68,7 +70,7 @@ export class WelcomeModal extends Component {
<option value="stressed">Stressed</option>
<option value="frustrated">Frustrated</option>
</select>
<button onClick={this.handleSubmit}>
<button type='button' onClick={this.handleSubmit}>
Take 5 minutes to check in!
</button>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ exports[`WelcomeModal component should display an error message if not all of th
</select>
<button
onClick={[Function]}
type="button"
>
Take 5 minutes to check in!
</button>
Expand Down Expand Up @@ -123,6 +124,7 @@ exports[`WelcomeModal component should match the snapshot if there are no errors
</select>
<button
onClick={[Function]}
type="button"
>
Take 5 minutes to check in!
</button>
Expand Down
2 changes: 2 additions & 0 deletions src/reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { combineReducers } from 'redux';
import { user } from './user';
import { errorMsg } from './errorMsg';
import { messages } from './messages';

const rootReducer = combineReducers({
user,
messages,
errorMsg
});

Expand Down
13 changes: 13 additions & 0 deletions src/reducers/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const messages = (state = [], action) => {
switch(action.type) {
case 'SUBMIT_MESSAGE':
return [...state, {
message: action.message,
isUser: action.isUser
}];
case 'DELETE_MESSAGES':
return [];
default:
return state;
}
}
36 changes: 36 additions & 0 deletions src/reducers/messages.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { messages } from './messages';

describe('messages reducer', () => {
it('should return the initial state', () => {
const expected = [];
const result = messages(undefined, {});
expect(result).toEqual(expected);
});

it('should return the state when SUBMIT_MESSAGE is the type', () => {
const expected = [{
message: 'puhlease',
isUser: true
}];
const mockAction = {
type: 'SUBMIT_MESSAGE',
message: 'puhlease',
isUser: true
};
const result = messages([], mockAction);
expect(result).toEqual(expected);
});

it('should return the state when DELETE_MESSAGES is the type', () => {
const expected = [];
const initialState = [{
message: 'puhlease',
isUser: true
}];
const mockAction = {
type: 'DELETE_MESSAGES'
}
const result = messages(initialState, mockAction);
expect(result).toEqual(expected);
})
});