Upload 5.16
This commit is contained in:
462
part5/bloglist-frontend/package-lock.json
generated
462
part5/bloglist-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,6 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"axios": "^1.2.3",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
@@ -18,7 +15,8 @@
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"eslint": "eslint ."
|
||||
"eslint": "eslint .",
|
||||
"dev": "NODE_ENV=development nodemon index.js"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
@@ -40,6 +38,11 @@
|
||||
},
|
||||
"proxy": "http://localhost:3001/",
|
||||
"devDependencies": {
|
||||
"eslint-plugin-jest": "^27.2.2"
|
||||
}
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"eslint-plugin-jest": "^27.2.2",
|
||||
"nodemon": "^2.0.22"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import Blog from './components/Blog'
|
||||
import { BlogForm } from './components/BlogForm'
|
||||
import Notification from './components/Notification'
|
||||
import blogService from './services/blogs'
|
||||
import loginService from './services/login'
|
||||
import Togglable from './components/Togglable'
|
||||
import Blog from './components/Blog.js'
|
||||
import { BlogForm } from './components/BlogForm.js'
|
||||
import Notification from './components/Notification.js'
|
||||
import blogService from './services/blogs.js'
|
||||
import loginService from './services/login.js'
|
||||
import Togglable from './components/Togglable.js'
|
||||
|
||||
const App = () => {
|
||||
const [blogs, setBlogs] = useState([])
|
||||
@@ -24,12 +24,12 @@ const App = () => {
|
||||
setSuccessMessage(message)
|
||||
setTimeout(() => {
|
||||
setSuccessMessage(null)
|
||||
}, 5000)
|
||||
}, 3000)
|
||||
} else if (type === 'error') {
|
||||
setErrorMessage(message)
|
||||
setTimeout(() => {
|
||||
setErrorMessage(null)
|
||||
}, 5000)
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ const App = () => {
|
||||
<input
|
||||
type="text"
|
||||
value={username}
|
||||
name="Username"
|
||||
name="username"
|
||||
onChange={({ target }) => setUsername(target.value)}
|
||||
/>
|
||||
</div>
|
||||
@@ -122,7 +122,7 @@ const App = () => {
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
name="Password"
|
||||
name="password"
|
||||
onChange={({ target }) => setPassword(target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import blogService from '../services/blogs'
|
||||
import Togglable from './Togglable'
|
||||
import blogService from '../services/blogs.js'
|
||||
import Togglable from './Togglable.js'
|
||||
|
||||
const Blog = ({ blog, setNotification, removeBlog }) => {
|
||||
const blogStyle = {
|
||||
@@ -26,13 +26,26 @@ const Blog = ({ blog, setNotification, removeBlog }) => {
|
||||
})
|
||||
}
|
||||
|
||||
const findUser = async (blogId) => {
|
||||
const blogs = await blogService.getAll()
|
||||
const blogToFind = blogs.filter((blog) => blog.user).find((blog) => blog.id === blogId)
|
||||
|
||||
blog.user = blogToFind?.user
|
||||
}
|
||||
|
||||
if (!blog.user) {
|
||||
findUser(blog.id)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={blogStyle}>
|
||||
<div style={blogStyle} className="blog">
|
||||
<div>
|
||||
<em>{blog.title}</em>
|
||||
<Togglable buttonLabel="View">
|
||||
<em>
|
||||
{blog.title} by {blog.author}
|
||||
</em>
|
||||
<Togglable buttonLabel="View" className="blogButton">
|
||||
<ul>
|
||||
<li> Author: {blog.author}</li>
|
||||
<li>User: {blog.user?.name || 'Unknown' }</li>
|
||||
<li> URL: {blog.url}</li>
|
||||
<li>
|
||||
{likes} likes
|
||||
|
||||
88
part5/bloglist-frontend/src/components/Blog.test.js
Normal file
88
part5/bloglist-frontend/src/components/Blog.test.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import React from 'react'
|
||||
import '@testing-library/jest-dom/extend-expect'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { Blog } from './Blog'
|
||||
import { BlogForm } from './BlogForm'
|
||||
|
||||
const testSubject = {
|
||||
blog: {
|
||||
id: '62e5309ba56f29d013ebe184',
|
||||
author: 'Andrew Trieu',
|
||||
title: 'How to be a good programmer',
|
||||
url: 'https://lmgtfy.app/',
|
||||
likes: 10000000,
|
||||
user: {
|
||||
username: 'andyyyyy',
|
||||
name: 'Andrew Trieu',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
describe('test for blogs', () => {
|
||||
test('blog\'s title and author is rendered, but not url or likes', () => {
|
||||
const { container } = render(
|
||||
<Blog blog={testSubject.blog}/>
|
||||
)
|
||||
|
||||
const div = container.querySelector('.blog')
|
||||
expect(div).toHaveTextContent('How to be a good programmer by Andrew Trieu')
|
||||
})
|
||||
|
||||
test('blog\'s url and likes are rendered when button is clicked', async () => {
|
||||
render(<Blog blog={testSubject.blog}/>)
|
||||
|
||||
const user = userEvent.setup()
|
||||
const button = screen.getByText('How to be a good programmer by Andrew Trieu')
|
||||
await user.click(button)
|
||||
|
||||
const url = screen.getByText('https://lmgtfy.app/')
|
||||
expect(url).toBeDefined()
|
||||
|
||||
const likes = screen.getByText('10000000')
|
||||
expect(likes).toBeDefined()
|
||||
})
|
||||
|
||||
test('clicking the like button twice calls event handler twice', async () => {
|
||||
// Blog does not have updateBlog function
|
||||
const mockHandler = jest.fn()
|
||||
|
||||
render(<Blog blog={testSubject.blog}/>)
|
||||
|
||||
const user = userEvent.setup()
|
||||
const button = screen.getByText('How to be a good programmer by Andrew Trieu')
|
||||
await user.click(button)
|
||||
|
||||
const likeButton = screen.getByText('+')
|
||||
await user.click(likeButton)
|
||||
await user.click(likeButton)
|
||||
|
||||
// 3 times because the blog is viewed once and the like button is clicked twice
|
||||
expect(mockHandler.mock.calls).toHaveLength(3)
|
||||
})
|
||||
|
||||
test('new blog form calls event handler with correct details', async () => {
|
||||
const createBlog = jest.fn()
|
||||
|
||||
const component = render(
|
||||
<BlogForm createBlog={createBlog}/>
|
||||
)
|
||||
|
||||
const user = userEvent.setup()
|
||||
|
||||
const title = component.container.getElementsByName('title')
|
||||
const author = component.container.getElementsByName('author')
|
||||
const url = component.container.getElementsByName('urlAddress')
|
||||
const form = component.container.getElementsByName('form')
|
||||
|
||||
await user.type(title, 'How to be a good programmer')
|
||||
await user.type(author, 'Andrew Trieu')
|
||||
await user.type(url, 'https://lmgtfy.app/')
|
||||
await user.submit(form)
|
||||
|
||||
expect(createBlog.mock.calls).toHaveLength(1)
|
||||
expect(createBlog.mock.calls[0][0].title).toBe('How to be a good programmer')
|
||||
expect(createBlog.mock.calls[0][0].author).toBe('Andrew Trieu')
|
||||
expect(createBlog.mock.calls[0][0].url).toBe('https://lmgtfy.app/')
|
||||
})
|
||||
})
|
||||
@@ -24,7 +24,7 @@ export const BlogForm = ({ createBlog }) => {
|
||||
return (
|
||||
<div>
|
||||
<h2> Create new blog</h2>
|
||||
<form onSubmit={addBlog}>
|
||||
<form onSubmit={addBlog} name='form'>
|
||||
<div>
|
||||
Title:
|
||||
<input
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App'
|
||||
import App from './App.js'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(<App />)
|
||||
Reference in New Issue
Block a user