diff --git a/application-templates/javascript/event/src/app.js b/application-templates/javascript/event/src/app.js new file mode 100644 index 0000000..7574371 --- /dev/null +++ b/application-templates/javascript/event/src/app.js @@ -0,0 +1,33 @@ +import 'dotenv/config'; + +import express from 'express'; +import bodyParser from 'body-parser'; + +// Import routes +import EventRoutes from './routes/event.route.js'; + +import { readConfiguration } from './utils/config.utils.js'; +import { errorMiddleware } from './middleware/error.middleware.js'; +import CustomError from './errors/custom.error.js'; + +// Read env variables +readConfiguration(); + +// Create the express app +const app = express(); +app.disable('x-powered-by'); + +// Define configurations +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +// Define routes +app.use('/event', EventRoutes); +app.use('*', () => { + throw new CustomError(404, 'Path not found.'); +}); + +// Global error handler +app.use(errorMiddleware); + +export default app; diff --git a/application-templates/javascript/event/src/index.js b/application-templates/javascript/event/src/index.js index 494305d..529964a 100644 --- a/application-templates/javascript/event/src/index.js +++ b/application-templates/javascript/event/src/index.js @@ -1,34 +1,11 @@ import 'dotenv/config'; -import express from 'express'; -import bodyParser from 'body-parser'; - -// Import routes -import EventRoutes from './routes/event.route.js'; import { logger } from './utils/logger.utils.js'; -import { readConfiguration } from './utils/config.utils.js'; -import { errorMiddleware } from './middleware/error.middleware.js'; - -// Read env variables -readConfiguration(); +import app from './app.js'; const PORT = 8080; -// Create the express app -const app = express(); -app.disable('x-powered-by'); - -// Define configurations -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); - -// Define routes -app.use('/event', EventRoutes); - -// Global error handler -app.use(errorMiddleware); - // Listen the application const server = app.listen(PORT, () => { logger.info(`⚡️ Event application listening on port ${PORT}`); diff --git a/application-templates/javascript/event/src/middleware/error.middleware.js b/application-templates/javascript/event/src/middleware/error.middleware.js index 991c1e5..1a3d13f 100644 --- a/application-templates/javascript/event/src/middleware/error.middleware.js +++ b/application-templates/javascript/event/src/middleware/error.middleware.js @@ -1,6 +1,6 @@ import CustomError from '../errors/custom.error.js'; -export const errorMiddleware = (error, _req, res) => { +export const errorMiddleware = (error, _req, res, _next) => { const isDevelopment = process.env.NODE_ENV === 'development'; if (error instanceof CustomError) { @@ -13,5 +13,11 @@ export const errorMiddleware = (error, _req, res) => { return; } - res.status(500).send(isDevelopment ? error : 'Internal server error'); + res + .status(500) + .send( + isDevelopment + ? { messge: error.message } + : { message: 'Internal server error' } + ); }; diff --git a/application-templates/javascript/event/src/routes/event.route.js b/application-templates/javascript/event/src/routes/event.route.js index afc58ec..d84de72 100644 --- a/application-templates/javascript/event/src/routes/event.route.js +++ b/application-templates/javascript/event/src/routes/event.route.js @@ -5,11 +5,11 @@ import { post } from '../controllers/event.controller.js'; const eventRouter = Router(); -eventRouter.post('/', (req, res, next) => { +eventRouter.post('/', async (req, res, next) => { logger.info('Event message received'); try { - post(req, res); + await post(req, res); } catch (error) { next(error); } diff --git a/application-templates/javascript/event/tests/integration/routes.spec.js b/application-templates/javascript/event/tests/integration/routes.spec.js index 1994aef..06ab3c4 100644 --- a/application-templates/javascript/event/tests/integration/routes.spec.js +++ b/application-templates/javascript/event/tests/integration/routes.spec.js @@ -1,9 +1,51 @@ import { expect } from '@jest/globals'; +import request from 'supertest'; +import app from '../../src/app'; +import * as eventController from '../../src/controllers/event.controller'; -//@todo: test this with msw (see typescipt job) -// make msw a shared package -describe('Testing Event Controller', () => { - test('POST `/event` route', async () => { - expect(1).toBe(1); +describe('Testing router', () => { + test('Post to non existing route', async () => { + const response = await request(app).post('/none'); + expect(response.status).toBe(404); + expect(response.body).toEqual({ + message: 'Path not found.', + }); + }); + test('Post invalid body', async () => { + const response = await request(app).post('/event').send({ + message: 'hello world', + }); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request: No customer id in the Pub/Sub message', + }); + }); + test('Post empty body', async () => { + const response = await request(app).post('/event'); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request: Wrong No Pub/Sub message format', + }); + }); +}); +describe('unexpected error', () => { + let postMock; + + beforeEach(() => { + // Mock the post method to throw an error + postMock = jest.spyOn(eventController, 'post').mockImplementation(() => { + throw new Error('Test error'); + }); + }); + + afterEach(() => { + // Restore the original implementation + postMock.mockRestore(); + }); + test('should handle errors thrown by post method', async () => { + // Call the route handler + const response = await request(app).post('/event'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ message: 'Internal server error' }); }); }); diff --git a/application-templates/javascript/job/src/app.js b/application-templates/javascript/job/src/app.js new file mode 100644 index 0000000..ff95c57 --- /dev/null +++ b/application-templates/javascript/job/src/app.js @@ -0,0 +1,29 @@ +import * as dotenv from 'dotenv'; +dotenv.config(); + +import express from 'express'; + +// Import routes +import JobRoutes from './routes/job.route.js'; + +import { readConfiguration } from './utils/config.utils.js'; +import { errorMiddleware } from './middleware/error.middleware.js'; +import CustomError from './errors/custom.error.js'; + +// Read env variables +readConfiguration(); + +// Create the express app +const app = express(); +app.disable('x-powered-by'); + +// Define routes +app.use('/job', JobRoutes); +app.use('*', () => { + throw new CustomError(404, 'Path not found.'); +}); + +// Global error handler +app.use(errorMiddleware); + +export default app; diff --git a/application-templates/javascript/job/src/index.js b/application-templates/javascript/job/src/index.js index 0b31bd7..6750ac1 100644 --- a/application-templates/javascript/job/src/index.js +++ b/application-templates/javascript/job/src/index.js @@ -1,32 +1,12 @@ import * as dotenv from 'dotenv'; dotenv.config(); -import express from 'express'; - -// Import routes -import JobRoutes from './routes/job.route.js'; - // Import logger import { logger } from './utils/logger.utils.js'; - -import { readConfiguration } from './utils/config.utils.js'; -import { errorMiddleware } from './middleware/error.middleware.js'; - -// Read env variables -readConfiguration(); +import app from './app.js'; const PORT = 8080; -// Create the express app -const app = express(); -app.disable('x-powered-by'); - -// Define routes -app.use('/job', JobRoutes); - -// Global error handler -app.use(errorMiddleware); - // Listen the application const server = app.listen(PORT, () => { logger.info(`⚡️ Job application listening on port ${PORT}`); diff --git a/application-templates/javascript/job/src/middleware/error.middleware.js b/application-templates/javascript/job/src/middleware/error.middleware.js index 991c1e5..1a3d13f 100644 --- a/application-templates/javascript/job/src/middleware/error.middleware.js +++ b/application-templates/javascript/job/src/middleware/error.middleware.js @@ -1,6 +1,6 @@ import CustomError from '../errors/custom.error.js'; -export const errorMiddleware = (error, _req, res) => { +export const errorMiddleware = (error, _req, res, _next) => { const isDevelopment = process.env.NODE_ENV === 'development'; if (error instanceof CustomError) { @@ -13,5 +13,11 @@ export const errorMiddleware = (error, _req, res) => { return; } - res.status(500).send(isDevelopment ? error : 'Internal server error'); + res + .status(500) + .send( + isDevelopment + ? { messge: error.message } + : { message: 'Internal server error' } + ); }; diff --git a/application-templates/javascript/job/src/routes/job.route.js b/application-templates/javascript/job/src/routes/job.route.js index 327d716..747bd37 100644 --- a/application-templates/javascript/job/src/routes/job.route.js +++ b/application-templates/javascript/job/src/routes/job.route.js @@ -5,9 +5,9 @@ import { post } from '../controllers/job.controller.js'; // Create the router for our app const jobRouter = Router(); -jobRouter.post('/', (req, res, next) => { +jobRouter.post('/', async (req, res, next) => { try { - post(req, res); + await post(req, res); } catch (error) { next(error); } diff --git a/application-templates/javascript/job/tests/integration/orders.spec.js b/application-templates/javascript/job/tests/integration/orders.spec.js index f33c33e..7f552f9 100644 --- a/application-templates/javascript/job/tests/integration/orders.spec.js +++ b/application-templates/javascript/job/tests/integration/orders.spec.js @@ -1,7 +1,35 @@ import { expect } from '@jest/globals'; +import request from 'supertest'; +import app from '../../src/app'; +import * as jobController from '../../src/controllers/job.controller'; -describe('Testing Job Template', () => { - test('GET all orders', async () => { - expect(1).toBe(1); +describe('Testing router', () => { + test('Post to non existing route', async () => { + const response = await request(app).post('/none'); + expect(response.status).toBe(404); + expect(response.body).toEqual({ + message: 'Path not found.', + }); + }); +}); +describe('unexpected error', () => { + let postMock; + + beforeEach(() => { + // Mock the post method to throw an error + postMock = jest.spyOn(jobController, 'post').mockImplementation(() => { + throw new Error('Test error'); + }); + }); + + afterEach(() => { + // Restore the original implementation + postMock.mockRestore(); + }); + test('should handle errors thrown by post method', async () => { + // Call the route handler + const response = await request(app).post('/job'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ message: 'Internal server error' }); }); }); diff --git a/application-templates/javascript/service/src/app.js b/application-templates/javascript/service/src/app.js new file mode 100644 index 0000000..ef9a7ed --- /dev/null +++ b/application-templates/javascript/service/src/app.js @@ -0,0 +1,32 @@ +import 'dotenv/config'; +import express from 'express'; +import bodyParser from 'body-parser'; + +// Import routes +import ServiceRoutes from './routes/service.route.js'; + +import { readConfiguration } from './utils/config.utils.js'; +import { errorMiddleware } from './middleware/error.middleware.js'; +import CustomError from './errors/custom.error.js'; + +// Read env variables +readConfiguration(); + +// Create the express app +const app = express(); +app.disable('x-powered-by'); + +// Define configurations +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +// Define routes +app.use('/service', ServiceRoutes); +app.use('*', () => { + throw new CustomError(404, 'Path not found.'); +}); + +// Global error handler +app.use(errorMiddleware); + +export default app; diff --git a/application-templates/javascript/service/src/index.js b/application-templates/javascript/service/src/index.js index 8f3ed1b..64cb717 100644 --- a/application-templates/javascript/service/src/index.js +++ b/application-templates/javascript/service/src/index.js @@ -1,35 +1,10 @@ import 'dotenv/config'; -import express from 'express'; -import bodyParser from 'body-parser'; - -// Import routes -import ServiceRoutes from './routes/service.route.js'; - // Import logger import { logger } from './utils/logger.utils.js'; - -import { readConfiguration } from './utils/config.utils.js'; -import { errorMiddleware } from './middleware/error.middleware.js'; - -// Read env variables -readConfiguration(); +import app from './app'; const PORT = 8080; -// Create the express app -const app = express(); -app.disable('x-powered-by'); - -// Define configurations -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); - -// Define routes -app.use('/service', ServiceRoutes); - -// Global error handler -app.use(errorMiddleware); - // Listen the application const server = app.listen(PORT, () => { logger.info(`⚡️ Service application listening on port ${PORT}`); diff --git a/application-templates/javascript/service/src/middleware/error.middleware.js b/application-templates/javascript/service/src/middleware/error.middleware.js index 991c1e5..0b4a45e 100644 --- a/application-templates/javascript/service/src/middleware/error.middleware.js +++ b/application-templates/javascript/service/src/middleware/error.middleware.js @@ -1,6 +1,6 @@ import CustomError from '../errors/custom.error.js'; -export const errorMiddleware = (error, _req, res) => { +export const errorMiddleware = (error, _req, res, _next) => { const isDevelopment = process.env.NODE_ENV === 'development'; if (error instanceof CustomError) { @@ -12,6 +12,11 @@ export const errorMiddleware = (error, _req, res) => { return; } - - res.status(500).send(isDevelopment ? error : 'Internal server error'); + res + .status(500) + .send( + isDevelopment + ? { messge: error.message } + : { message: 'Internal server error' } + ); }; diff --git a/application-templates/javascript/service/src/routes/service.route.js b/application-templates/javascript/service/src/routes/service.route.js index 51210da..894e8b8 100644 --- a/application-templates/javascript/service/src/routes/service.route.js +++ b/application-templates/javascript/service/src/routes/service.route.js @@ -4,11 +4,11 @@ import { post } from '../controllers/service.controller.js'; const serviceRouter = Router(); -serviceRouter.post('/', (req, res, next) => { +serviceRouter.post('/', async (req, res, next) => { logger.info('Cart update extension executed'); try { - post(req, res); + await post(req, res); } catch (error) { next(error); } diff --git a/application-templates/javascript/service/tests/integration/routes.spec.js b/application-templates/javascript/service/tests/integration/routes.spec.js index c452ee6..0e8ab4d 100644 --- a/application-templates/javascript/service/tests/integration/routes.spec.js +++ b/application-templates/javascript/service/tests/integration/routes.spec.js @@ -1,8 +1,51 @@ import { expect } from '@jest/globals'; +import request from 'supertest'; +import app from '../../src/app'; +import * as serviceController from '../../src/controllers/service.controller'; -//@todo: implement tests (use msw in shared package) -describe('Testing Cart Controller', () => { - test('POST `/service` route', async () => { - expect(1).toBe(88888888); +describe('Testing router', () => { + test('Post to non existing route', async () => { + const response = await request(app).post('/none'); + expect(response.status).toBe(404); + expect(response.body).toEqual({ + message: 'Path not found.', + }); + }); + test('Post invalid body', async () => { + const response = await request(app).post('/service').send({ + message: 'hello world', + }); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request - Missing body parameters.', + }); + }); + test('Post empty body', async () => { + const response = await request(app).post('/service'); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request - Missing body parameters.', + }); + }); +}); +describe('unexpected error', () => { + let postMock; + + beforeEach(() => { + // Mock the post method to throw an error + postMock = jest.spyOn(serviceController, 'post').mockImplementation(() => { + throw new Error('Test error'); + }); + }); + + afterEach(() => { + // Restore the original implementation + postMock.mockRestore(); + }); + test('should handle errors thrown by post method', async () => { + // Call the route handler + const response = await request(app).post('/service'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ message: 'Internal server error' }); }); }); diff --git a/application-templates/typescript/event/.eslintrc.cjs b/application-templates/typescript/event/.eslintrc.cjs index 8c19aef..bb6a70d 100644 --- a/application-templates/typescript/event/.eslintrc.cjs +++ b/application-templates/typescript/event/.eslintrc.cjs @@ -7,7 +7,7 @@ module.exports = { plugins: ['@typescript-eslint'], extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], rules: { - '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 'no-undef': 'error', 'no-console': 'error', 'no-const-assign': 'error', diff --git a/application-templates/typescript/event/src/app.ts b/application-templates/typescript/event/src/app.ts new file mode 100644 index 0000000..365140f --- /dev/null +++ b/application-templates/typescript/event/src/app.ts @@ -0,0 +1,34 @@ +import * as dotenv from 'dotenv'; +dotenv.config(); + +import express, { Express } from 'express'; +import bodyParser from 'body-parser'; + +// Import routes +import EventRoutes from './routes/event.route'; + +import { readConfiguration } from './utils/config.utils'; +import { errorMiddleware } from './middleware/error.middleware'; +import CustomError from './errors/custom.error'; + +// Read env variables +readConfiguration(); + +// Create the express app +const app: Express = express(); +app.disable('x-powered-by'); + +// Define configurations +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +// Define routes +app.use('/event', EventRoutes); +app.use('*', () => { + throw new CustomError(404, 'Path not found.'); +}); + +// Global error handler +app.use(errorMiddleware); + +export default app; diff --git a/application-templates/typescript/event/src/index.ts b/application-templates/typescript/event/src/index.ts index cb14379..fcdb418 100644 --- a/application-templates/typescript/event/src/index.ts +++ b/application-templates/typescript/event/src/index.ts @@ -1,35 +1,12 @@ import * as dotenv from 'dotenv'; dotenv.config(); -import express, { Express } from 'express'; -import bodyParser from 'body-parser'; - -// Import routes -import EventRoutes from './routes/event.route'; import { logger } from './utils/logger.utils'; -import { readConfiguration } from './utils/config.utils'; -import { errorMiddleware } from './middleware/error.middleware'; - -// Read env variables -readConfiguration(); +import app from './app'; const PORT = 8080; -// Create the express app -const app: Express = express(); -app.disable('x-powered-by'); - -// Define configurations -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); - -// Define routes -app.use('/event', EventRoutes); - -// Global error handler -app.use(errorMiddleware); - // Listen the application const server = app.listen(PORT, () => { logger.info(`⚡️ Event application listening on port ${PORT}`); diff --git a/application-templates/typescript/event/src/middleware/error.middleware.ts b/application-templates/typescript/event/src/middleware/error.middleware.ts index c76bfc3..8b1e6ba 100644 --- a/application-templates/typescript/event/src/middleware/error.middleware.ts +++ b/application-templates/typescript/event/src/middleware/error.middleware.ts @@ -1,10 +1,11 @@ -import { ErrorRequestHandler, Request, Response } from 'express'; +import { ErrorRequestHandler, NextFunction, Request, Response } from 'express'; import CustomError from '../errors/custom.error'; export const errorMiddleware: ErrorRequestHandler = ( error: Error, _: Request, - res: Response + res: Response, + _next: NextFunction ) => { const isDevelopment = process.env.NODE_ENV === 'development'; @@ -18,5 +19,11 @@ export const errorMiddleware: ErrorRequestHandler = ( return; } - res.status(500).send(isDevelopment ? error : 'Internal server error'); + res + .status(500) + .send( + isDevelopment + ? { messge: error.message } + : { message: 'Internal server error' } + ); }; diff --git a/application-templates/typescript/event/src/routes/event.route.ts b/application-templates/typescript/event/src/routes/event.route.ts index 6a097a3..0bd2fa5 100644 --- a/application-templates/typescript/event/src/routes/event.route.ts +++ b/application-templates/typescript/event/src/routes/event.route.ts @@ -5,10 +5,10 @@ import { post } from '../controllers/event.controller'; const eventRouter: Router = Router(); -eventRouter.post('/', (req, res, next) => { +eventRouter.post('/', async (req, res, next) => { logger.info('Event message received'); try { - post(req, res); + await post(req, res); } catch (error) { next(error); } diff --git a/application-templates/typescript/event/tests/event.spec.ts b/application-templates/typescript/event/tests/event.spec.ts index 1b176d7..f16396f 100644 --- a/application-templates/typescript/event/tests/event.spec.ts +++ b/application-templates/typescript/event/tests/event.spec.ts @@ -1,7 +1,51 @@ -import { describe, expect, test } from '@jest/globals'; +import { expect } from '@jest/globals'; +import request from 'supertest'; +import app from '../src/app'; +import * as enventController from '../src/controllers/event.controller'; -describe('Testing Event Controller', () => { - test('POST `/event` route', async () => { - expect(1).toBe(1); +describe('Testing router', () => { + test('Post to non existing route', async () => { + const response = await request(app).post('/none'); + expect(response.status).toBe(404); + expect(response.body).toEqual({ + message: 'Path not found.', + }); + }); + test('Post invalid body', async () => { + const response = await request(app).post('/event').send({ + message: 'hello world', + }); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request: No customer id in the Pub/Sub message', + }); + }); + test('Post empty body', async () => { + const response = await request(app).post('/event'); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request: Wrong No Pub/Sub message format', + }); + }); +}); +describe('unexpected error', () => { + let postMock: jest.SpyInstance; + + beforeEach(() => { + // Mock the post method to throw an error + postMock = jest.spyOn(enventController, 'post').mockImplementation(() => { + throw new Error('Test error'); + }); + }); + + afterEach(() => { + // Restore the original implementation + postMock.mockRestore(); + }); + test('should handle errors thrown by post method', async () => { + // Call the route handler + const response = await request(app).post('/event'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ message: 'Internal server error' }); }); }); diff --git a/application-templates/typescript/job/src/app.ts b/application-templates/typescript/job/src/app.ts new file mode 100644 index 0000000..ba8ea87 --- /dev/null +++ b/application-templates/typescript/job/src/app.ts @@ -0,0 +1,29 @@ +import * as dotenv from 'dotenv'; +dotenv.config(); + +import express, { Express } from 'express'; + +// Import routes +import JobRoutes from './routes/job.route'; + +import { readConfiguration } from './utils/config.utils'; +import { errorMiddleware } from './middleware/error.middleware'; +import CustomError from './errors/custom.error'; + +// Read env variables +readConfiguration(); + +// Create the express app +const app: Express = express(); +app.disable('x-powered-by'); + +// Define routes +app.use('/job', JobRoutes); +app.use('*', () => { + throw new CustomError(404, 'Path not found.'); +}); + +// Global error handler +app.use(errorMiddleware); + +export default app; diff --git a/application-templates/typescript/job/src/index.ts b/application-templates/typescript/job/src/index.ts index b401749..5be476b 100644 --- a/application-templates/typescript/job/src/index.ts +++ b/application-templates/typescript/job/src/index.ts @@ -1,32 +1,13 @@ import * as dotenv from 'dotenv'; dotenv.config(); -import express, { Express } from 'express'; - -// Import routes -import JobRoutes from './routes/job.route'; - // Import logger import { logger } from './utils/logger.utils'; -import { readConfiguration } from './utils/config.utils'; -import { errorMiddleware } from './middleware/error.middleware'; - -// Read env variables -readConfiguration(); +import app from './app'; const PORT = 8080; -// Create the express app -const app: Express = express(); -app.disable('x-powered-by'); - -// Define routes -app.use('/job', JobRoutes); - -// Global error handler -app.use(errorMiddleware); - // Listen the application const server = app.listen(PORT, () => { logger.info(`⚡️ Job application listening on port ${PORT}`); diff --git a/application-templates/typescript/job/src/middleware/error.middleware.ts b/application-templates/typescript/job/src/middleware/error.middleware.ts index c76bfc3..8b1e6ba 100644 --- a/application-templates/typescript/job/src/middleware/error.middleware.ts +++ b/application-templates/typescript/job/src/middleware/error.middleware.ts @@ -1,10 +1,11 @@ -import { ErrorRequestHandler, Request, Response } from 'express'; +import { ErrorRequestHandler, NextFunction, Request, Response } from 'express'; import CustomError from '../errors/custom.error'; export const errorMiddleware: ErrorRequestHandler = ( error: Error, _: Request, - res: Response + res: Response, + _next: NextFunction ) => { const isDevelopment = process.env.NODE_ENV === 'development'; @@ -18,5 +19,11 @@ export const errorMiddleware: ErrorRequestHandler = ( return; } - res.status(500).send(isDevelopment ? error : 'Internal server error'); + res + .status(500) + .send( + isDevelopment + ? { messge: error.message } + : { message: 'Internal server error' } + ); }; diff --git a/application-templates/typescript/job/src/routes/job.route.ts b/application-templates/typescript/job/src/routes/job.route.ts index 858d47f..5ac702a 100644 --- a/application-templates/typescript/job/src/routes/job.route.ts +++ b/application-templates/typescript/job/src/routes/job.route.ts @@ -5,9 +5,9 @@ import { post } from '../controllers/job.controller'; // Create the router for our app const jobRouter: Router = Router(); -jobRouter.post('/', (req, res, next) => { +jobRouter.post('/', async (req, res, next) => { try { - post(req, res); + await post(req, res); } catch (error) { next(error); } diff --git a/application-templates/typescript/job/tests/routes.spec.ts b/application-templates/typescript/job/tests/routes.spec.ts index f1fdf7f..22f33e9 100644 --- a/application-templates/typescript/job/tests/routes.spec.ts +++ b/application-templates/typescript/job/tests/routes.spec.ts @@ -1,7 +1,35 @@ -import { describe, expect, test } from '@jest/globals'; +import { expect } from '@jest/globals'; +import request from 'supertest'; +import app from '../src/app'; +import * as jobController from '../src/controllers/job.controller'; -describe('Testing Job', () => { - test('Mock Job testing', async () => { - expect(1).toBe(1); +describe('Testing router', () => { + test('Post to non existing route', async () => { + const response = await request(app).post('/none'); + expect(response.status).toBe(404); + expect(response.body).toEqual({ + message: 'Path not found.', + }); + }); +}); +describe('unexpected error', () => { + let postMock: jest.SpyInstance; + + beforeEach(() => { + // Mock the post method to throw an error + postMock = jest.spyOn(jobController, 'post').mockImplementation(() => { + throw new Error('Test error'); + }); + }); + + afterEach(() => { + // Restore the original implementation + postMock.mockRestore(); + }); + test('should handle errors thrown by post method', async () => { + // Call the route handler + const response = await request(app).post('/job'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ message: 'Internal server error' }); }); }); diff --git a/application-templates/typescript/service/.eslintrc.cjs b/application-templates/typescript/service/.eslintrc.cjs index 8c19aef..bb6a70d 100644 --- a/application-templates/typescript/service/.eslintrc.cjs +++ b/application-templates/typescript/service/.eslintrc.cjs @@ -7,7 +7,7 @@ module.exports = { plugins: ['@typescript-eslint'], extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], rules: { - '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 'no-undef': 'error', 'no-console': 'error', 'no-const-assign': 'error', diff --git a/application-templates/typescript/service/src/app.ts b/application-templates/typescript/service/src/app.ts new file mode 100644 index 0000000..d428fe2 --- /dev/null +++ b/application-templates/typescript/service/src/app.ts @@ -0,0 +1,33 @@ +import * as dotenv from 'dotenv'; +dotenv.config(); + +import express, { Express } from 'express'; +import bodyParser from 'body-parser'; + +// Import routes +import ServiceRoutes from './routes/service.route'; + +import { readConfiguration } from './utils/config.utils'; +import { errorMiddleware } from './middleware/error.middleware'; +import CustomError from './errors/custom.error'; + +// Read env variables +readConfiguration(); + +// Create the express app +const app: Express = express(); +app.disable('x-powered-by'); + +// Define configurations +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +// Define routes +app.use('/service', ServiceRoutes); +app.use('*', () => { + throw new CustomError(404, 'Path not found.'); +}); +// Global error handler +app.use(errorMiddleware); + +export default app; diff --git a/application-templates/typescript/service/src/index.ts b/application-templates/typescript/service/src/index.ts index 6c78fa6..5f50297 100644 --- a/application-templates/typescript/service/src/index.ts +++ b/application-templates/typescript/service/src/index.ts @@ -1,37 +1,13 @@ import * as dotenv from 'dotenv'; dotenv.config(); -import express, { Express } from 'express'; -import bodyParser from 'body-parser'; - -// Import routes -import ServiceRoutes from './routes/service.route'; - // Import logger import { logger } from './utils/logger.utils'; -import { readConfiguration } from './utils/config.utils'; -import { errorMiddleware } from './middleware/error.middleware'; - -// Read env variables -readConfiguration(); +import app from './app'; const PORT = 8080; -// Create the express app -const app: Express = express(); -app.disable('x-powered-by'); - -// Define configurations -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); - -// Define routes -app.use('/service', ServiceRoutes); - -// Global error handler -app.use(errorMiddleware); - // Listen the application const server = app.listen(PORT, () => { logger.info(`⚡️ Service application listening on port ${PORT}`); diff --git a/application-templates/typescript/service/src/middleware/error.middleware.ts b/application-templates/typescript/service/src/middleware/error.middleware.ts index c76bfc3..8b1e6ba 100644 --- a/application-templates/typescript/service/src/middleware/error.middleware.ts +++ b/application-templates/typescript/service/src/middleware/error.middleware.ts @@ -1,10 +1,11 @@ -import { ErrorRequestHandler, Request, Response } from 'express'; +import { ErrorRequestHandler, NextFunction, Request, Response } from 'express'; import CustomError from '../errors/custom.error'; export const errorMiddleware: ErrorRequestHandler = ( error: Error, _: Request, - res: Response + res: Response, + _next: NextFunction ) => { const isDevelopment = process.env.NODE_ENV === 'development'; @@ -18,5 +19,11 @@ export const errorMiddleware: ErrorRequestHandler = ( return; } - res.status(500).send(isDevelopment ? error : 'Internal server error'); + res + .status(500) + .send( + isDevelopment + ? { messge: error.message } + : { message: 'Internal server error' } + ); }; diff --git a/application-templates/typescript/service/src/routes/service.route.ts b/application-templates/typescript/service/src/routes/service.route.ts index fb5e663..c9391cb 100644 --- a/application-templates/typescript/service/src/routes/service.route.ts +++ b/application-templates/typescript/service/src/routes/service.route.ts @@ -4,11 +4,11 @@ import { post } from '../controllers/service.controller'; const serviceRouter = Router(); -serviceRouter.post('/', (req, res, next) => { +serviceRouter.post('/', async (req, res, next) => { logger.info('Service post message received'); try { - post(req, res); + await post(req, res); } catch (error) { next(error); } diff --git a/application-templates/typescript/service/tests/service.spec.ts b/application-templates/typescript/service/tests/service.spec.ts index 3d9d8f1..6157328 100644 --- a/application-templates/typescript/service/tests/service.spec.ts +++ b/application-templates/typescript/service/tests/service.spec.ts @@ -1,7 +1,51 @@ -import { describe, expect, test } from '@jest/globals'; +import { expect } from '@jest/globals'; +import request from 'supertest'; +import app from '../src/app'; +import * as serviceController from '../src/controllers/service.controller'; -describe('Testing Cart Controller', () => { - test('POST `/service` route', async () => { - expect(1).toBe(1); +describe('Testing router', () => { + test('Post to non existing route', async () => { + const response = await request(app).post('/none'); + expect(response.status).toBe(404); + expect(response.body).toEqual({ + message: 'Path not found.', + }); + }); + test('Post invalid body', async () => { + const response = await request(app).post('/service').send({ + message: 'hello world', + }); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request - Missing body parameters.', + }); + }); + test('Post empty body', async () => { + const response = await request(app).post('/service'); + expect(response.status).toBe(400); + expect(response.body).toEqual({ + message: 'Bad request - Missing body parameters.', + }); + }); +}); +describe('unexpected error', () => { + let postMock: jest.SpyInstance; + + beforeEach(() => { + // Mock the post method to throw an error + postMock = jest.spyOn(serviceController, 'post').mockImplementation(() => { + throw new Error('Test error'); + }); + }); + + afterEach(() => { + // Restore the original implementation + postMock.mockRestore(); + }); + test('should handle errors thrown by post method', async () => { + // Call the route handler + const response = await request(app).post('/service'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ message: 'Internal server error' }); }); }); diff --git a/package.json b/package.json index a008da4..2e5bc0b 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@tsconfig/node16": "^1.0.3", "@tsconfig/recommended": "^1.0.3", "@types/node": "^18.7.16", + "@types/supertest": "^6.0.2", "@typescript-eslint/eslint-plugin": "^5.36.2", "@typescript-eslint/parser": "^5.36.2", "eslint": "^8.46.0", @@ -48,6 +49,7 @@ "jest": "^29.6.2", "prettier": "^3.0.1", "rimraf": "^5.0.1", + "supertest": "^7.0.0", "typescript": "^5.1.6" }, "dependencies": {