+
Node.js Crud Application
+
+
+ This application demonstrates how a Node.js application implements a
+ CRUD endpoint to manage fruits. This management interface
+ invokes the CRUD service endpoint, that interact with a PosgreSQL
+ database .
+
+
+
Add/Edit a fruit
+
+
+
+
Fruit List
+
+
+
+
+
{{ fruit.name }}
+
{{ fruit.stock }}
+
+
+
+
+
+
+
diff --git a/nodejs-rest-http-crud/test/fruits-api-test.js b/nodejs-rest-http-crud/test/fruits-api-test.js
new file mode 100644
index 0000000..18530c1
--- /dev/null
+++ b/nodejs-rest-http-crud/test/fruits-api-test.js
@@ -0,0 +1,50 @@
+/* eslint-disable no-undef */
+'use strict';
+
+const assert = require('assert');
+const proxyquire = require('proxyquire');
+
+const mockDb = {
+ query: () => {
+ return Promise.resolve();
+ }
+};
+
+const fruits = proxyquire('../lib/api/fruits', {
+ '../db': mockDb
+});
+
+describe('Fruits methods', () => {
+ it('API', () => {
+ assert.strictEqual(typeof fruits.find, 'function');
+ assert.strictEqual(typeof fruits.findAll, 'function');
+ assert.strictEqual(typeof fruits.create, 'function');
+ assert.strictEqual(typeof fruits.update, 'function');
+ assert.strictEqual(typeof fruits.remove, 'function');
+ });
+
+ it('find all', () => {
+ const result = fruits.findAll();
+ assert.strictEqual(result instanceof Promise, true);
+ });
+
+ it('find', () => {
+ const result = fruits.find('id');
+ assert.strictEqual(result instanceof Promise, true);
+ });
+
+ it('create', () => {
+ const result = fruits.create('name', 'stock');
+ assert.strictEqual(result instanceof Promise, true);
+ });
+
+ it('update', () => {
+ const result = fruits.update({ name: 'name', stock: 'stock', id: 1 });
+ assert.strictEqual(result instanceof Promise, true);
+ });
+
+ it('remove', () => {
+ const result = fruits.remove('id');
+ assert.strictEqual(result instanceof Promise, true);
+ });
+});
diff --git a/nodejs-rest-http-crud/test/fruits-test.js b/nodejs-rest-http-crud/test/fruits-test.js
new file mode 100644
index 0000000..8b5cee5
--- /dev/null
+++ b/nodejs-rest-http-crud/test/fruits-test.js
@@ -0,0 +1,641 @@
+/* eslint-disable no-undef */
+'use strict';
+
+const assert = require('assert');
+const supertest = require('supertest');
+const proxyquire = require('proxyquire');
+
+const mockDb = {
+ init: () => {
+ return Promise.resolve();
+ }
+};
+
+describe('Fruits', () => {
+ it('get all', async () => {
+ const mockApi = {
+ findAll: () => Promise.resolve({ rows: [{ id: 1 }] })
+ };
+
+ // Mock the nested require
+ const routesStub = proxyquire('../lib/routes/fruits', {
+ '../api/fruits': mockApi
+ });
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb,
+ './lib/routes/fruits': routesStub
+ });
+
+ const { body } = await supertest(app)
+ .get('/api/fruits')
+ .expect('Content-Type', /json/)
+ .expect(200);
+
+ assert.strictEqual(Array.isArray(body), true);
+ assert.strictEqual(body.length, 1);
+ });
+
+ it('get all error', async () => {
+ const mockApi = {
+ findAll: () => Promise.reject(new Error('error'))
+ };
+
+ // Mock the nested require
+ const routesStub = proxyquire('../lib/routes/fruits', {
+ '../api/fruits': mockApi
+ });
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb,
+ './lib/routes/fruits': routesStub
+ });
+
+ const response = await supertest(app)
+ .get('/api/fruits')
+ .expect(400);
+
+ assert.strictEqual(response.statusCode, 400);
+ });
+
+ it('get one', async () => {
+ const mockApi = {
+ find: id => {
+ assert.strictEqual(id, '1');
+ return Promise.resolve({ rows: [{ id }] });
+ }
+ };
+ // Mock the nested require
+ const routesStub = proxyquire('../lib/routes/fruits', {
+ '../api/fruits': mockApi
+ });
+ const app = proxyquire('../app', {
+ './lib/db': mockDb,
+ './lib/routes/fruits': routesStub
+ });
+ const { body } = await supertest(app)
+ .get('/api/fruits/1')
+ .expect('Content-Type', /json/)
+ .expect(200);
+ assert.strictEqual(Array.isArray(body), false);
+ assert.strictEqual(body.id, '1');
+ });
+
+ it('get one - return 404', async () => {
+ const mockApi = {
+ find: () => Promise.resolve({ rowCount: 0 })
+ };
+
+ // Mock the nested require
+ const routesStub = proxyquire('../lib/routes/fruits', {
+ '../api/fruits': mockApi
+ });
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb,
+ './lib/routes/fruits': routesStub
+ });
+ const response = await supertest(app)
+ .get('/api/fruits/1')
+ .expect(404);
+ assert.strictEqual(response.text, 'Item 1 not found');
+ });
+
+ it('get one - error', async () => {
+ const mockApi = {
+ find: () => Promise.reject(new Error('error'))
+ };
+
+ // Mock the nested require
+ const routesStub = proxyquire('../lib/routes/fruits', {
+ '../api/fruits': mockApi
+ });
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb,
+ './lib/routes/fruits': routesStub
+ });
+
+ const response = await supertest(app)
+ .get('/api/fruits/1')
+ .expect(400);
+ assert.strictEqual(response.statusCode, 400);
+ });
+
+ it('post', async () => {
+ const fruitData = {
+ name: 'Banana',
+ stock: 10
+ };
+
+ const mockApi = {
+ create: (name, stock) => {
+ assert.strictEqual(name, fruitData.name);
+ assert.strictEqual(stock, fruitData.stock);
+ return Promise.resolve({ rows: [] });
+ }
+ };
+
+ // Mock the nested require
+ const routesStub = proxyquire('../lib/routes/fruits', {
+ '../api/fruits': mockApi
+ });
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb,
+ './lib/routes/fruits': routesStub
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .send(fruitData)
+ .expect(201);
+ assert.strictEqual(response.statusCode, 201);
+ });
+
+ it('post - error - no name', async () => {
+ const fruitData = {
+ stock: 10
+ };
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .send(fruitData)
+ .expect(422);
+ assert.strictEqual(response.statusCode, 422);
+ assert.strictEqual(response.text, 'The name is required!');
+ });
+
+ it('post - error - no stock', async () => {
+ const fruitData = {
+ name: 'Banana'
+ };
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .send(fruitData)
+ .expect(422);
+ assert.strictEqual(response.statusCode, 422);
+ assert.strictEqual(response.text, 'The stock must be greater or equal to 0!');
+ });
+
+ it('post - error - id error', async () => {
+ const app = proxyquire('../app', {
+ './lib/db': mockDb
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .send({ name: 'Banana', stock: 10, id: 22 })
+ .expect(422);
+
+ assert.strictEqual(response.statusCode, 422);
+ assert.strictEqual(response.text, 'Id was invalidly set on request.');
+ });
+
+ it('post - error', async () => {
+ const fruitData = {
+ name: 'Banana',
+ stock: 10
+ };
+
+ const mockApi = {
+ create: () => {
+ return Promise.reject(new Error('error'));
+ }
+ };
+
+ // Mock the nested require
+ const routesStub = proxyquire('../lib/routes/fruits', {
+ '../api/fruits': mockApi
+ });
+
+ const app = proxyquire('../app', {
+ './lib/db': mockDb,
+ './lib/routes/fruits': routesStub
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .send(fruitData)
+ .expect(400);
+
+ assert.strictEqual(response.statusCode, 400);
+ });
+
+ it('post - error - id error', async () => {
+ const app = proxyquire('../app', {
+ './lib/db': mockDb
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .send({ name: 'Banana', stock: 10, id: 22 })
+ .expect(422);
+
+ assert.strictEqual(response.statusCode, 422);
+ assert.strictEqual(response.text, 'Id was invalidly set on request.');
+ });
+
+ it('post - error - no payload', async () => {
+ const app = proxyquire('../app', {
+ './lib/db': mockDb
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .expect(415);
+
+ assert.strictEqual(response.statusCode, 415);
+ assert.strictEqual(response.text, 'Invalid payload!');
+ });
+
+ it('post - error - invalid payload', async () => {
+ const app = proxyquire('../app', {
+ './lib/db': mockDb
+ });
+
+ const response = await supertest(app)
+ .post('/api/fruits')
+ .set('Content-Type', 'application/json')
+ .send('Some text')
+ .expect(415);
+
+ assert.strictEqual(response.statusCode, 415);
+ assert.strictEqual(response.text, 'Invalid payload!');
+ });
+
+ it('post - error - xml payload', async () => {
+ const app = proxyquire('../app', {
+ './lib/db': mockDb
+ });
+ const xmlFruitData = '