From bc244fac933778855b53c82947c0cf04ef486599 Mon Sep 17 00:00:00 2001 From: NecroBread Date: Mon, 8 Jan 2024 15:59:03 +0200 Subject: [PATCH] fix db and error issues --- .env.example | 1 + .env.local.example | 10 --- .env.test | 11 --- docker-compose-dev.yml | 2 +- src/config/get-config.ts | 5 +- src/features/article/article-entity.ts | 4 +- src/features/article/article-handlers.ts | 8 +- src/features/comment/comment-entity.ts | 6 +- src/features/comment/comment-handlers.ts | 8 +- src/features/user/user-entity.ts | 2 +- src/features/user/user-handlers.ts | 12 +-- tests/.gitkeep | 0 tests/article/article.test.ts | 71 --------------- tests/root.test.ts | 24 ----- tests/setup-tests.ts | 3 - tests/test-utils.ts | 30 ------- tests/user/signin.test.ts | 75 ---------------- tests/user/signup.test.ts | 108 ----------------------- 18 files changed, 23 insertions(+), 357 deletions(-) delete mode 100644 .env.local.example delete mode 100644 .env.test create mode 100644 tests/.gitkeep delete mode 100644 tests/article/article.test.ts delete mode 100644 tests/root.test.ts delete mode 100644 tests/setup-tests.ts delete mode 100644 tests/test-utils.ts delete mode 100644 tests/user/signin.test.ts delete mode 100644 tests/user/signup.test.ts diff --git a/.env.example b/.env.example index 200d89e..10806e4 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,7 @@ ALLOW_ORIGIN="*" ALLOW_METHODS="GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS" ALLOW_HEADERS="Content-Type,Cache-Control,Expires" JWT_SECRET=SUPERSECRET +DB_NAME="express_app" DB_HOST=host.docker.internal DB_PORT=6543 DB_USERNAME=postgres diff --git a/.env.local.example b/.env.local.example deleted file mode 100644 index 200d89e..0000000 --- a/.env.local.example +++ /dev/null @@ -1,10 +0,0 @@ -NODE_ENV=development -PORT=5000 -ALLOW_ORIGIN="*" -ALLOW_METHODS="GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS" -ALLOW_HEADERS="Content-Type,Cache-Control,Expires" -JWT_SECRET=SUPERSECRET -DB_HOST=host.docker.internal -DB_PORT=6543 -DB_USERNAME=postgres -DB_PASSWORD=123123 \ No newline at end of file diff --git a/.env.test b/.env.test deleted file mode 100644 index 02c28e4..0000000 --- a/.env.test +++ /dev/null @@ -1,11 +0,0 @@ -NODE_ENV=development -PORT=5000 -ALLOW_ORIGIN="*" -ALLOW_METHODS="GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS" -ALLOW_HEADERS="Content-Type,Cache-Control,Expires" -JWT_SECRET=SUPERSECRET -DB_NAME="test_express_app" -DB_HOST=localhost -DB_PORT=5432 -DB_USERNAME=postgres -DB_PASSWORD=password \ No newline at end of file diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 055c2b6..b2936a9 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -12,7 +12,7 @@ services: depends_on: - postgres_db env_file: - - .env.local + - .env volumes: - type: bind source: . diff --git a/src/config/get-config.ts b/src/config/get-config.ts index de961ac..53bdf1c 100644 --- a/src/config/get-config.ts +++ b/src/config/get-config.ts @@ -3,10 +3,7 @@ import dotenv from "dotenv"; /** * Load enviroment variables */ -if (!process.env.NODE_ENV) { - dotenv.config(); - dotenv.config({ path: `.env.local`, override: true }); -} +dotenv.config(); export function getConfig() { return { diff --git a/src/features/article/article-entity.ts b/src/features/article/article-entity.ts index 6986c76..56a9e21 100644 --- a/src/features/article/article-entity.ts +++ b/src/features/article/article-entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; import { User } from "../user/user-entity"; @Entity() @@ -12,7 +12,7 @@ export class Article { @Column({ type: "varchar", length: 2000 }) content: string; - @OneToOne(() => User) + @ManyToOne(() => User) @JoinColumn() owner: string; diff --git a/src/features/article/article-handlers.ts b/src/features/article/article-handlers.ts index a42bce9..d1dc943 100644 --- a/src/features/article/article-handlers.ts +++ b/src/features/article/article-handlers.ts @@ -40,7 +40,7 @@ export function getOneArticle() { data: result, }); } catch (err) { - next(new NotFoundError(err)); + next(err); } }; } @@ -61,7 +61,7 @@ export function createArticle() { data: result, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } @@ -79,7 +79,7 @@ export function updateArticle() { data: result, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } @@ -98,7 +98,7 @@ export function deleteArticle() { data: null, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } diff --git a/src/features/comment/comment-entity.ts b/src/features/comment/comment-entity.ts index 4b05d40..baebbcb 100644 --- a/src/features/comment/comment-entity.ts +++ b/src/features/comment/comment-entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, OneToOne, PrimaryGeneratedColumn } from "typeorm"; import { User } from "../user/user-entity"; @Entity() @@ -13,11 +13,11 @@ export class Comment { @JoinColumn() owner: string; - @OneToOne(() => Comment, { nullable: true }) + @ManyToOne(() => Comment, { nullable: true }) @JoinColumn() parent: string; - @OneToOne(() => User) + @ManyToOne(() => User) @JoinColumn() article: string; diff --git a/src/features/comment/comment-handlers.ts b/src/features/comment/comment-handlers.ts index 5b0be3d..3687ce4 100644 --- a/src/features/comment/comment-handlers.ts +++ b/src/features/comment/comment-handlers.ts @@ -40,7 +40,7 @@ export function getOneComment() { data: result, }); } catch (err) { - next(new NotFoundError(err)); + next(err); } }; } @@ -61,7 +61,7 @@ export function createComment() { data: result, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } @@ -79,7 +79,7 @@ export function updateComment() { data: result, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } @@ -98,7 +98,7 @@ export function deleteComment() { data: null, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } diff --git a/src/features/user/user-entity.ts b/src/features/user/user-entity.ts index dbfbd8a..2559634 100644 --- a/src/features/user/user-entity.ts +++ b/src/features/user/user-entity.ts @@ -1,6 +1,6 @@ import bcrypt from "bcrypt"; -import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "typeorm"; +import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity() export class User { diff --git a/src/features/user/user-handlers.ts b/src/features/user/user-handlers.ts index bf69ebe..090d5f1 100644 --- a/src/features/user/user-handlers.ts +++ b/src/features/user/user-handlers.ts @@ -25,7 +25,7 @@ export function signUp() { data: user, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } @@ -42,7 +42,7 @@ export function signIn() { data: user, }); } catch (err) { - next(new BadRequestError(err)); + next(err); } }; } @@ -56,7 +56,7 @@ export function signOut() { data: null, }); } catch (err) { - return next(new BadRequestError(err)); + return next(err); } }; } @@ -74,7 +74,7 @@ export function getUserData() { data: userData, }); } catch (err) { - return next(new BadRequestError(err)); + return next(err); } }; } @@ -98,7 +98,7 @@ export function updateUser() { data: updatedUser, }); } catch (err) { - return next(new BadRequestError(err)); + return next(err); } }; } @@ -123,7 +123,7 @@ export function updatePassword() { data: updatedUser, }); } catch (err) { - return next(new BadRequestError(err)); + return next(err); } }; } diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/article/article.test.ts b/tests/article/article.test.ts deleted file mode 100644 index 42e0197..0000000 --- a/tests/article/article.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import supertest, { SuperTest, Test } from "supertest"; -import app from "../../src/app"; -import { initTestDataSource } from "../test-utils"; -import { DataSource } from "typeorm"; - -const url = "/api/v1/articles"; -const mockUser = { - username: "user", - firstName: "User", - lastName: "Useroff", - password: "123123", -}; - -let db: DataSource; - -describe(`${url}`, () => { - let agent: SuperTest; - - async function login() { - return await agent - .post("/api/v1/user/signin") - .set("Content-Type", "application/json") - .send({ username: "user", password: "123123" }); - } - - beforeAll(async () => { - require("dotenv").config(); - - db = await initTestDataSource(); - - agent = supertest(app); - - await agent.post("/api/v1/user/signup").set("Content-Type", "application/json").send(mockUser); - }); - - afterAll((done) => { - db.dropDatabase().then(() => { - db.destroy(); - done(); - }); - }); - - test("should fetch articles as empty array when there are none", async () => { - const test = await agent.get(url).expect(200); - - expect(test.body.message).toBe("Articles"); - expect(test.body.data).toStrictEqual([]); - expect(test.body.code).toBe(200); - }); - - test("should create article when data is valid", async () => { - const req = await login(); - - const cookies = req.headers["set-cookie"]; - await agent - .post(url) - .set("Content-Type", "application/json") - .send({ - title: "Test title", - content: "Test content", - }) - .set("Cookie", cookies) - .expect(201); - - const test = await supertest(app).get(url).expect(200); - - expect(test.body.message).toBe("Articles"); - expect(test.body.data).toHaveLength(1); - expect(test.body.code).toBe(200); - }); -}); diff --git a/tests/root.test.ts b/tests/root.test.ts deleted file mode 100644 index 9347ee4..0000000 --- a/tests/root.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import supertest from "supertest"; -import app from "../src/app"; -import { initTestDataSource } from "./test-utils"; -import { DataSource } from "typeorm"; - -let db: DataSource; - -describe("root", () => { - beforeAll(async () => { - db = await initTestDataSource(); - }); - - afterAll((done) => { - db.dropDatabase().then(() => { - db.destroy(); - done(); - }); - }); - test("should return 404 and a message when url does not exist", async () => { - const test = await supertest(app).get("/asdasdc1").expect(404); - - expect(test.body.message).toBe("Not found"); - }); -}); diff --git a/tests/setup-tests.ts b/tests/setup-tests.ts deleted file mode 100644 index 8eb996b..0000000 --- a/tests/setup-tests.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as dotenv from "dotenv"; - -dotenv.config({ path: `.env.test`, override: true }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts deleted file mode 100644 index 74c2f09..0000000 --- a/tests/test-utils.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { DataSource, DataSourceOptions } from "typeorm"; -import { Article } from "../src/features/article/article-entity"; -import { Comment } from "../src/features/comment/comment-entity"; -import { User } from "../src/features/user/user-entity"; -import { createDatabase } from "typeorm-extension"; -import { AppDataSource } from "../src/config/db"; -import { getConfig } from "../src/config/get-config"; - -export async function initTestDataSource(): Promise { - const config = getConfig(); - - const options: DataSourceOptions = { - type: "postgres", - host: config.DB_HOST, - port: 5000, - username: config.DB_USERNAME, - password: config.DB_PASSWORD, - database: config.DB_NAME, - synchronize: config.NODE_ENV === "production" ? false : true, - logging: true, - entities: [Article, Comment, User], - }; - - await createDatabase({ - options, - ifNotExist: true, - }); - - return AppDataSource.initialize(); -} diff --git a/tests/user/signin.test.ts b/tests/user/signin.test.ts deleted file mode 100644 index 225bf5d..0000000 --- a/tests/user/signin.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import supertest, { SuperTest, Test } from "supertest"; -import app from "../../src/app"; -import { DataSource } from "typeorm"; -import { initTestDataSource } from "../test-utils"; - -const url = "/api/v1/user/signin"; -let db: DataSource; - -describe(`${url}`, () => { - let agent: SuperTest; - - beforeAll(async () => { - db = await initTestDataSource(); - agent = supertest(app); - - // signup a user - return await agent.post("/api/v1/user/signup").set("Content-Type", "application/json").send({ - username: "user", - firstName: "User", - lastName: "Useroff", - password: "123123", - }); - }); - - afterAll((done) => { - db.dropDatabase().then(() => { - db.destroy(); - done(); - }); - }); - - test("should return 4xx code when request body is empty", async () => { - const test = await agent.post(url).expect(400); - - expect(test.body.message).toBe('"username" is required'); - expect(test.body.data).toBe(null); - expect(test.body.code).toBe(400); - }); - - test("should signin with existing user when request body is valid", async () => { - const test = await agent - .post(url) - .set("Content-Type", "application/json") - .send({ username: "user", password: "123123" }) - .expect(200); - - expect(test.body.message).toBe("Sign in successful"); - expect(test.body.data).toBeTruthy(); - expect(test.body.code).toBe(200); - }); - - test("should fail to sign in when password do not match", async () => { - const test = await agent - .post(url) - .set("Content-Type", "application/json") - .send({ username: "user", password: "12c3123" }) - .expect(401); - - expect(test.body.message).toBe("Sign in failed"); - expect(test.body.data).toBe(null); - expect(test.body.code).toBe(401); - }); - - test("should fail to sign in when username do not match", async () => { - const test = await agent - .post(url) - .set("Content-Type", "application/json") - .send({ username: "user1", password: "1c23123" }) - .expect(401); - - expect(test.body.message).toBe("Sign in failed"); - expect(test.body.data).toBe(null); - expect(test.body.code).toBe(401); - }); -}); diff --git a/tests/user/signup.test.ts b/tests/user/signup.test.ts deleted file mode 100644 index e4f73d8..0000000 --- a/tests/user/signup.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -import supertest, { SuperTest, Test } from "supertest"; -import app from "../../src/app"; -import { DataSource } from "typeorm"; -import { initTestDataSource } from "../test-utils"; -import { User } from "../../src/features/user/user-entity"; -import * as config from "../../src/config/get-config"; - -const url = "/api/v1/user/signup"; -let db: DataSource; - -describe(`${url}`, () => { - let agent: SuperTest; - - beforeAll(async () => { - db = await initTestDataSource(); - agent = supertest(app); - }); - - afterAll((done) => { - db.dropDatabase().then(() => { - db.destroy(); - done(); - }); - }); - - test("should return 4xx code when request body is empty", async () => { - const test = await agent.post(url).expect(400); - - expect(test.body.message).toBe('"username" is required'); - expect(test.body.data).toBe(null); - expect(test.body.code).toBe(400); - }); - - test("should sign up successfully when user data is valid", async () => { - const test = await agent - .post(url) - .set("Content-Type", "application/json") - .send({ - username: `john1`, - firstName: "John", - lastName: "Johnson", - password: "123123", - }) - .expect(201); - - expect(test.body.message).toBe("Sign up successful"); - expect(test.body.data).toBeTruthy(); - expect(test.body.code).toBe(201); - }); - - test("should fail to sign up when password is invalid", async () => { - const test = await agent - .post(url) - .set("Content-Type", "application/json") - .send({ - username: `john`, - firstName: "John", - lastName: "Johnson", - password: "123% 123", - }) - .expect(400); - - expect(test.body.message).toBe("Sign up failed"); - expect(test.body.data).toBe(null); - expect(test.body.code).toBe(400); - }); - - test("should fail to sign up when username is invalid", async () => { - const test = await agent - .post(url) - .set("Content-Type", "application/json") - .send({ - username: "john asda s a", - firstName: "John", - lastName: "Johnson", - password: "123123", - }) - .expect(400); - - expect(test.body.message).toBe('"username" must only contain alpha-numeric characters'); - expect(test.body.data).toBe(null); - expect(test.body.code).toBe(400); - }); - - test("should fail to sign up when username is not unique", async () => { - await agent.post(url).set("Content-Type", "application/json").send({ - username: "bob", - firstName: "John", - lastName: "Johnson", - password: "123123", - }); - - const test = await agent - .post(url) - .set("Content-Type", "application/json") - .send({ - username: "bob", - firstName: "John", - lastName: "Johnson", - password: "123123", - }) - .expect(400); - - expect(test.body.message).toBe("Sign up failed"); - expect(test.body.data).toBe(null); - expect(test.body.code).toBe(400); - }); -});