feat: implemented unit tests

This commit is contained in:
Hackntosh 2023-09-30 17:15:19 -03:00
parent e31b7d083e
commit f73a12e454
15 changed files with 2158 additions and 28 deletions

1767
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,8 @@
"prisma:generate": "npx prisma generate",
"prisma:seed": "prisma db seed",
"prisma:studio": "npx prisma studio",
"prod:start": "npx prisma migrate deploy && pm2-runtime start dist/server.js"
"prod:start": "npx prisma migrate deploy && pm2-runtime start dist/server.js",
"test": "vitest run"
},
"ts-standard": {
"project": "tsconfig.json",
@ -62,7 +63,9 @@
"supertest": "^6.3.3",
"ts-node-dev": "^2.0.0",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.6"
"typescript": "^5.1.6",
"vite-tsconfig-paths": "^4.2.1",
"vitest": "^0.34.6"
},
"dependencies": {
"@prisma/client": "^5.0.0",

View file

@ -0,0 +1,45 @@
import app from '../../app'
import { expect, describe, beforeAll, afterAll, it } from 'vitest'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from 'interfaces/user'
let user: User
describe('POST /post/create', () => {
beforeAll(async () => {
user = await signUpNewUser()
})
afterAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await deleteUser(user.username!)
})
it('should respond with 200 status code if the user send the token and the content', async () => {
const response = await request(app)
.post('/post/create')
.send({
content: 'Hello world',
})
.set('Authorization', `Bearer ${user.token ?? ''}`)
.expect(200)
expect(response.body).toEqual(
expect.objectContaining({
id: expect.any(String),
content: expect.any(String),
authorId: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String),
}),
)
})
it('should respond with 400 status code if the user send no token', async () => {
const response = await request(app).post('/post/create').expect(401)
expect(response.body).toHaveProperty('error')
})
})

View file

@ -0,0 +1,37 @@
import app from '../../app'
import { describe, beforeAll, afterAll, it } from 'vitest'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from 'interfaces/user'
let user: User
describe('DELETE /post/delete', () => {
beforeAll(async () => {
user = await signUpNewUser()
})
afterAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await deleteUser(user.username!)
})
it('should delete the post successfully', async () => {
const response = await request(app)
.post('/post/create')
.send({
content: 'lorem ipsum',
})
.set('Authorization', `Bearer ${user.token ?? ''}`)
.expect(200)
await request(app)
.post('/post/delete')
.send({
postId: response.body.id,
})
.set('Authorization', `Bearer ${user.token ?? ''}`)
.expect(200)
})
})

View file

@ -0,0 +1,55 @@
import app from '../../app'
import { expect, describe, beforeAll, afterAll, it } from 'vitest'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from 'interfaces/user'
let postId: string
let user: User
describe('POST /post/info', () => {
beforeAll(async () => {
user = await signUpNewUser()
const token = user.token ?? ''
const post = await request(app)
.post('/post/create')
.send({
content: 'Hello world',
})
.set('Authorization', `Bearer ${token}`)
.expect(200)
postId = post.body.id
})
afterAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await deleteUser(user.username!)
})
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).toEqual(
expect.objectContaining({
id: expect.any(String),
content: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String),
author: expect.any(Object),
}),
)
})
it('should respond with 400 status code if the post does not exists', async () => {
const response = await request(app).get('/post/info?id=abc').expect(400)
expect(response.body).toHaveProperty('error')
})
})

View file

@ -0,0 +1,57 @@
import app from '../../app'
import { expect, describe, beforeAll, afterAll, it } from 'vitest'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import deleteUser from '../utils/delete-user'
import type User from 'interfaces/user'
let user: User
describe('PUT /post/update', () => {
beforeAll(async () => {
user = await signUpNewUser()
})
afterAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await deleteUser(user.username!)
})
it('should create a new post and update the content of it', async () => {
const post = await request(app)
.post('/post/create')
.send({
content: 'Lorem',
})
.set('Authorization', `Bearer ${user.token ?? ''}`)
.expect(200)
expect(post.body).toHaveProperty('id')
const fieldsToUpdate = {
postId: post.body.id,
content: 'Lorem ipsum',
}
const response = await request(app)
.put('/post/update')
.send(fieldsToUpdate)
.set('Authorization', `Bearer ${user.token ?? ''}`)
.expect(200)
// Post content should be Lorem Ipsum
if (post.body.content === response.body.content) {
throw new Error("Post didn't update")
}
expect(response.body).toEqual(
expect.objectContaining({
id: expect.any(String),
content: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String),
author: expect.any(Object),
}),
)
})
})

View file

@ -0,0 +1,46 @@
import app from '../../app'
import deleteUser from '../utils/delete-user'
import { expect, describe, beforeAll, afterAll, it } from 'vitest'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import type User from 'interfaces/user'
let user: User
describe('POST /user/auth', () => {
beforeAll(async () => {
user = await signUpNewUser()
})
afterAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await deleteUser(user.username!)
})
it('should respond with a error if the user does not exists', async () => {
const response = await request(app)
.post('/user/auth')
.send({ email: 'mm@mm.com', password: 'aa' })
.expect(400)
expect(response.body).toHaveProperty('error')
expect(response.body.error).toBe('Invalid email or password')
})
it('should respond with a error if receive an invalid email or password', async () => {
const response = await request(app)
.post('/user/auth')
.send({ email: user.email, password: 'fake_pass' })
.expect(400)
expect(response.body).toHaveProperty('error')
expect(response.body.error).toBe('Invalid email or password')
})
it('should respond with a error if receive an empty body', async () => {
const response = await request(app).post('/user/auth').send({}).expect(400)
expect(response.body).toHaveProperty('error')
expect(response.body.error).toBe('Missing fields')
})
})

View file

@ -0,0 +1,20 @@
import app from '../../app'
import { describe, beforeAll, it } from 'vitest'
import request from 'supertest'
import signUpNewUser from '../utils/create-user'
import type User from 'interfaces/user'
let user: User
describe('DELETE /user/delete', () => {
beforeAll(async () => {
user = await signUpNewUser()
})
it('should delete the user successfully', async () => {
await request(app)
.post('/user/delete')
.set('Authorization', `Bearer ${user.token ?? ''}`)
.expect(200)
})
})

View file

@ -0,0 +1,38 @@
import app from '../../app'
import { expect, describe, beforeAll, afterAll, it } from 'vitest'
import request from 'supertest'
import deleteUser from '../utils/delete-user'
import signUpNewUser from '../utils/create-user'
import type User from 'interfaces/user'
let user: User
describe('POST /user/info', () => {
beforeAll(async () => {
user = await signUpNewUser()
})
afterAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await deleteUser(user.username!)
})
it('should respond with 200 status code and return the user data', async () => {
const response = await request(app)
.get(`/user/info?u=${user.username ?? ''}`)
.expect(200)
expect(response.body).toHaveProperty('profileImage')
expect(response.body).toHaveProperty('displayName')
expect(response.body).toHaveProperty('username')
expect(response.body).toHaveProperty('createdAt')
expect(response.body).toHaveProperty('posts')
expect(response.body).toHaveProperty('likedPosts')
})
it('should respond with 400 status code if the user send no username', async () => {
const response = await request(app).get('/user/info?u=').expect(400)
expect(response.body).toHaveProperty('error')
})
})

View file

@ -0,0 +1,46 @@
import app from '../../app'
import { describe, beforeAll, afterAll, it } from 'vitest'
import request from 'supertest'
import deleteUser from '../utils/delete-user'
import signUpNewUser from '../utils/create-user'
import type User from 'interfaces/user'
let user: User
describe('POST /user/signup', () => {
beforeAll(async () => {
user = await signUpNewUser()
delete user.token
})
afterAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await deleteUser(user.username!)
})
it('should respond with a 400 status code if sent any invalid data', async () => {
await request(app)
.post('/user/signup')
.send({
username: 'username12@',
email: user.email,
password: user.password,
})
.expect(400)
})
it('should respond with a 400 status code for an existing username or email', async () => {
await request(app)
.post('/user/signup')
.send({
username: user.username,
email: user.email,
password: user.password,
})
.expect(400)
})
it('should respond with a 400 status code if receive an empty body', async () => {
await request(app).post('/user/signup').send({}).expect(400)
})
})

View file

@ -0,0 +1,37 @@
import app from '../../app'
import request from 'supertest'
import { faker } from '@faker-js/faker'
import type userPayload from '../../interfaces/user'
async function signUpNewUser(): Promise<userPayload> {
// To avoid conflicts with existing usernames or emails
const username = faker.internet.userName({ lastName: 'doe' }).toLowerCase()
const email = faker.internet.email()
const password = faker.internet.password() + '@1'
await request(app)
.post('/user/signup')
.send({
username,
email,
password,
})
.expect(200)
const response = await request(app)
.post('/user/auth')
.send({
email,
password,
})
.expect(200)
return {
username,
email,
password,
token: response.body.token,
}
}
export default signUpNewUser

View file

@ -0,0 +1,17 @@
import prisma from '../../clients/prisma-client'
export default async function deleteUser(username: string) {
await prisma.post.deleteMany({
where: {
author: {
username,
},
},
})
await prisma.user.deleteMany({
where: {
username,
},
})
}

View file

@ -5,7 +5,7 @@ import logger from 'helpers/logger'
let maxConnections
if (process.env.NODE_ENV === 'development') {
if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
logger.info('Development environment detected. Rate limit is now disabled.')
maxConnections = 0
} else {

View file

@ -13,7 +13,7 @@
"middlewares/*": ["middlewares/*"],
"services/*": ["services/*"]
},
"typeRoots": ["./src/@types", "./node_modules/@types"],
"typeRoots": ["./src/@types", "./node_modules/@types", "./node_modules/@types/minimist/index.d.ts"],
"outDir": "./dist",
"removeComments": true,
"esModuleInterop": true,

10
vitest.config.ts Normal file
View file

@ -0,0 +1,10 @@
import { defineConfig } from 'vitest/config'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [tsconfigPaths()],
test: {
name: 'Project Knedita',
env: { NODE_ENV: 'test' },
},
})