mirror of
https://github.com/hknsh/project-knedita.git
synced 2024-11-28 17:41:15 +00:00
Created new tests (some of they are not working)
This commit is contained in:
parent
d07ccddb10
commit
34604fce27
27 changed files with 1639 additions and 4234 deletions
12
README.md
12
README.md
|
@ -5,16 +5,24 @@ A simple social media created with React Native and Express.
|
|||
|
||||
## To-do - Backend
|
||||
|
||||
- Create/update/delete Posts
|
||||
- Create/update/delete Posts ✅
|
||||
- Create/update/delete Users ✅
|
||||
- Password recuperation
|
||||
- Two step verification
|
||||
- Able to choose a profile picture
|
||||
- Probably gonna use LocalStack to mock Amazon S3
|
||||
- Following/unfollowing features
|
||||
- Like posts
|
||||
- Probably pinned posts
|
||||
- Authentication ✅
|
||||
- Add more verification (like, if the password is too short)
|
||||
- Set display name
|
||||
- Set display name ✅
|
||||
- Add rate limit
|
||||
|
||||
## Known problems
|
||||
|
||||
- Tests taking too long
|
||||
- Some tests will give error 401, for now just try until it works
|
||||
|
||||
## License
|
||||
|
||||
|
|
5515
package-lock.json
generated
5515
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,7 @@
|
|||
"author": "Cookie",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@swc/cli": "^0.1.62",
|
||||
"@swc/core": "^1.3.66",
|
||||
"@swc/jest": "^0.2.26",
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Post" ALTER COLUMN "updatedAt" DROP DEFAULT;
|
|
@ -26,5 +26,5 @@ model Post {
|
|||
authorId String
|
||||
author User @relation(fields: [authorId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
|
@ -17,6 +17,6 @@ const postsRouter = Router()
|
|||
postsRouter.post('/create', ensureAuthenticated, postCreateController)
|
||||
postsRouter.post('/delete', ensureAuthenticated, postDeleteController)
|
||||
postsRouter.get('/info', postInfoController)
|
||||
postsRouter.put('/update', postUpdateController)
|
||||
postsRouter.put('/update', ensureAuthenticated, postUpdateController)
|
||||
|
||||
export default postsRouter
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { posts } from '../../services/index'
|
||||
import { post } from '../../services/index'
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
async function postCreateController (req: Request, res: Response): Promise<void> {
|
||||
const { content } = req.body
|
||||
const id: string = req.user?.id ?? ''
|
||||
|
||||
const result = await posts.postCreate(content, id)
|
||||
const result = await post.create(content, id)
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { posts } from '../../services/index'
|
||||
import { post } from '../../services/index'
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
async function postDeleteController (req: Request, res: Response): Promise<void> {
|
||||
const userId = req.user?.id ?? ''
|
||||
const postId = req.body.postId
|
||||
|
||||
const result = await posts.postDelete(postId, userId)
|
||||
const result = await post.delete(postId, userId)
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { posts } from '../../services/index'
|
||||
import { post } from '../../services/index'
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
async function postInfoController (req: Request, res: Response): Promise<void> {
|
||||
|
@ -11,7 +11,7 @@ async function postInfoController (req: Request, res: Response): Promise<void> {
|
|||
return
|
||||
}
|
||||
|
||||
const result = await posts.postInfo(id)
|
||||
const result = await post.info(id)
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import { posts } from '../../services/index'
|
||||
import { post } from '../../services/index'
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
async function postUpdateController (req: Request, res: Response): Promise<void> {
|
||||
const result = await posts.postUpdate()
|
||||
const { postId, content } = req.body
|
||||
const userId = req.user?.id ?? ''
|
||||
|
||||
const result = await post.update(postId, content, userId)
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { users } from '../../services/index'
|
||||
import { user } from '../../services/index'
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
async function userAuthController (req: Request, res: Response): Promise<void> {
|
||||
const { email, password } = req.body
|
||||
|
||||
const result = await users.userAuth(email, password)
|
||||
const result = await user.auth(email, password)
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { users } from '../../services'
|
||||
import { user } from '../../services'
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
async function userDeleteController (req: Request, res: Response): Promise<void> {
|
||||
const userId = req.user?.id ?? ''
|
||||
const result = await users.userDelete(userId)
|
||||
const result = await user.delete(userId)
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { users } from '../../services'
|
||||
import { user } from '../../services'
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
async function userInfoController (req: Request, res: Response): Promise<void> {
|
||||
|
@ -11,7 +11,7 @@ async function userInfoController (req: Request, res: Response): Promise<void> {
|
|||
return
|
||||
}
|
||||
|
||||
const result = await users.userInfo(username.toLowerCase())
|
||||
const result = await user.info(username.toLowerCase())
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { users } from '../../services'
|
||||
import { user } from '../../services'
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
async function userSignupController (req: Request, res: Response): Promise<void> {
|
||||
const { username, email, password } = req.body
|
||||
|
||||
const result = await users.userSignup(username, email, password)
|
||||
const result = await user.signup(username, email, password)
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import { users } from '../../services'
|
||||
import { user } from '../../services'
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
async function userUpdateController (req: Request, res: Response): Promise<void> {
|
||||
const result = await users.userUpdate()
|
||||
const { email, displayName, username } = req.body
|
||||
const id = req.user?.id ?? ''
|
||||
|
||||
const result = await user.update({ id, email, displayName, username })
|
||||
|
||||
if (result instanceof Error) {
|
||||
res.status(400).json({
|
||||
|
|
10
src/interfaces/user.ts
Normal file
10
src/interfaces/user.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
interface userPayload {
|
||||
id?: string
|
||||
displayName?: string | null
|
||||
username?: string
|
||||
password?: string
|
||||
email?: string
|
||||
token?: string
|
||||
}
|
||||
|
||||
export default userPayload
|
|
@ -49,7 +49,7 @@ async function ensureAuthenticated (req: Request, res: Response, next: NextFunct
|
|||
return next()
|
||||
} catch (error) {
|
||||
res.status(401).json({
|
||||
error: (error as Error).message
|
||||
error: `JWT Error: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,20 +10,20 @@ import postInfoService from './posts/post-info'
|
|||
import postUpdateService from './posts/post-update'
|
||||
|
||||
// User services
|
||||
const users = {
|
||||
userAuth: userAuthService,
|
||||
userDelete: userDeleteService,
|
||||
userInfo: userInfoService,
|
||||
userSignup: userSignupService,
|
||||
userUpdate: userUpdateService
|
||||
const user = {
|
||||
auth: userAuthService,
|
||||
delete: userDeleteService,
|
||||
info: userInfoService,
|
||||
signup: userSignupService,
|
||||
update: userUpdateService
|
||||
}
|
||||
|
||||
// Post services
|
||||
const posts = {
|
||||
postCreate: postCreateService,
|
||||
postDelete: postDeleteService,
|
||||
postInfo: postInfoService,
|
||||
postUpdate: postUpdateService
|
||||
const post = {
|
||||
create: postCreateService,
|
||||
delete: postDeleteService,
|
||||
info: postInfoService,
|
||||
update: postUpdateService
|
||||
}
|
||||
|
||||
export { users, posts }
|
||||
export { user, post }
|
||||
|
|
|
@ -3,8 +3,6 @@ import prisma from '../../db'
|
|||
async function postDeleteService (postId: string, userId: string): Promise<Object | Error> {
|
||||
const post = await prisma.post.findFirst({ where: { id: postId } })
|
||||
|
||||
console.log(postId, userId)
|
||||
|
||||
if (post === null) {
|
||||
return new Error('Post not found')
|
||||
}
|
||||
|
|
|
@ -1,6 +1,45 @@
|
|||
import prisma from '../../db'
|
||||
|
||||
async function postUpdateService (): Promise<Object | Error> {
|
||||
return {}
|
||||
async function postUpdateService (postId: string, content: string, userId: string): Promise<Object | Error> {
|
||||
const post = await prisma.post.findFirst({ where: { id: postId } })
|
||||
|
||||
if (post === null) {
|
||||
return new Error('Post not found')
|
||||
}
|
||||
|
||||
if (await prisma.user.findFirst({ where: { id: userId } }) === null) {
|
||||
return new Error('User not found')
|
||||
}
|
||||
|
||||
if (post.authorId !== userId) {
|
||||
return new Error('Forbidden')
|
||||
}
|
||||
|
||||
if (post.content === content.trim()) {
|
||||
content = post.content
|
||||
}
|
||||
|
||||
const updatedPost = await prisma.post.update({
|
||||
where: {
|
||||
id: postId
|
||||
},
|
||||
data: {
|
||||
content
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
content: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
author: {
|
||||
select: {
|
||||
displayName: true,
|
||||
username: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return updatedPost
|
||||
}
|
||||
export default postUpdateService
|
||||
|
|
|
@ -1,7 +1,50 @@
|
|||
import userPayload from '../../interfaces/user'
|
||||
import prisma from '../../db'
|
||||
|
||||
async function userUpdateService (): Promise<Object | Error> {
|
||||
return {}
|
||||
async function userUpdateService ({ id, email, displayName, username }: userPayload): Promise<Object | Error> {
|
||||
const user = await prisma.user.findFirst({ where: { id } })
|
||||
|
||||
if (user === null) {
|
||||
return new Error('User not found')
|
||||
}
|
||||
|
||||
if (email !== undefined && email.trim() !== user.email) {
|
||||
const existingUser = await prisma.user.findFirst({ where: { email } })
|
||||
if ((existingUser != null) && existingUser.email !== user.email) {
|
||||
return new Error('Email already in use')
|
||||
}
|
||||
}
|
||||
|
||||
if (username !== undefined && username.trim() !== user.username) {
|
||||
const existingUser = await prisma.user.findFirst({ where: { username } })
|
||||
if ((existingUser != null) && existingUser.username !== user.username) {
|
||||
return new Error('Username already in use')
|
||||
}
|
||||
}
|
||||
|
||||
if (user.id !== id) {
|
||||
return new Error('Forbidden')
|
||||
}
|
||||
|
||||
// TODO: /user/change-password | /user/change-email
|
||||
|
||||
const updatedUser = await prisma.user.update({
|
||||
where: {
|
||||
id
|
||||
},
|
||||
data: {
|
||||
email: email ?? user.email,
|
||||
displayName: displayName ?? user.displayName,
|
||||
username: username ?? user.username
|
||||
},
|
||||
select: {
|
||||
displayName: true,
|
||||
username: true,
|
||||
createdAt: true
|
||||
}
|
||||
})
|
||||
|
||||
return updatedUser
|
||||
}
|
||||
|
||||
export default userUpdateService
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
import prisma from '../../db'
|
||||
import app from '../../app'
|
||||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
|
||||
let token = ''
|
||||
let token = ''; let username = ''
|
||||
|
||||
describe('POST /post/create', () => {
|
||||
beforeAll(async () => {
|
||||
await request(app).post('/user/signup').send({
|
||||
username: 'dummmyuser7',
|
||||
email: 'random1@email.com',
|
||||
password: 'pass'
|
||||
})
|
||||
const user = await signUpNewUser()
|
||||
|
||||
const response = await request(app).post('/user/auth').send({
|
||||
email: 'random1@email.com',
|
||||
password: 'pass'
|
||||
}).expect(200)
|
||||
|
||||
token = response.body.token
|
||||
token = user.token ?? ''
|
||||
username = user.username ?? ''
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
|
@ -29,7 +22,7 @@ describe('POST /post/create', () => {
|
|||
|
||||
await prisma.user.deleteMany({
|
||||
where: {
|
||||
username: 'dummmyuser7'
|
||||
username
|
||||
}
|
||||
})
|
||||
await prisma.$disconnect()
|
||||
|
|
|
@ -2,8 +2,18 @@ import prisma from '../../db'
|
|||
import app from '../../app'
|
||||
import request from 'supertest'
|
||||
|
||||
// Post id at the body
|
||||
// User token at the header
|
||||
|
||||
// Create new post
|
||||
// Create new user
|
||||
// Auth the user
|
||||
// Create the post with the token
|
||||
// Send the request with the post id and the token
|
||||
// Should delete the post successfully
|
||||
|
||||
describe('DELETE /post/delete', () => {
|
||||
test('should ignore', () => {
|
||||
it('should delete the post successfully', async () => {
|
||||
expect(1 + 1).toBe(2)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,9 +1,52 @@
|
|||
import prisma from '../../db'
|
||||
import app from '../../app'
|
||||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
|
||||
let postId = ''; let username = ''
|
||||
|
||||
describe('POST /post/info', () => {
|
||||
test('should ignore', () => {
|
||||
expect(1 + 1).toBe(2)
|
||||
beforeAll(async () => {
|
||||
const user = await signUpNewUser()
|
||||
|
||||
const token = user.token ?? ''
|
||||
|
||||
const post = await request(app).post('/post/create').send({
|
||||
content: 'nothing to see here!'
|
||||
}).set('Authorization', `Bearer ${token}`).expect(200)
|
||||
|
||||
username = user.username ?? ''
|
||||
postId = post.body.id
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma.post.deleteMany({
|
||||
where: {
|
||||
id: postId
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.user.deleteMany({
|
||||
where: {
|
||||
username
|
||||
}
|
||||
})
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
|
||||
it('should respond with 200 status code and return some info about the post', async () => {
|
||||
const response = await request(app).get(`/post/info?id=${postId}`).expect(200)
|
||||
|
||||
expect(response.body).toHaveProperty('id')
|
||||
expect(response.body).toHaveProperty('content')
|
||||
expect(response.body).toHaveProperty('createdAt')
|
||||
expect(response.body).toHaveProperty('updatedAt')
|
||||
expect(response.body).toHaveProperty('author')
|
||||
})
|
||||
|
||||
it('should respond with 400 status code if the post does not exists', async () => {
|
||||
const response = await request(app).get('/post/info?id=randominfohere').expect(400)
|
||||
|
||||
expect(response.body).toHaveProperty('error')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
import prisma from '../../db'
|
||||
import app from '../../app'
|
||||
import request from 'supertest'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
|
||||
let token = ''
|
||||
|
||||
describe('DELETE /user/delete', () => {
|
||||
test('should ignore', () => {
|
||||
expect(1 + 1).toBe(2)
|
||||
beforeAll(async () => {
|
||||
const user = await signUpNewUser()
|
||||
console.log(user)
|
||||
token = user.token ?? ''
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
|
||||
it('should delete the user successfully', async () => {
|
||||
await request(app).post('/user/delete')
|
||||
.set('Authorization', `Bearer ${token}`)
|
||||
.expect(200)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,9 +1,40 @@
|
|||
import prisma from '../../db'
|
||||
import app from '../../app'
|
||||
import request from 'supertest'
|
||||
import app from '../../app'
|
||||
import prisma from '../../db'
|
||||
import signUpNewUser from '../utils/create-user'
|
||||
|
||||
let token = ''; let username = ''
|
||||
|
||||
describe('PUT /user/update', () => {
|
||||
test('should ignore', () => {
|
||||
expect(1 + 1).toBe(2)
|
||||
beforeAll(async () => {
|
||||
const user = await signUpNewUser()
|
||||
|
||||
username = user.username
|
||||
token = user.token
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await prisma.user.deleteMany({
|
||||
where: {
|
||||
username
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
|
||||
it('should update the user successfully', async () => {
|
||||
const fieldsToUpdate = {
|
||||
displayName: 'Cookie'
|
||||
}
|
||||
|
||||
const response = await request(app)
|
||||
.put('/user/update')
|
||||
.send(fieldsToUpdate)
|
||||
.set('Authorization', `Bearer ${token}`).expect(200)
|
||||
|
||||
expect(response.body).toHaveProperty('displayName')
|
||||
expect(response.body).toHaveProperty('username')
|
||||
expect(response.body).toHaveProperty('createdAt')
|
||||
})
|
||||
})
|
||||
|
|
33
src/tests/utils/create-user.ts
Normal file
33
src/tests/utils/create-user.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import app from '../../app'
|
||||
import request from 'supertest'
|
||||
import { faker } from '@faker-js/faker'
|
||||
import userPayload from '../../interfaces/user'
|
||||
|
||||
async function signUpNewUser (): Promise<userPayload> {
|
||||
// To avoid conflicts with existing usernames or emails
|
||||
const username = faker.internet.userName().toLowerCase()
|
||||
const email = faker.internet.email().toLowerCase()
|
||||
const password = faker.internet.password()
|
||||
|
||||
await request(app).post('/user/signup').send({
|
||||
username,
|
||||
email,
|
||||
password
|
||||
})
|
||||
|
||||
const response = await request(app)
|
||||
.post('/user/auth')
|
||||
.send({
|
||||
email,
|
||||
password
|
||||
})
|
||||
|
||||
return {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
token: response.body.token
|
||||
}
|
||||
}
|
||||
|
||||
export default signUpNewUser
|
Loading…
Reference in a new issue