Skip to content

Commit

Permalink
ch: Setup CI workflow for testing, coverage reporting, building and l…
Browse files Browse the repository at this point in the history
…inting
  • Loading branch information
aimedivin committed Apr 27, 2024
1 parent c4904a3 commit 1d2a3e8
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 79 deletions.
45 changes: 29 additions & 16 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,45 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
plugins: ['@typescript-eslint', 'jest'],
env: {
'jest/globals': true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:jest/recommended',
],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
"@typescript-eslint/no-unused-vars": [
"warn",
'@typescript-eslint/no-unused-vars': [
'warn',
{
"args": "all",
"argsIgnorePattern": "^_",
"caughtErrors": "all",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
'no-undef': 'warn',
'semi': ['warn', 'always'],
'no-multi-spaces': 'warn',
'no-trailing-spaces': 'warn',
'space-before-function-paren': ['warn', 'always'],
'func-style': ['warn', 'declaration', { 'allowArrowFunctions': true }],
'func-style': ['warn', 'declaration', { allowArrowFunctions: true }],
'camelcase': 'warn',
'@typescript-eslint/explicit-function-return-type': ['warn', { allowExpressions: true }],
'@typescript-eslint/explicit-member-accessibility': ['warn', { accessibility: 'explicit' }],
'@typescript-eslint/explicit-function-return-type': [
'warn',
{ allowExpressions: true },
],
'@typescript-eslint/explicit-member-accessibility': [
'warn',
{ accessibility: 'explicit' },
],
'no-unused-vars': 'warn',
'no-extra-semi': 'warn',
},
};
};
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: knights-ecomm-be CI

on: [push, pull_request]

jobs:
build-lint-test-coverage:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Install dependencies
run: npm install

- name: Build project
run: npm run build --if-present

- name: Run tests
run: npm test

- name: Upload coverage report to Coveralls
uses: coverallsapp/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ functionalities for the frontend, such as storing, retrieving, deleting data and
List of endpoints exposed by the service

## Setup

- to use loggers in program use below functions

```bash
logger.error('This is an error message');
logger.warn('This is a warning message');
Expand Down
32 changes: 16 additions & 16 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
export default {
preset: "ts-jest",
testEnvironment: "node",
testMatch: ["**/**/*.test.ts"],
verbose: true,
forceExit: true,
clearMocks: true,
resetMocks: true,
restoreMocks: true,
collectCoverageFrom: [
"src/**/*.{ts,tsx}", // Include all JavaScript/JSX files in the src directory
],
coveragePathIgnorePatterns: [
"/node_modules/", // Exclude the node_modules directory
"/__tests__/", // Exclude the tests directory
],
};
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/**/*.test.ts'],
verbose: true,
forceExit: true,
clearMocks: true,
resetMocks: true,
restoreMocks: true,
collectCoverageFrom: [
'src/**/*.{ts,tsx}', // Include all JavaScript/JSX files in the src directory
],
coveragePathIgnorePatterns: [
'/node_modules/', // Exclude the node_modules directory
'/__tests__/', // Exclude the tests directory
],
};
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@
"@types/jest": "^29.5.12",
"@types/jsend": "^1.0.32",
"@types/morgan": "^1.9.9",
"@types/supertest": "^6.0.2",
"@types/winston": "^2.4.4",
"@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-custom-plugin": "^1.0.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-jest": "^28.3.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"prettier": "^3.2.5",
Expand Down
12 changes: 5 additions & 7 deletions src/__test__/route.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import request from 'supertest';
import {app, server} from '../index'; // update this with the path to your app file
import { app, server } from '../index'; // update this with the path to your app file

describe('GET /', () => {
afterAll(done => {
server.close(done);
});
afterAll(done => {
server.close(done);
});

it('responds with "Knights Ecommerce API"', done => {
request(app)
.get('/')
.expect(200, 'Knights Ecommerce API', done);
request(app).get('/').expect(200, 'Knights Ecommerce API', done);
});
});
36 changes: 18 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
import express, { Request, Response } from "express";
import cors from "cors";
import dotenv from "dotenv";
import router from "./routes";
import { addDocumentation } from "./startups/docs";
import express, { Request, Response } from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import router from './routes';
import { addDocumentation } from './startups/docs';

import {CustomError,errorHandler} from "./middlewares/errorHandler";
import { CustomError, errorHandler } from './middlewares/errorHandler';
import morgan from 'morgan';
dotenv.config();

export const app = express();
const port = process.env.PORT as string;
app.use(express.json());

app.use(cors({ origin: "*" }));
app.use(cors({ origin: '*' }));

app.all('*', (req: Request,res: Response,next) =>{
const error = new CustomError(`Can't find ${req.originalUrl} on the server!`,404);
error.status = 'fail';
next(error);
app.get('/', (req: Request, res: Response) => {
res.send('Knights Ecommerce API');
});

addDocumentation(app);
app.get("/api/v1", (req: Request, res: Response) => {
res.send("Knights Ecommerce API");
app.all('*', (req: Request, res: Response, next) => {
const error = new CustomError(`Can't find ${req.originalUrl} on the server!`, 404);
error.status = 'fail';
next(error);
});

addDocumentation(app);

app.use(router);
app.use(errorHandler);

//morgan
const morganFormat = ':method :url :status :response-time ms - :res[content-length]';
app.use(morgan(morganFormat));



app.listen(port, () => {
console.log(`[server]: Server is running at http://localhost:${port}`);
export const server = app.listen(port, () => {
console.log(`[server]: Server is running at http://localhost:${port}`);
});
37 changes: 16 additions & 21 deletions src/middlewares/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import { Request, Response } from 'express';

class CustomError extends Error {
statusCode: number;
status: string;
statusCode: number;
status: string;

constructor (message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
Error.captureStackTrace(this, this.constructor);
}
constructor (message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
Error.captureStackTrace(this, this.constructor);
}
}

const errorHandler = (
err: CustomError,
req: Request,
res: Response,

) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
res.status(err.statusCode).json({
status: err.statusCode,
message: err.message
});
console.error(err.stack);
const errorHandler = (err: CustomError, req: Request, res: Response) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
res.status(err.statusCode).json({
status: err.statusCode,
message: err.message,
});
console.error(err.stack);
};

export { CustomError, errorHandler };
5 changes: 4 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
"types": ["node"] /* Specify type package names to be included without being referenced in a source file. */,
"types": [
"node",
"jest"
] /* Specify type package names to be included without being referenced in a source file. */,
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
Expand Down

0 comments on commit 1d2a3e8

Please sign in to comment.