Compare commits

...

21 Commits

@ -14,7 +14,7 @@ These are the notes from a meeting with the frontend developer that describe wha
#### Users
- Index [token required]
- Show [token required]
- Create N[token required]
- Create [token required]
#### Orders
- Current Order by user (args: user id)[token required]

@ -2,7 +2,7 @@
"dev": {
"driver": "pg",
"host": "127.0.0.1",
"database": "shelf_dev",
"database": "shelf",
"user": "postgres",
"password": "fredy123"
},
@ -10,7 +10,7 @@
"driver": "pg",
"host": "127.0.0.1",
"database": "shelf_test",
"user": "postgres_test",
"user": "postgres",
"password": "fredy123"
}
}

@ -12,3 +12,4 @@ services:
volumes:
postgres:

@ -1,7 +1,10 @@
{
"spec_dir": "spec",
"spec_dir": "src/tests",
"spec_files": [
"../**/tests/*[s]pec.ts"
"models/product_spec.ts",
"models/user_spec.ts",
"models/order_spec.ts",
"handlers/*_[sS]pec.ts"
],
"helpers": [
"helpers/**/*.js"
@ -15,5 +18,5 @@
}
],
"stopSpecOnExpectationFailure": false,
"random": true
"random": false
}

@ -0,0 +1,53 @@
'use strict';
var dbm;
var type;
var seed;
var fs = require('fs');
var path = require('path');
var Promise;
/**
* We receive the dbmigrate dependency from dbmigrate initially.
* This enables us to not have to rely on NODE_PATH.
*/
exports.setup = function(options, seedLink) {
dbm = options.dbmigrate;
type = dbm.dataType;
seed = seedLink;
Promise = options.Promise;
};
exports.up = function(db) {
var filePath = path.join(__dirname, 'sqls', '20220520025053-shelf-up.sql');
return new Promise( function( resolve, reject ) {
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
if (err) return reject(err);
console.log('received data: ' + data);
resolve(data);
});
})
.then(function(data) {
return db.runSql(data);
});
};
exports.down = function(db) {
var filePath = path.join(__dirname, 'sqls', '20220520025053-shelf-down.sql');
return new Promise( function( resolve, reject ) {
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
if (err) return reject(err);
console.log('received data: ' + data);
resolve(data);
});
})
.then(function(data) {
return db.runSql(data);
});
};
exports._meta = {
"version": 1
};

@ -1,7 +0,0 @@
CREATE TABLE books (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
author VARCHAR(255),
price integer not null,
summary text
);

@ -0,0 +1,4 @@
DROP TABLE order_products;
DROP TABLE orders;
DROP TABLE users;
DROP TABLE products;

@ -0,0 +1,29 @@
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(250) NOT NULL,
price INTEGER NOT NULL
);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
firstName VARCHAR(250) NOT NULL,
lastName VARCHAR(250) NOT NULL,
username VARCHAR(250) NOT NULL,
password VARCHAR(250) NOT NULL
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
status VARCHAR(15),
user_id INTEGER NOT NULL REFERENCES users(id)
);
CREATE TABLE order_products (
id SERIAL PRIMARY KEY,
quantity INTEGER NOT NULL,
order_id INTEGER NOT NULL REFERENCES orders(id),
product_id INTEGER NOT NULL REFERENCES products(id)
)

@ -1,13 +1,16 @@
{
"name": "storefront_backend",
"name": "Shelf_backend",
"version": "0.1.0",
"description": "",
"main": "server.ts",
"scripts": {
"start": "nodemon src/server.ts",
"dev": "db-migrate --env dev up && nodemon src/server.ts",
"watch": "tsc-watch --esModuleInterop src/server.ts --outDir ./dist --onSuccess \"node ./dist/server.js\"",
"test": "jasmine-ts",
"test": "db-migrate --env test up && ENV=test jasmine-ts --config jasmine.json && db-migrate --env test down",
"build": "npx tsc",
"up": "db-migrate up",
"down": "db-migrate down",
"lint": "eslint --ext .ts",
"prettier": "prettier \"src/**/*.ts\" --write",
"tsc": "tsc"
@ -15,23 +18,28 @@
"author": "AnisB",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"body-parser": "^1.19.0",
"db-migrate": "^0.11.13",
"db-migrate-pg": "^1.2.2",
"cross-env": "^7.0.3",
"dotenv": "^16.0.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"nodemon": "^2.0.15",
"pg": "^8.5.1",
"typescript": "^4.1.3"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",
"@types/express": "^4.17.9",
"@types/jasmine": "^3.6.3",
"@types/jsonwebtoken": "^8.5.8",
"@types/pg": "^7.14.7",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.10.1",
"db-migrate": "^0.11.13",
"db-migrate-pg": "^1.2.2",
"eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",

@ -1,24 +1,36 @@
import { Pool } from 'pg';
import dotenv from 'dotenv';
import dotenv from 'dotenv'
import { Pool } from 'pg'
dotenv.config();
dotenv.config()
const {
ENV,
POSTGRES_HOST,
POSTGRES_DB,
POSTGRES_USER,
POSTGRES_PASSWORD
} = process.env;
ENV,
POSTGRES_HOST,
POSTGRES_DB,
POSTGRES_TEST_DB,
POSTGRES_USER,
POSTGRES_PASSWORD
} = process.env
let client = new Pool();
if (ENV === 'dev') {
client = new Pool({
host: POSTGRES_HOST,
database: POSTGRES_DB,
user: POSTGRES_USER,
password: POSTGRES_PASSWORD
});
console.log(ENV)
if(ENV === 'dev') {
client = new Pool({
host: POSTGRES_HOST,
database: POSTGRES_DB,
user: POSTGRES_USER,
password: POSTGRES_PASSWORD,
})
}
if(ENV === 'test') {
client = new Pool({
host: POSTGRES_HOST,
database: POSTGRES_TEST_DB,
user: POSTGRES_USER,
password: POSTGRES_PASSWORD,
})
}
export default client
export default client;

@ -0,0 +1,78 @@
import express, { Request, Response } from 'express'
import { Order, OrderProduct, OrderStore } from '../models/order'
import { verifyAuthToken } from './utils'
const orderRoutes = (app: express.Application) => {
app.get('/orders', index)
app.get('/orders/:id', read)
app.post('/orders', verifyAuthToken, create)
app.post('/orders/:id/products', verifyAuthToken, addProduct)
app.delete('/orders/:id/products', verifyAuthToken, deleteProduct)
}
const store = new OrderStore()
const index = async (req: Request, res: Response) => {
try {
const orders = await store.index()
res.json(orders)
} catch (err) {
res.status(400)
res.json(err)
}
}
const read = async (req: Request, res: Response) => {
try {
const order = await store.read(parseInt(req.params.id))
res.json(order)
} catch (err) {
res.status(400)
res.json(err)
}
}
const create = async (req: Request, res: Response) => {
try {
const orderInfo: Order = {
status: req.body.status,
user_id: parseInt(req.body.user_id)
}
const newOrder = await store.create(orderInfo)
res.json(newOrder)
} catch (err) {
res.status(400)
res.json(err)
}
}
const addProduct = async (req: Request, res: Response) => {
try {
const orderProductInfo: OrderProduct = {
order_id: parseInt(req.params.id),
quantity: parseInt(req.body.quantity),
product_id: parseInt(req.body.product_id)
}
const addedProduct = await store.addProduct(orderProductInfo)
res.json(addedProduct)
} catch (err) {
res.status(400)
res.json(err)
}
}
const deleteProduct = async (req: Request, res: Response) => {
try {
const deletedProduct = await store.deleteProduct(parseInt(req.params.id))
res.json(deletedProduct)
} catch (err) {
res.status(400)
res.json(err)
}
}
export default orderRoutes

@ -0,0 +1,80 @@
import express, { Request, Response } from 'express'
import { Product, ProductStore } from '../models/product'
import { verifyAuthToken } from './utils'
const productRoutes = (app: express.Application) => {
app.get('/products', index)
app.get('/products/:id', read)
app.post('/products', verifyAuthToken, create)
app.put('/products/:id', verifyAuthToken, update)
app.delete('/products/:id', verifyAuthToken, destroy)
}
const store = new ProductStore()
const index = async (req: Request, res: Response) => {
try {
const products = await store.index()
res.json(products)
} catch (err) {
res.status(400)
res.json(err)
}
}
const read = async (req: Request, res: Response) => {
try {
const product = await store.read(parseInt(req.params.id))
res.json(product)
} catch (err) {
res.status(400)
res.json(err)
}
}
const create = async (req: Request, res: Response) => {
try {
const productInfo: Product = {
name: req.body.name,
price: req.body.price,
}
const newProduct = await store.create(productInfo)
res.json(newProduct)
} catch (err) {
res.status(400)
res.json(err)
}
}
const update = async (req: Request, res: Response) => {
try {
const productInfo: Product = {
id: parseInt(req.params.id),
name: req.body.name,
price: req.body.price,
}
const updatedProduct = await store.update(productInfo)
res.json(updatedProduct)
} catch (err) {
res.status(400)
res.json(err)
}
}
const destroy = async (req: Request, res: Response) => {
try {
const deleted = await store.delete(parseInt(req.params.id))
res.json(deleted)
} catch (err) {
res.status(400)
res.json(err)
}
}
export default productRoutes

@ -0,0 +1,113 @@
import express, { Request, Response } from 'express'
import { User, UserStore } from '../models/user'
import { verifyAuthToken, verifyUserToken} from './utils'
const userRoutes = (app: express.Application) => {
app.get('/users', verifyAuthToken, index)
app.get('/users/:id', verifyAuthToken, read)
app.post('/users', create)
app.put('/users/:id', verifyAuthToken, update)
app.delete('/users/:id', verifyAuthToken, destroy)
app.post("/users/auth", authenticate)
}
const store = new UserStore()
const index = async (req: Request, res: Response) => {
try {
const users = await store.index()
res.json(users);
} catch (err) {
res.status(400)
res.json(err)
}
}
const read = async (req: Request, res: Response) => {
try {
const user = await store.read(parseInt(req.params.id))
res.json(user)
} catch (err) {
res.status(400)
res.json(err)
}
}
const create = async (req: Request, res: Response) => {
const userInfo: User = {
firstname: req.body.firstname,
lastname: req.body.lastname,
username: req.body.username,
password: req.body.password
}
try {
const newUser = await store.create(userInfo)
res.json(verifyUserToken(newUser))
} catch(err) {
res.status(400)
res.json(err)
}
}
const update = async (req: Request, res: Response) => {
try {
const userInfo: User = {
id: parseInt(req.params.id),
firstname: req.body.firstname,
lastname: req.body.lastname,
username: req.body.username,
password: req.body.password
}
const updatedUser = await store.update(userInfo)
res.json(updatedUser)
} catch (err) {
res.status(400)
res.json(err)
}
}
const destroy = async (req: Request, res: Response) => {
try {
const deleted = await store.delete(parseInt(req.params.id))
res.json(deleted)
} catch (err) {
res.status(400)
res.json(err)
}
}
const authenticate = async (req: Request, res: Response) => {
try {
const userInfo: User = {
username: req.body.username,
password: req.body.password
}
if (userInfo.username === undefined || userInfo.password === undefined) {
res.status(400)
res.send("Missing credentials username or password")
}
const authUser: User | null = await store.authenticate(userInfo.username, userInfo.password)
if (authUser === null) {
res.status(401)
res.send("Password is incorrect")
}
res.json(verifyUserToken(authUser))
} catch(err) {
res.status(401)
res.json(err)
}
}
export default userRoutes

@ -0,0 +1,27 @@
import jwt, { Secret } from "jsonwebtoken"
import { User } from "../models/user"
import { NextFunction, Request, Response } from "express"
const SECRET = process.env.TOKEN_SECRET as Secret
export const verifyAuthToken = (req: Request, res: Response, next: NextFunction) => {
if (!req.headers.authorization) {
res.status(401)
res.json("Missing authorization header")
return false
}
try {
const token = req.headers.authorization.split(' ')[1]
jwt.verify(token, SECRET)
next()
} catch (err) {
res.status(401)
res.json("Access denied, invalid token")
}
}
export const verifyUserToken = (user: User | null) => {
return jwt.sign({ user }, SECRET)
}

@ -1,83 +0,0 @@
import { Client } from 'pg';
import client from '../database';
//import { Books } from '../types';
export type Book = {
id: number;
title: string;
author: string;
price: number;
summary: string;
}
export class BookStore {
async index(): Promise<Book[]> {
try {
// @ts-ignore
const conn = await client.connect()
const sql = 'SELECT * FROM books'
const result = await conn.query(sql)
conn.release()
return result.rows
} catch (err) {
throw new Error(`Cannot get any books ${err}`)
}
}
async show(id: string): Promise<Book> {
try {
const sql = 'SELECT * FROM books where id =($1)'
// @ts-ignore
const conn = await client.connect()
const result = await conn.query(sql, [id])
conn.release()
return result.rows[0]
} catch (err) {
throw new Error(`Could not find book ${id}. Error: ${err}`)
}
}
async create(b: Book): Promise<Book> {
try {
const sql = 'INSERT INTO books (title, author, price, summary) VALUES ($1, $2, $3, $4) RETURNING *'
// @ts-ignore
const conn = await client.connect()
const result = await conn.query(sql, [b.title, b.author, b.price, b.summary])
const book = result.rows[0]
conn.release()
return book
} catch (err) {
throw new Error(`Could not add new book ${title}. Error: ${err}`)
}
}
async delete(id: string): Promise<Book> {
try {
const sql = 'DELETE FROM books WHERE id=(1$)'
// @ts-ignore
const conn = await client.connect()
const result = await conn.query(sql, [id])
const book = result.rows[0]
conn.release()
return book
} catch (err) {
throw new Error(`Could not delete book ${id}. Error: ${err}`)
}
}
}

@ -0,0 +1,135 @@
import client from '../database'
export type Order = {
id?: number
status: string
user_id: number
}
export type OrderProduct = {
id?: number
quantity: number
order_id: number
product_id: number
}
export class OrderStore {
async index(): Promise<Order[]> {
try {
const conn = await client.connect()
const sql = 'SELECT * FROM orders'
const result = await conn.query(sql)
const orders = result.rows
conn.release()
return orders
} catch (err) {
throw new Error(`Cannot get any order ${err}`)
}
}
async read(user_id: number): Promise<Order> {
try {
const conn = await client.connect()
const sql = 'SELECT * FROM orders WHERE user_id=($1)'
const result = await conn.query(sql, [user_id])
const order = result.rows[0]
conn.release()
return order
} catch (err) {
throw new Error(`Could not find order ${user_id}. Error: ${err}`)
}
}
async create(o: Order): Promise<Order> {
try {
const conn = await client.connect()
const sql = 'INSERT INTO orders (status, user_id) VALUES ($1, $2) RETURNING *'
const result = await conn.query(sql, [o.status, o.user_id])
const order = result.rows[0]
conn.release()
return order
} catch (err) {
throw new Error(`Could not add a new order ${o.user_id}. Error: ${err}`)
}
}
async addProduct(o: OrderProduct): Promise<OrderProduct> {
try {
const ordersql = 'SELECT * FROM orders WHERE id=($1)'
const conn = await client.connect()
const result = await conn.query(ordersql, [o.order_id])
const order = result.rows[0]
if(order.status !== "active") {
throw new Error(`Could not add product ${o.product_id} to order ${o.order_id} because order status is ${order.status}`)
}
conn.release()
} catch (err) {
throw new Error(`${err}`)
}
try {
const sql = 'INSERT INTO order_products (quantity, order_id, product_id) VALUES ($1, $2, $3) RETURNING *'
const conn = await client.connect()
const result = await conn.query(sql, [o.quantity, o.order_id, o.product_id])
const order = result.rows[0]
conn.release()
return order
} catch (err) {
throw new Error(`Could not add product ${o.product_id} to order ${o.order_id}: Error: ${err}`)
}
}
async deleteProduct(id: number): Promise<Order> {
try {
const sql = 'DELETE FROM order_products WHERE order_id=($1)'
const conn = await client.connect()
const result = await conn.query(sql, [id])
conn.release()
} catch (err) {
throw new Error(`Could not delete order ${id}: Error: ${err}`)
}
try {
const ordersql = 'DELETE FROM orders WHERE id=($1)'
const conn = await client.connect()
const ordersResult = await conn.query(ordersql, [id])
const order = ordersResult.rows[0]
conn.release()
return order
} catch (err) {
throw new Error(`${err}`)
}
}
}

@ -0,0 +1,101 @@
import client from '../database';
export type Product = {
id?: number;
name: string;
price: number;
}
export class ProductStore {
async index(): Promise<Product[]> {
try {
const conn = await client.connect()
const sql = 'SELECT * FROM products'
const result = await conn.query(sql)
const products = result.rows
conn.release()
return products
} catch (err) {
throw new Error(`Cannot get any products ${err}`)
}
}
async read(id: number): Promise<Product> {
try {
const conn = await client.connect()
const sql = 'SELECT * FROM products WHERE id=($1)'
const result = await conn.query(sql, [id])
const product = result.rows[0]
conn.release()
return product
} catch (err) {
throw new Error(`Could not find product ${id}. Error: ${err}`)
}
}
async create(p: Product): Promise<Product> {
try {
const conn = await client.connect()
const sql = 'INSERT INTO products (name, price) VALUES ($1, $2) RETURNING *'
const result = await conn.query(sql, [p.name, p.price])
const product = result.rows[0]
conn.release()
return product
} catch (err) {
throw new Error(`Could not add a new product ${p.name}. Error: ${err}`)
}
}
async update(p: Product): Promise<Product> {
try {
const conn = await client.connect();
const sql = 'UPDATE products SET name=$1, price=$2 WHERE id=$3 RETURNING *'
const result = await conn.query(sql, [p.name, p.price, p.id])
const product = result.rows[0]
conn.release()
return product
} catch (err) {
throw new Error(`Could not update product ${p.id}. Error: ${err}`)
}
}
async delete(id: number): Promise<Product> {
try {
const conn = await client.connect()
const sql = 'DELETE FROM products WHERE id=($1)'
const result = await conn.query(sql, [id])
const product = result.rows[0]
conn.release()
return product
} catch (err) {
throw new Error(`Could not delete product ${id}. Error: ${err}`)
}
}
}

@ -0,0 +1,142 @@
import client from '../database';
import bcrypt from 'bcrypt';
const { BCRYPT_PASSWORD, SALT_ROUNDS} = process.env
const pepper = BCRYPT_PASSWORD
const saltRounds = SALT_ROUNDS
export type User = {
id?: number;
firstname?: string;
lastname?: string;
username: string;
password: string;
}
export class UserStore {
async index(): Promise<User[]> {
try {
const conn = await client.connect()
const sql = 'SELECT * FROM users'
const result = await conn.query(sql)
const users = result.rows
conn.release()
return users
} catch (err) {
throw new Error(`Cannot get any users ${err}`)
}
}
async read(id: number): Promise<User> {
try {
const conn = await client.connect()
const sql = 'SELECT * FROM users WHERE id=($1)'
const result = await conn.query(sql, [id])
const user = result.rows[0]
conn.release()
return user
} catch (err) {
throw new Error(`Could not find user ${id}. Error: ${err}`)
}
}
async create(u: User): Promise<User> {
try {
const conn = await client.connect()
const sql = 'INSERT INTO users (firstname, lastname, username, password) VALUES ($1, $2, $3, $4) RETURNING *'
const hash = bcrypt.hashSync(
u.password + pepper,
parseInt(saltRounds as string, 10)
)
const result = await conn.query(sql, [u.firstname, u.lastname, u.username, hash])
const user = result.rows[0]
conn.release()
return user
} catch(err) {
throw new Error(`Could not add a new user ${u.firstname}. Error: ${err}`)
}
}
async update(u: User): Promise<User> {
try {
const conn = await client.connect()
const sql = 'UPDATE users SET firstname=$1, lastName=$2, username=$3, password=$4 WHERE id=$5 RETURNING *'
const hash = bcrypt.hashSync(
u.password + pepper,
parseInt(saltRounds as string, 10)
)
const result = await conn.query(sql, [u.firstname, u.lastname, u.username, hash, u.id])
const user = result.rows[0]
conn.release()
return user
} catch (err) {
throw new Error(`Could not update user ${u.firstname}. Error: ${err}`)
}
}
async delete(id: Number): Promise<User> {
try {
const conn = await client.connect()
const sql = 'DELETE FROM users WHERE id=($1)'
const result = await conn.query(sql, [id])
const user = result.rows[0]
conn.release()
return user
} catch (err) {
throw new Error(`Could not delete user ${id}. Error: ${err}`)
}
}
async authenticate(username: string, password: string): Promise<User | null> {
try {
const conn = await client.connect()
//const sql = 'SELECT password FROM users WHERE username=($1)'
const sql = 'SELECT * FROM users WHERE username=($1)'
const result = await conn.query(sql, [username])
if(result.rows.length) {
const user = result.rows[0]
if (bcrypt.compareSync(password + pepper, user.password)) {
return user
}
}
conn.release()
return null
} catch (err) {
throw new Error(`Could not find user ${username}. Error: ${err}`)
}
}
}

@ -1,17 +1,29 @@
import express, { Request, Response } from 'express'
import bodyParser from 'body-parser'
import productRoutes from './handlers/products'
import userRoutes from './handlers/users'
import orderRoutes from './handlers/orders'
const app: express.Application = express()
const address: string = "0.0.0.0:3000"
const port = 3000;
app.use(bodyParser.json())
app.get('/', function (req: Request, res: Response) {
res.send('Hello World!')
res.send('Main API')
})
app.listen(3000, function () {
productRoutes(app)
userRoutes(app)
orderRoutes(app)
// Start express server
app.listen(port, function () {
console.log(`starting app on: ${address}`)
})
export default app;

@ -0,0 +1,89 @@
import supertest from "supertest"
import app from "../../server"
import { Product } from '../../models/product'
import { User } from '../../models/user'
import { Order, OrderProduct } from '../../models/order'
const token = process.env.TOKEN_SECRET_TEST as string
const request = supertest(app);
const testProduct: Product = {
id: 3,
name: "metro",
price: 10
}
const testUser: User = {
id: 3,
firstname: 'John',
lastname: 'Doe',
username: 'Jd',
password: 'password'
}
const testOrder: Order = {
status: "active",
user_id: 3
}
const testOrderProduct: OrderProduct = {
id: 2,
quantity: 5,
order_id: 2,
product_id: 3
}
describe("Order handler", () => {
beforeAll( async () => {
const product = await request
.post('/products')
.auth(token, {type: "bearer"})
.send(testProduct)
const user = await request
.post('/users')
.auth(token, {type: "bearer"})
.send(testUser)
})
it('Should create a new order', async () => {
const response = await request
.post("/orders")
.auth(token, {type: "bearer"})
.send(testOrder)
expect(response.status).toBe(200)
})
it('Should index orders', async () => {
const response = await request
.get("/orders")
expect(response.status).toBe(200)
})
it('Should get order by id', async () => {
const response = await request
.get("/orders/2")
expect(response.status).toBe(200)
})
it('Should add a new product to order', async () => {
const response = await request
.post('/orders/2/products')
.auth(token, {type: 'bearer'})
.send(testOrderProduct)
expect(response.status).toBe(200)
})
it('Should delete order', async () => {
const response = await request
.delete('/orders/2/products')
.auth(token, {type: 'bearer'})
expect(response.status).toBe(200)
})
})

@ -0,0 +1,64 @@
import supertest from "supertest"
import app from "../../server"
import { Product } from '../../models/product'
const token = process.env.TOKEN_SECRET_TEST as string
const request = supertest(app);
const testProduct: Product = {
name: "metro",
price: 10
}
const updatedProduct: Product = {
name: "1984",
price: 5
}
describe("Product handler", () => {
console.log("PRODUCT")
it('Should create a new product', async () => {
const response = await request
.post("/products")
.auth(token, { type: "bearer" })
.send(testProduct);
expect(response.status).toBe(200);
})
it('Should index products', async () => {
const response = await request
.get("/products")
expect(response.status).toBe(200);
})
it('Should get product by id', async () => {
const response = await request
.get("/products/1")
expect(response.status).toBe(200);
})
it('Should update product with id', async () => {
const response = await request
.put("/products/1")
.auth(token, { type: 'bearer'})
.send(updatedProduct)
expect(response.status).toBe(200);
})
it('Should delete product with id', async () => {
const response = await request
.delete("/products/1")
.auth(token, { type: 'bearer'})
expect(response.status).toBe(200);
})
})

@ -0,0 +1,75 @@
import supertest from "supertest"
import app from "../../server"
import { User } from '../../models/user'
const token = process.env.TOKEN_SECRET_TEST as string
const request = supertest(app);
const testUser: User = {
id: 1,
firstname: 'John',
lastname: 'Doe',
username: 'Jd',
password: 'password'
}
describe("Users handler", () => {
it('Should create a new user', async () => {
const response = await request
.post("/users")
.auth(token, {type: "bearer"})
.send(testUser);
expect(response.status).toBe(200)
})
it('Should authenticate a user', async () => {
const response = await request
.post("/users/auth")
.auth(token, {type: "bearer"})
.send(testUser);
expect(response.status).toBe(200)
})
it('Should index users', async () => {
const response = await request
.get("/users")
.auth(token, {type: "bearer"})
expect(response.status).toBe(200)
})
it('Should get user by id', async () => {
const response = await request
.get("/users/1")
.auth(token, {type: "bearer"})
expect(response.status).toBe(200)
})
it('Should update a user', async () => {
const updatedUser = {
id: 1,
firstname: 'Sara',
lastname: 'Doe',
username: 'Sd',
password: 'password123'
}
const response = await request
.put("/users/1")
.auth(token, {type: 'bearer'})
.send(updatedUser)
expect(response.status).toBe(200)
})
it('Should delete a user by id', async () => {
const response = await request
.delete("/users/1")
.auth(token, {type: 'bearer'})
expect(response.status).toBe(200)
})
})

@ -0,0 +1,98 @@
import { User, UserStore } from '../../models/user'
import { Product, ProductStore } from '../../models/product';
import { Order, OrderProduct, OrderStore } from '../../models/order'
const orderStore = new OrderStore()
const userStore = new UserStore()
const productStore = new ProductStore()
const testProduct: Product = {
id: 2,
name: '1984',
price: 5
}
const testUser: User = {
id: 2,
firstname: 'John',
lastname: 'Doe',
username: 'Jd',
password: 'password'
}
const testOrder: Order = {
id: 1,
status: "active",
user_id: 2
}
const testOrderProduct: OrderProduct = {
id: 1,
quantity: 5,
order_id: 1,
product_id: 2
}
describe("Order model", () => {
beforeAll(async () => {
await productStore.create(testProduct)
await userStore.create(testUser)
})
console.log('ORDER')
it('Should have an index method', () => {
expect(orderStore.index).toBeDefined();
});
it('Should have a read method', () => {
expect(orderStore.read).toBeDefined;
});
it('Should have a create method', () => {
expect(orderStore.create).toBeDefined;
});
it('Should have a update method', () => {
expect(orderStore.addProduct).toBeDefined;
});
it('Create method should add a new order', async () => {
const result = await orderStore.create(testOrder)
expect(result).toEqual(testOrder)
});
it('Index method should return a list of orders', async () => {
const result = await orderStore.index();
expect(result[0]).toEqual(testOrder)
})
it('Read method should return a order', async () => {
const result = await orderStore.read(2);
expect(result).toEqual(testOrder)
})
it('addProduct should add a new product to order', async () => {
const result = await orderStore.addProduct(testOrderProduct)
expect(result).toEqual(testOrderProduct)
})
it('deleteProduct should delete product from order', async () => {
const result = await orderStore.deleteProduct(1)
const checkorder = await orderStore.index()
expect(checkorder).toEqual([])
})
afterAll(async () => {
await productStore.delete(1)
await userStore.delete(1)
})
});

@ -0,0 +1,73 @@
import { Product, ProductStore } from '../../models/product'
const store = new ProductStore()
const testProduct: Product = {
id: 1,
name: '1984',
price: 5,
}
const updatedProduct: Product = {
id: 1,
name: 'The Dark Tower',
price: 7
}
describe("Product model", () => {
it('Should have an index method', () => {
expect(store.index).toBeDefined();
});
it('Should have a read method', () => {
expect(store.read).toBeDefined;
});
it('Should have a create method', () => {
expect(store.create).toBeDefined;
});
it('Should have a update method', () => {
expect(store.update).toBeDefined;
});
it('Should have a delete method', () => {
expect(store.delete).toBeDefined;
});
it('Create method should add a product', async () => {
const result = await store.create(testProduct);
expect(result).toEqual(testProduct);
});
it('Index method should return a list of products', async () => {
const result = await store.index();
expect(result).toEqual([testProduct]);
});
it('Read method should return a product', async () => {
const result = await store.read(1);
expect(result).toEqual(testProduct);
});
it('Update method should update a product', async () => {
const result = await store.update(updatedProduct);
expect(result).toEqual({
id: 1,
name: 'The Dark Tower',
price: 7,
});
});
it('Delete method should remove the product', async () => {
store.delete(1);
const result = await store.index()
expect(result).toEqual([]);
});
});

@ -0,0 +1,110 @@
import { User, UserStore } from '../../models/user'
import bcrypt from 'bcrypt'
const { BCRYPT_PASSWORD } = process.env
const pepper = BCRYPT_PASSWORD
const store = new UserStore()
const testUser: User = {
id: 1,
firstname: 'John',
lastname: 'Doe',
username: 'Jd',
password: 'password'
}
const updatedUser: User = {
id: 1,
firstname: 'Sara',
lastname: 'Doe',
username: 'Sd',
password: 'password123'
}
describe("User model", () => {
console.log("USER")
it('Should have an index method', () => {
expect(store.index).toBeDefined();
});
it('Should have a read method', () => {
expect(store.read).toBeDefined;
});
it('Should have a create method', () => {
expect(store.create).toBeDefined;
});
it('Should have a update method', () => {
expect(store.update).toBeDefined;
});
it('Should have a delete method', () => {
expect(store.delete).toBeDefined;
});
it('Create method should create a new user', async () => {
const result = await store.create(testUser);
expect(result.firstname).toEqual(testUser.firstname)
expect(result.lastname).toEqual(testUser.lastname)
expect(result.username).toEqual(testUser.username)
expect(bcrypt.compareSync(testUser.password + pepper, result.password)).toBeTrue
})
it('Index method should should return a list of users', async () => {
const result = await store.index();
expect(result[0].firstname).toEqual(testUser.firstname)
expect(result[0].lastname).toEqual(testUser.lastname)
expect(result[0].username).toEqual(testUser.username)
expect(bcrypt.compareSync(testUser.password + pepper, result[0].password)).toBeTrue
})
it('Read method should return user', async () => {
const result = await store.read(1);
expect(result.firstname).toEqual(testUser.firstname)
expect(result.lastname).toEqual(testUser.lastname)
expect(result.username).toEqual(testUser.username)
expect(bcrypt.compareSync(testUser.password + pepper, result.password)).toBeTrue
})
it('Authenticate method', async () => {
const authUser = {
username: 'Jd',
password: 'password'
}
const result = await store.authenticate(authUser.username, authUser.password);
if (result) {
expect(result.firstname).toEqual(testUser.firstname)
expect(result.lastname).toEqual(testUser.lastname)
expect(result.username).toEqual(testUser.username)
expect(bcrypt.compareSync(testUser.password + pepper, result.password)).toBeTrue
}
})
it('Update method should create a new user', async () => {
const result = await store.update(updatedUser);
expect(result.firstname).toEqual(updatedUser.firstname)
expect(result.lastname).toEqual(updatedUser.lastname)
expect(result.username).toEqual(updatedUser.username)
expect(bcrypt.compareSync(updatedUser.password + pepper, result.password)).toBeTrue
})
it('Delete method should delete a user by Id', async () => {
const result = await store.delete(1);
const checkUsers = await store.index()
expect(checkUsers).toEqual([])
})
})

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save