// data structure as dummy database
class BookAMeal {
constructor() {
this.mealOptionList = [];
this.menuList = [];
this.orderList = [];
}
mealFormat(data) {
this.mealOptionData = {
id: data.mealId,
name: data.mealOptionName,
price: parseInt(data.mealOptionPrice, 10),
};
return this.mealOptionData;
}
totalPriceMenu(optionOneArray, optionTwoArray) {
this.total = 0;
optionOneArray.forEach((optionOne) => {
optionTwoArray.forEach((optionTwo) => {
if (optionOne === optionTwo.name) {
this.total += optionTwo.price;
}
});
});
return this.total;
}
totalPriceOrders(optionOneArray, optionTwoArray) {
this.total = 0;
optionOneArray.forEach((optionOne) => {
optionTwoArray.forEach((optionTwo) => {
if (optionOne === optionTwo.name) {
this.total += optionTwo.total;
}
});
});
return this.total;
}
menuFormat(data) {
this.menuOptions = data.menuOptions.split(' ');
this.menuData = {
date: new Date(),
id: data.menuId,
name: data.menuName,
mealOptions: this.menuOptions,
total: this.totalPriceMenu(this.menuOptions, this.mealOptionList),
};
return this.menuData;
}
orderFormat(data) {
this.orderMenus = data.menuList.split(' ');
this.orderData = {
id: data.orderId,
customer: data.customerName,
menu: this.orderMenus,
total: this.totalPriceOrders(this.orderMenus, this.menuList),
};
return this.orderData;
}
}
const data = new BookAMeal();
export default data;
// meals controller for POST route that works fine with both mocha and POSTMAN after refracting
import data from '../models';
import services from '../services';
// @ts-ignore
import bookAMeal from './index';
bookAMeal.addOneMealOption = async (req, res) => {
services.createOne(res, data.mealOptionList, data.mealFormat(req.body),
'Success! Meal option created', req.body.mealOptionName, req.body.mealOptionPrice,
(/^[A-Za-z]+$/).test(req.body.mealOptionName), (/^[0-9]+$/).test(req.body.mealOptionPrice),
'Meal option name', 'Meal option price', services.mustBeNumbersErr('Meal option price'));
};
export default bookAMeal.addOneMealOption;
// menu controller for POST route that gives error 500 during testing with mocha and POSTMAN when refracted like above meals controller
import data from '../models';
import services from '../services';
// @ts-ignore
import bookAMeal from './index';
bookAMeal.setMenu = async (req, res) => {
services.createOne(res, data.menuList, data.menuFormat(req.body),
'Success! Menu created', req.body.menuName, req.body.menuOptions,
(/^[A-Za-z]+$/).test(req.body.menuName), (/^[A-Za-z\s]+$/).test(req.body.menuOptions),
'Menu name', 'Menu options', services.stringToArrayErr('Menu options'));
// commented code below passes with both mocha and POSTMAN but needs to be refracted to pass code climate
/*
const testSetMenu = services.testItem(req.body.menuName, req.body.menuOptions, (/^[A-Za-z]+$/).test(req.body.menuName), (/^[A-Za-z\s]+$/).test(req.body.menuOptions));
if (testSetMenu) {
services.createOneRes(res, data.menuList, data.menuFormat(req.body), 'Success! Menu created');
return;
}
services.processErr(req.body.menuName, req.body.menuOptions, 'Menu name', 'Menu options', services.stringToArrayErr('Menu options'), res);
*/
};
export default bookAMeal.setMenu;
// services that is called by all controllers including the above 2
class Services {
async getAll(dataRes, dataMessage, array) {
this.data = array;
dataRes.status(200).send({
message: dataMessage,
data: this.data,
});
}
findOne(dataParams, arrayData) {
this.findItem = arrayData.find(item => item.id === parseInt(dataParams.id, 10));
return this.findItem;
}
testItem(dataOne, dataTwo, dataOneTest, dataTwoTest) {
this.testResult = (dataOne && dataTwo && dataOneTest && dataTwoTest) === true;
return this.testResult;
}
async createOneRes(dataRes, arrayData, dataFormat, dataMessage) {
this.createdItem = await dataFormat;
this.createdItem.id = arrayData.length;
await arrayData.push(this.createdItem);
dataRes.status(201).send({
message: dataMessage,
data: this.createdItem,
});
}
async createOne(dataRes, arrayData, dataFormat, dataMessage, dataOne,
dataTwo, dataOneTest, dataTwoTest, nameOne, nameTwo, dataTwoTestRes) {
this.testCreate = this.testItem(dataOne, dataTwo, dataOneTest, dataTwoTest);
if (this.testCreate) {
this.createOneRes(dataRes, arrayData, dataFormat, dataMessage);
return;
}
this.processErr(dataOne, dataTwo, nameOne, nameTwo, dataTwoTestRes, dataRes);
}
async updateOne(dataRes, arrayData, dataFormat, dataMessage, updateId) {
this.updatedItem = await dataFormat;
this.updatedItem = updateId;
await arrayData.splice(updateId, 1, this.updatedItem);
dataRes.status(200).send({
message: dataMessage,
data: this.updatedItem,
});
}
async deleteOne(dataRes, arrayData, deleteId) {
this.id = deleteId;
await arrayData.splice(this.id, 1);
dataRes.status(204).send({});
}
requiredNameErr(name) {
this.message = {
message: `Fail! ${name} is required`,
};
return this.message;
}
mustBeLettersErr(name) {
this.message = {
message: `Fail! ${name} must be letters`,
};
return this.message;
}
mustBeNumbersErr(price) {
this.message = {
message: `Fail! ${price} must be numbers`,
};
return this.message;
}
stringToArrayErr(name) {
this.message = {
message: `Fail! ${name} must be letters and seperated by spaces`,
};
return this.message;
}
sendErr400(message, dataRes) {
this.error = dataRes.status(400).send(message);
return this.error;
}
processErr(dataOne, dataTwo, nameOne, nameTwo, dataTwoTestRes, resData) {
if (!dataOne) {
this.sendErr400(this.requiredNameErr(nameOne), resData);
return;
}
if ((/^[A-Za-z]+$/).test(dataOne) === false) {
this.sendErr400(this.mustBeLettersErr(nameOne), resData);
return;
}
if (!dataTwo) {
this.sendErr400(this.requiredNameErr(nameTwo), resData);
return;
}
this.sendErr400(dataTwoTestRes, resData);
}
}
const services = new Services();
export default services;
// exported data seeding for tests
import chai, {
expect,
} from 'chai';
import chaiHttp from 'chai-http';
import app from '../index';
import data from '../models';
class Data {
async meals() {
this.testId = 0;
this.secondTestId = 0;
this.thirdTestId = 0;
this.testDataOne = {
mealId: data.mealOptionList.length,
mealOptionName: 'Dodo',
mealOptionPrice: 100,
};
this.testDataTwo = {
mealId: data.mealOptionList.length,
mealOptionName: 'Rice',
mealOptionPrice: 1000,
};
this.testDataThree = {
mealId: data.mealOptionList.length,
mealOptionName: 'Beans',
mealOptionPrice: 10000,
};
this.addMealOne = await data.mealFormat(this.testDataOne);
this.addMealTwo = await data.mealFormat(this.testDataTwo);
this.addMealThree = await data.mealFormat(this.testDataThree);
this.testDataList = [this.addMealOne, this.addMealTwo, this.addMealThree];
await data.mealOptionList.push(...this.testDataList);
this.testId += this.addMealOne.id;
this.secondTestId += this.addMealTwo.id;
this.thirdTestId += this.addMealThree.id;
}
async menus() {
this.testId = 0;
this.secondTestId = 0;
this.thirdTestId = 0;
this.testDataFour = {
menuId: data.menuList.length,
menuName: 'Launch',
menuOptions: 'Rice Dodo',
};
this.testDataFive = {
menuId: data.menuList.length,
menuName: 'Dinner',
menuOptions: 'Rice Beans',
};
this.testDataSix = {
menuId: data.menuList.length,
menuName: 'Breakfast',
menuOptions: 'Beans Dodo',
};
this.addOne = await data.menuFormat(this.testDataFour);
this.addTwo = await data.menuFormat(this.testDataFive);
this.addThree = await data.menuFormat(this.testDataSix);
this.testDataListTwo = [this.addOne, this.addTwo, this.addThree];
await data.menuList.push(...this.testDataListTwo);
this.testId += this.addOne.id;
this.secondTestId += this.addTwo.id;
this.thirdTestId += this.addThree.id;
}
async orders() {
this.testId = 0;
this.secondTestId = 0;
this.thirdTestId = 0;
this.testDataSeven = {
orderId: data.orderList.length,
customerName: 'Okezie',
menuList: 'Breakfast Lunch',
};
this.testDataEight = {
orderId: data.orderList.length,
customerName: 'Frank',
menuList: 'Breakfast Dinner',
};
this.testDataNine = {
orderId: data.orderList.length,
customerName: 'Obiedere',
menuList: 'Lunch Dinner',
};
this.addFour = await data.orderFormat(this.testDataSeven);
this.addFive = await data.orderFormat(this.testDataEight);
this.addSix = await data.orderFormat(this.testDataNine);
this.testDataListThree = [this.addFour, this.addFive, this.addSix];
await data.orderList.push(...this.testDataListThree);
this.testId += this.addFour.id;
this.secondTestId += this.addFive.id;
this.thirdTestId += this.addSix.id;
}
}
const dataSetup = new Data();
export {
expect,
chai,
chaiHttp,
app,
dataSetup,
};
// tests for meals controller that passes both mocha and POSTMAN
import {
expect,
chai,
chaiHttp,
app,
dataSetup,
} from './index';
chai.use(chaiHttp);
describe('Test endpoint at "/v1/meals" to create a meal option with POST', () => {
before(() => {
dataSetup.meals();
dataSetup.menus();
dataSetup.orders();
});
it('should create a meal option at "/v1/meal" with post if all request data are valid', async () => {
const testData = {
mealOptionName: 'Dodo',
mealOptionPrice: 10,
};
const response = await chai.request(app).post('/v1/meals').send(testData);
expect(response).to.have.status(201);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('data');
expect(response.body).to.have.property('message').equal('Success! Meal option created');
expect(response.body.data).to.have.property('id');
expect(response.body.data).to.have.property('name').equal(testData.mealOptionName);
expect(response.body.data).to.have.property('price').equal(testData.mealOptionPrice);
});
it('should not create a meal option at "/v1/meals" with POST if meal option name in request does not exist', async () => {
const testData = {
mealOptionPrice: 10,
};
const response = await chai.request(app).post('/v1/meals').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Meal option name is required');
});
it('should not create a meal option at "/v1/meals" with POST if meal option name in request is an empty string', async () => {
const testData = {
mealOptionName: '',
mealOptionPrice: 10,
};
const response = await chai.request(app).post('/v1/meals').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Meal option name is required');
});
it('should not create a meal option at "/v1/meals" with POST if meal option name in request are not letters', async () => {
const testData = {
mealOptionName: '0(}fieidfjd',
mealOptionPrice: 10,
};
const response = await chai.request(app).post('/v1/meals').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Meal option name must be letters');
});
it('should not create a meal option at "/v1/meals" with POST if meal option price in request does not exist', async () => {
const testData = {
mealOptionName: 'Dodo',
};
const response = await chai.request(app).post('/v1/meals').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Meal option price is required');
});
it('should not create a meal option at "/v1/meals" with POST if meal option price in request is an empty string', async () => {
const testData = {
mealOptionName: 'Dodo',
mealOptionPrice: '',
};
const response = await chai.request(app).post('/v1/meals').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Meal option price is required');
});
it('should not create a meal option at "/v1/meals" with POST if meal option price in request is NOT a number', async () => {
const testData = {
mealOptionName: 'Dodo',
mealOptionPrice: 'p0{f(jf]',
};
const response = await chai.request(app).post('/v1/meals').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Meal option price must be numbers');
});
});
// tests for menu controller that fails mocha at 'menu options does not exist' but passes with POSTMAN
import {
expect,
chai,
chaiHttp,
app,
dataSetup,
} from './index';
chai.use(chaiHttp);
describe('Test endpoint at "/v1/menus" to set menus with POST', () => {
before(() => {
dataSetup.meals();
dataSetup.menus();
dataSetup.orders();
});
it('should set a menu at "/v1/menus" with post if all request data are valid', async () => {
const testData = {
menuName: 'Launch',
menuOptions: 'Dodo Rice',
};
const response = await chai.request(app).post('/v1/menus').send(testData);
expect(response).to.have.status(201);
expect(response).to.be.an('object');
expect(response.body).to.have.property('data');
expect(response.body).to.have.property('message').equal('Success! Menu created');
expect(response.body.data).to.have.property('id');
expect(response.body.data).to.have.property('name').equal(testData.menuName);
expect(response.body.data).to.have.property('total');
});
it('should not create a menu at "/v1/menus" with POST if menu name in request does not exist', async () => {
const testData = {
menuOptions: 'Dodo Beans',
};
const response = await chai.request(app).post('/v1/menus').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Menu name is required');
});
it('should not create a menu at "/v1/menus" with POST if menu name in request is an empty string', async () => {
const testData = {
menuName: '',
menuOptions: 'Dodo Beans',
};
const response = await chai.request(app).post('/v1/menus').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Menu name is required');
});
it('should not create a menu at "/v1/menus" with POST if menu name in request are not letters', async () => {
const testData = {
menuName: '}04[}(odyr',
menuOptions: 'Dodo Beans',
};
const response = await chai.request(app).post('/v1/menus').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Menu name must be letters');
});
it('should not create a menu at "/v1/menus" with POST if menu options in request does not exist', async () => {
const testData = {
menuName: 'Launch',
};
const response = await chai.request(app).post('/v1/menus').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Menu options is required');
});
it('should not create a menu at "/v1/menus" with POST if menu options in request is an empty string', async () => {
const testData = {
menuName: 'Launch',
menuOptions: '',
};
const response = await chai.request(app).post('/v1/menus').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Menu options is required');
});
it('should not create a menu at "/v1/menus" with POST if menu options in request are not letters', async () => {
const testData = {
menuName: 'Launch',
menuOptions: '90{f]f9d()',
};
const response = await chai.request(app).post('/v1/menus').send(testData);
expect(response).to.have.status(400);
expect(response.body).to.be.an('object');
expect(response.body).to.have.property('message').equal('Fail! Menu options must be letters and seperated by spaces');
});
});