From 7d7c62ba4c5486902a926e16e4607d9b0062ca73 Mon Sep 17 00:00:00 2001 From: Grace Date: Thu, 16 Jun 2022 01:37:03 -0700 Subject: [PATCH 1/7] Test first chat message to show sender name as ChatEntry component --- src/App.js | 7 ++-- src/App.test.js | 62 ++++++++++++++++---------------- src/components/ChatEntry.js | 2 +- src/components/ChatEntry.test.js | 16 ++++----- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/App.js b/src/App.js index c10859093..694f71b0a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,19 @@ import React from 'react'; import './App.css'; import chatMessages from './data/messages.json'; +import ChatEntry from './components/ChatEntry'; const App = () => { + const sender = chatMessages[0].sender; return (

Application title

- {/* Wave 01: Render one ChatEntry component - Wave 02: Render ChatLog component */} + {/* Wave 01: Render one ChatEntry component*/} + + {/* Wave 02: Render ChatLog component */}
); diff --git a/src/App.test.js b/src/App.test.js index ca75c71dd..ca5281135 100644 --- a/src/App.test.js +++ b/src/App.test.js @@ -1,53 +1,53 @@ -import React from 'react' -import App from './App' -import { render, screen, fireEvent } from '@testing-library/react' +import React from 'react'; +import App from './App'; +import { render, screen, fireEvent } from '@testing-library/react'; -describe('Wave 03: clicking like button and rendering App', () => { +describe.skip('Wave 03: clicking like button and rendering App', () => { test('that the correct number of likes is printed at the top', () => { // Arrange - const { container } = render() - let buttons = container.querySelectorAll('button.like') + const { container } = render(); + let buttons = container.querySelectorAll('button.like'); // Act - fireEvent.click(buttons[0]) - fireEvent.click(buttons[1]) - fireEvent.click(buttons[10]) + fireEvent.click(buttons[0]); + fireEvent.click(buttons[1]); + fireEvent.click(buttons[10]); // Assert - const countScreen = screen.getByText(/3 ❤️s/) - expect(countScreen).not.toBeNull() - }) + const countScreen = screen.getByText(/3 ❤️s/); + expect(countScreen).not.toBeNull(); + }); test('clicking button toggles heart and does not affect other buttons', () => { // Arrange - const { container } = render() - const buttons = container.querySelectorAll('button.like') - const firstButton = buttons[0] - const lastButton = buttons[buttons.length - 1] + const { container } = render(); + const buttons = container.querySelectorAll('button.like'); + const firstButton = buttons[0]; + const lastButton = buttons[buttons.length - 1]; // Act-Assert // click the first button - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('❤️') + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('❤️'); // check that all other buttons haven't changed for (let i = 1; i < buttons.length; i++) { - expect(buttons[i].innerHTML).toEqual('🤍') + expect(buttons[i].innerHTML).toEqual('🤍'); } // click the first button a few more times - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('🤍') - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('❤️') - fireEvent.click(firstButton) - expect(firstButton.innerHTML).toEqual('🤍') + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('🤍'); + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('❤️'); + fireEvent.click(firstButton); + expect(firstButton.innerHTML).toEqual('🤍'); // click the last button a couple times - fireEvent.click(lastButton) - expect(lastButton.innerHTML).toEqual('❤️') - fireEvent.click(lastButton) - expect(lastButton.innerHTML).toEqual('🤍') - }) -}) + fireEvent.click(lastButton); + expect(lastButton.innerHTML).toEqual('❤️'); + fireEvent.click(lastButton); + expect(lastButton.innerHTML).toEqual('🤍'); + }); +}); diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index b92f0b7b2..e347a280d 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; const ChatEntry = (props) => { return (
-

Replace with name of sender

+

{props.sender}

Replace with body of ChatEntry

Replace with TimeStamp component

diff --git a/src/components/ChatEntry.test.js b/src/components/ChatEntry.test.js index b69270c03..3c3af8e25 100644 --- a/src/components/ChatEntry.test.js +++ b/src/components/ChatEntry.test.js @@ -1,9 +1,9 @@ -import React from "react"; -import "@testing-library/jest-dom/extend-expect"; -import ChatEntry from "./ChatEntry"; -import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import React from 'react'; +import '@testing-library/jest-dom/extend-expect'; +import ChatEntry from './ChatEntry'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; -describe("Wave 01: ChatEntry", () => { +describe.skip('Wave 01: ChatEntry', () => { beforeEach(() => { render( { ); }); - test("renders without crashing and shows the sender", () => { + test('renders without crashing and shows the sender', () => { expect(screen.getByText(/Joe Biden/)).toBeInTheDocument(); }); - test("that it will display the body", () => { + test('that it will display the body', () => { expect(screen.getByText(/Get out by 8am/)).toBeInTheDocument(); }); - test("that it will display the time", () => { + test('that it will display the time', () => { expect(screen.getByText(/\d+ years ago/)).toBeInTheDocument(); }); }); From cfdaabbb10293de7477f376471fefd4023fdad19 Mon Sep 17 00:00:00 2001 From: Grace Date: Thu, 16 Jun 2022 02:02:29 -0700 Subject: [PATCH 2/7] ChatEntry displays body, propTypes added, Wave 1 tests passed but timestamp not visible --- src/App.js | 11 ++++++-- src/components/ChatEntry.js | 10 +++++-- src/components/ChatEntry.test.js | 2 +- src/components/ChatLog.test.js | 48 ++++++++++++++++---------------- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/App.js b/src/App.js index 694f71b0a..462c1f643 100644 --- a/src/App.js +++ b/src/App.js @@ -4,7 +4,10 @@ import chatMessages from './data/messages.json'; import ChatEntry from './components/ChatEntry'; const App = () => { - const sender = chatMessages[0].sender; + const senderData = chatMessages[0].sender; + const bodyData = chatMessages[0].body; + const timeStampData = chatMessages[0].timeStamp; + return (
@@ -12,7 +15,11 @@ const App = () => {
{/* Wave 01: Render one ChatEntry component*/} - + {/* Wave 02: Render ChatLog component */}
diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index e347a280d..a818d3792 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -1,14 +1,17 @@ import React from 'react'; import './ChatEntry.css'; import PropTypes from 'prop-types'; +import TimeStamp from './TimeStamp'; const ChatEntry = (props) => { return (

{props.sender}

-

Replace with body of ChatEntry

-

Replace with TimeStamp component

+

{props.body}

+

+ +

@@ -16,7 +19,8 @@ const ChatEntry = (props) => { }; ChatEntry.propTypes = { - //Fill with correct proptypes + sender: PropTypes.string.isRequired, + body: PropTypes.string, }; export default ChatEntry; diff --git a/src/components/ChatEntry.test.js b/src/components/ChatEntry.test.js index 3c3af8e25..4a9a2b09f 100644 --- a/src/components/ChatEntry.test.js +++ b/src/components/ChatEntry.test.js @@ -3,7 +3,7 @@ import '@testing-library/jest-dom/extend-expect'; import ChatEntry from './ChatEntry'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; -describe.skip('Wave 01: ChatEntry', () => { +describe('Wave 01: ChatEntry', () => { beforeEach(() => { render( { +describe.skip('Wave 02: ChatLog', () => { beforeEach(() => { render(); }); - test("renders without crashing and shows all the names", () => { + test('renders without crashing and shows all the names', () => { [ { - name: "Vladimir", + name: 'Vladimir', numChats: 3, }, { - name: "Estragon", + name: 'Estragon', numChats: 2, }, ].forEach((person) => { @@ -56,7 +56,7 @@ describe("Wave 02: ChatLog", () => { }); }); - test("renders an empty list without crashing", () => { + test('renders an empty list without crashing', () => { const element = render(); expect(element).not.toBeNull(); }); From 858793900cb01eafc43b94654f1e6d5b60c131d4 Mon Sep 17 00:00:00 2001 From: Grace Date: Thu, 16 Jun 2022 09:51:59 -0700 Subject: [PATCH 3/7] Added ChatLog component, pass Wave 1 with timestamp working --- src/App.js | 3 ++- src/components/ChatLog.js | 23 +++++++++++++++++++++++ src/components/ChatLog.test.js | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/components/ChatLog.js diff --git a/src/App.js b/src/App.js index 462c1f643..db1c2378c 100644 --- a/src/App.js +++ b/src/App.js @@ -2,6 +2,7 @@ import React from 'react'; import './App.css'; import chatMessages from './data/messages.json'; import ChatEntry from './components/ChatEntry'; +import ChatLog from './components/ChatLog'; const App = () => { const senderData = chatMessages[0].sender; @@ -18,7 +19,7 @@ const App = () => { {/* Wave 02: Render ChatLog component */} diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js new file mode 100644 index 000000000..a340a8ea0 --- /dev/null +++ b/src/components/ChatLog.js @@ -0,0 +1,23 @@ +import React from 'react'; +import './ChatLog.css'; +import PropTypes from 'prop-types'; +import ChatEntry from './ChatEntry'; + +const ChatLog = (props) => { + const chatEntries = props.chatEntries.map((entries) => { + return ( +
+ +
+ ); + }); + return
{chatEntries}
; +}; + +ChatLog.propTypes = {}; + +export default ChatLog; diff --git a/src/components/ChatLog.test.js b/src/components/ChatLog.test.js index 442d05215..5bafee291 100644 --- a/src/components/ChatLog.test.js +++ b/src/components/ChatLog.test.js @@ -31,7 +31,7 @@ const LOG = [ }, ]; -describe.skip('Wave 02: ChatLog', () => { +describe('Wave 02: ChatLog', () => { beforeEach(() => { render(); }); From d0b9bd4a5e94ad1e064a5104b3d774a9306ee86a Mon Sep 17 00:00:00 2001 From: Grace Date: Thu, 16 Jun 2022 10:01:16 -0700 Subject: [PATCH 4/7] Render ChatLog component with ChatEntry entries, pass Wave 2 --- src/App.js | 12 +++++++----- src/components/ChatLog.js | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/App.js b/src/App.js index db1c2378c..7fe2d6666 100644 --- a/src/App.js +++ b/src/App.js @@ -5,9 +5,10 @@ import ChatEntry from './components/ChatEntry'; import ChatLog from './components/ChatLog'; const App = () => { - const senderData = chatMessages[0].sender; - const bodyData = chatMessages[0].body; - const timeStampData = chatMessages[0].timeStamp; + // const senderData = chatMessages[0].sender; + // const bodyData = chatMessages[0].body; + // const timeStampData = chatMessages[0].timeStamp; + const messageData = chatMessages; return (
@@ -16,12 +17,13 @@ const App = () => {
{/* Wave 01: Render one ChatEntry component*/} - + > */} {/* Wave 02: Render ChatLog component */} +
); diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index a340a8ea0..5674816b0 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -4,13 +4,13 @@ import PropTypes from 'prop-types'; import ChatEntry from './ChatEntry'; const ChatLog = (props) => { - const chatEntries = props.chatEntries.map((entries) => { + const chatEntries = props.entries.map((entry) => { return (
); From d8400f273592aa0ea2878c51939add9f0b082bf7 Mon Sep 17 00:00:00 2001 From: Grace Date: Fri, 17 Jun 2022 15:04:55 -0700 Subject: [PATCH 5/7] Define toggleLiked function to update ChatEntry liked button --- src/App.js | 21 ++++++++++++++------- src/components/ChatEntry.js | 10 +++++++++- src/components/ChatLog.js | 3 +++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/App.js b/src/App.js index 7fe2d6666..5e3b91265 100644 --- a/src/App.js +++ b/src/App.js @@ -1,15 +1,22 @@ -import React from 'react'; +import React, { useState } from 'react'; import './App.css'; import chatMessages from './data/messages.json'; -import ChatEntry from './components/ChatEntry'; import ChatLog from './components/ChatLog'; const App = () => { - // const senderData = chatMessages[0].sender; - // const bodyData = chatMessages[0].body; - // const timeStampData = chatMessages[0].timeStamp; - const messageData = chatMessages; + const [messages, setMessages] = useState(chatMessages); + const toggleLiked = (id) => { + const newMessages = []; + for (const message of messages) { + if (message.id === id) { + message.liked = !message.liked; + } + newMessages.push(message); + } + setMessages(newMessages); + console.log('toggleLiked called'); + }; return (
@@ -23,7 +30,7 @@ const App = () => { timeStamp={timeStampData} > */} {/* Wave 02: Render ChatLog component */} - +
); diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index a818d3792..d54310d5d 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -4,6 +4,12 @@ import PropTypes from 'prop-types'; import TimeStamp from './TimeStamp'; const ChatEntry = (props) => { + const toggleLiked = () => { + props.likedCallback(props.id); + }; + + const likeButton = props.liked ? '❤️' : '🤍'; + return (

{props.sender}

@@ -12,7 +18,9 @@ const ChatEntry = (props) => {

- +
); diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 5674816b0..73ad56967 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -8,9 +8,12 @@ const ChatLog = (props) => { return (
); From 0d9a05d3cbafbf70ba927477ec7a6442814448b3 Mon Sep 17 00:00:00 2001 From: Grace Date: Tue, 21 Jun 2022 15:26:01 -0700 Subject: [PATCH 6/7] Define countLiked function to show liked messages count in header, wave 3 tests pass individually --- src/App.js | 15 ++++++++++++++- src/App.test.js | 2 +- src/components/ChatEntry.js | 6 ++++-- src/components/ChatLog.js | 15 +++++++++++++-- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/App.js b/src/App.js index 5e3b91265..58488b8d1 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,17 @@ import ChatLog from './components/ChatLog'; const App = () => { const [messages, setMessages] = useState(chatMessages); + const countLiked = () => { + let count = 0; + for (let message of messages) { + if (message.liked === true) { + count += 1; + } + } + console.log(count); + return count; + }; + const toggleLiked = (id) => { const newMessages = []; for (const message of messages) { @@ -17,12 +28,14 @@ const App = () => { setMessages(newMessages); console.log('toggleLiked called'); }; + return (

Application title

+

{countLiked()} ❤️s

-
+
{/* Wave 01: Render one ChatEntry component*/} {/* { +describe('Wave 03: clicking like button and rendering App', () => { test('that the correct number of likes is printed at the top', () => { // Arrange const { container } = render(); diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index d54310d5d..a55601f1e 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -4,12 +4,14 @@ import PropTypes from 'prop-types'; import TimeStamp from './TimeStamp'; const ChatEntry = (props) => { + // update the icon using props.liked + const likeButton = props.liked === true ? '❤️' : '🤍'; + + // clicking like button will trigger likedCallback const toggleLiked = () => { props.likedCallback(props.id); }; - const likeButton = props.liked ? '❤️' : '🤍'; - return (

{props.sender}

diff --git a/src/components/ChatLog.js b/src/components/ChatLog.js index 73ad56967..87f7fc938 100644 --- a/src/components/ChatLog.js +++ b/src/components/ChatLog.js @@ -6,7 +6,7 @@ import ChatEntry from './ChatEntry'; const ChatLog = (props) => { const chatEntries = props.entries.map((entry) => { return ( -
+
{ return
{chatEntries}
; }; -ChatLog.propTypes = {}; +ChatLog.propTypes = { + entries: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number.isRequired, + sender: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + timeStamp: PropTypes.string.isRequired, + liked: PropTypes.bool.isRequired, + }) + ), + likedCallback: PropTypes.func.isRequired, +}; export default ChatLog; From df3ff8fe8e8c1393505e40a7fa567498490a4a23 Mon Sep 17 00:00:00 2001 From: Grace Date: Tue, 21 Jun 2022 15:46:16 -0700 Subject: [PATCH 7/7] Add ternary logic to set class depending on if name of sender is local or remote (optional enhancement) --- src/App.js | 7 +++++-- src/components/ChatEntry.js | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/App.js b/src/App.js index 58488b8d1..ea175189b 100644 --- a/src/App.js +++ b/src/App.js @@ -19,7 +19,8 @@ const App = () => { const toggleLiked = (id) => { const newMessages = []; - for (const message of messages) { + const messagesCopy = JSON.parse(JSON.stringify(messages)); + for (const message of messagesCopy) { if (message.id === id) { message.liked = !message.liked; } @@ -32,7 +33,9 @@ const App = () => { return (
-

Application title

+

+ Chat between {chatMessages[0].sender} and {chatMessages[1].sender} +

{countLiked()} ❤️s

diff --git a/src/components/ChatEntry.js b/src/components/ChatEntry.js index a55601f1e..db7692938 100644 --- a/src/components/ChatEntry.js +++ b/src/components/ChatEntry.js @@ -7,13 +7,17 @@ const ChatEntry = (props) => { // update the icon using props.liked const likeButton = props.liked === true ? '❤️' : '🤍'; + // determine local or remote sender + const senderType = + props.sender === 'Vladimir' ? 'chat-entry local' : 'chat-entry remote'; + // clicking like button will trigger likedCallback const toggleLiked = () => { props.likedCallback(props.id); }; return ( -
+

{props.sender}

{props.body}