Created new tests (some of they are not working)

This commit is contained in:
Hackntosh 2023-06-27 20:24:26 -03:00
parent d07ccddb10
commit 34604fce27
27 changed files with 1639 additions and 4234 deletions

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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",

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Post" ALTER COLUMN "updatedAt" DROP DEFAULT;

View file

@ -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
}

View file

@ -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

View file

@ -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({

View file

@ -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({

View file

@ -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({

View file

@ -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({

View file

@ -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({

View file

@ -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({

View file

@ -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({

View file

@ -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({

View file

@ -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
View file

@ -0,0 +1,10 @@
interface userPayload {
id?: string
displayName?: string | null
username?: string
password?: string
email?: string
token?: string
}
export default userPayload

View file

@ -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}`
})
}
}

View file

@ -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 }

View file

@ -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')
}

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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)
})
})

View file

@ -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')
})
})

View file

@ -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)
})
})

View file

@ -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')
})
})

View 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