Skip to content

Commit

Permalink
Feat: Added Sonar lint
Browse files Browse the repository at this point in the history
  • Loading branch information
himanshu-wedensday committed May 9, 2024
1 parent 3c46cfb commit 84feba3
Show file tree
Hide file tree
Showing 17 changed files with 1,429 additions and 69 deletions.
12 changes: 9 additions & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ const prettierOptions = JSON.parse(fs.readFileSync(path.resolve(__dirname, '.pre

module.exports = {
parser: 'babel-eslint',
extends: ['prettier-standard'],
plugins: ['prettier'],
extends: [
'prettier-standard',
'plugin:prettier/recommended',
'plugin:sonarjs/recommended',
'plugin:security/recommended-legacy'
],
plugins: ['prettier', 'sonarjs', 'github', 'sonarjs'],
env: {
jest: true,
browser: true,
Expand Down Expand Up @@ -42,7 +47,8 @@ module.exports = {
'prefer-template': 2,
'require-yield': 0,
'prettier/prettier': ['error', prettierOptions],
'node/handle-callback-err': ['off']
'node/handle-callback-err': ['off'],
'max-lines-per-function': ['error', 300]
},
settings: {
'import/resolver': {
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Node Express GraphQL Template CI

on:
pull_request:
pull_request_target:
branches:
- develop
push:
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
"deep-map-keys": "^2.0.1",
"dotenv": "^10.0.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-fp": "^2.3.0",
"eslint-plugin-github": "4.10.1",
"eslint-plugin-security": "2.1.1",
"eslint-plugin-sonarjs": "^0.23.0",
"express": "^4.17.1",
"fs": "^0.0.1-security",
"graphql": "^16.6.0",
Expand Down
9 changes: 3 additions & 6 deletions server/daos/purchasedProducts.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ export const getEarliestCreatedDate = async () => {
const earliestPurchasedProduct = await db.purchasedProducts.findOne({
order: ['id']
});
const date = earliestPurchasedProduct.createdAt.toISOString().split('T')[0];
return date;
return earliestPurchasedProduct.createdAt.toISOString().split('T')[0];
};

export const getTotalByDate = async date => {
Expand All @@ -35,12 +34,10 @@ export const getTotalByDateForCategory = async (date, category) => {
return total || 0;
};

export const getCountByDate = async date => {
const total = await db.purchasedProducts.count({
export const getCountByDate = async date =>
await db.purchasedProducts.count({
where: { createdAt: { [Op.lt]: date.endOf('day').toISOString(), [Op.gt]: date.startOf('day').toISOString() } }
});
return total;
};

export const getCountByDateForCategory = async (date, category) => {
const total = await db.purchasedProducts.count({
Expand Down
5 changes: 1 addition & 4 deletions server/daos/tests/purchasedProducts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('purchasedProducts tests', () => {
const productId = 133;
const discount = 111;
const deliveryDate = '"2022-07-20T17:30:15+05:30"';
const mockDate = moment('2022-01-03');
const purchasedProduct = {
price,
productId,
Expand All @@ -43,7 +44,6 @@ describe('purchasedProducts tests', () => {
});
it('should return zero if there is no value present for the date', async () => {
jest.spyOn(db.purchasedProducts, 'sum').mockReturnValueOnce(NaN);
const mockDate = moment('2022-01-03');
const res = await getTotalByDate(mockDate);
expect(res).toEqual(0);
});
Expand All @@ -56,7 +56,6 @@ describe('purchasedProducts tests', () => {
});
it('should return zero if there is no value present for the date', async () => {
jest.spyOn(db.purchasedProducts, 'sum').mockReturnValueOnce(NaN);
const mockDate = moment('2022-01-03');
const res = await getTotalByDateForCategory(mockDate);
expect(res).toEqual(0);
});
Expand All @@ -70,7 +69,6 @@ describe('purchasedProducts tests', () => {
});
it('should return zero if there is no count present for the date', async () => {
db.purchasedProducts.count = jest.fn().mockImplementationOnce(() => 0);
const mockDate = moment('2022-01-03');
const res = await getCountByDate(mockDate);
expect(res).toEqual(0);
});
Expand All @@ -84,7 +82,6 @@ describe('purchasedProducts tests', () => {
});
it('should return zero if there is no count present for the date for the category', async () => {
db.purchasedProducts.count = jest.fn().mockImplementationOnce(() => NaN);
const mockDate = moment('2022-01-03');
const res = await getCountByDateForCategory(mockDate);
expect(res).toEqual(0);
});
Expand Down
3 changes: 1 addition & 2 deletions server/database/models/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ export function getAttributes(sequelize, DataTypes) {
}

export function model(sequelize, DataTypes) {
const users = sequelize.define('users', getAttributes(sequelize, DataTypes), {
return sequelize.define('users', getAttributes(sequelize, DataTypes), {
tableName: 'users',
paranoid: true,
timestamps: true
});
return users;
}
10 changes: 5 additions & 5 deletions server/gql/fields/args/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GraphQLInt, GraphQLNonNull } from 'graphql';

const description = 'Use with grapql-relay compliant queries';
export const customListArgs = {
limit: {
type: new GraphQLNonNull(GraphQLInt),
Expand All @@ -9,8 +9,8 @@ export const customListArgs = {
type: new GraphQLNonNull(GraphQLInt),
description: 'Use with offset to get paginated results with total'
},
before: { type: GraphQLInt, description: 'Use with grapql-relay compliant queries' },
after: { type: GraphQLInt, description: 'Use with grapql-relay compliant queries' },
first: { type: GraphQLInt, description: 'Use with grapql-relay compliant queries' },
last: { type: GraphQLInt, description: 'Use with grapql-relay compliant queries' }
before: { type: GraphQLInt, description },
after: { type: GraphQLInt, description },
first: { type: GraphQLInt, description },
last: { type: GraphQLInt, description }
};
8 changes: 6 additions & 2 deletions server/gql/models/aggregate/purchasedProductsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ export const handleAggregateQueries = (args, tableName) => {
let join = ``;
const addQuery = suffix => (tableName ? `${tableName}.` : '') + suffix;
if (args?.startDate) {
where = addWhereClause(where, `${addQuery(`created_at`)} > :startDate`);
const createdAtQuery = addQuery('created_at');
const whereClause = `${createdAtQuery} > :startDate`;
where = addWhereClause(where, whereClause);
}
if (args?.endDate) {
where = addWhereClause(where, `${addQuery(`created_at`)} < :endDate`);
const createdAtQuery = addQuery('created_at');
const whereClause = `${createdAtQuery} < :endDate`;
where = addWhereClause(where, whereClause);
}
if (args?.category) {
join = `LEFT JOIN products on products.id=purchased_products.product_id`;
Expand Down
11 changes: 4 additions & 7 deletions server/gql/models/aggregate/tests/purchasedProductsUtils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,10 @@ describe('queryOptions', () => {
});
it('should throw error and also send slack message if there is problem in parsing JSON', async () => {
jest.spyOn(redis, 'get').mockReturnValue('test');
const spy = jest.spyOn(utils, 'logger').mockImplementation(() => {
const obj = {
info: msg => msg,
error: err => err
};
return obj;
});
const spy = jest.spyOn(utils, 'logger').mockImplementation(() => ({
info: msg => msg,
error: err => err
}));
await queryRedis(type, args);
expect(spy).toBeCalledTimes(2);
});
Expand Down
7 changes: 4 additions & 3 deletions server/gql/models/tests/addresses/addresses.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,24 @@ const query = `
}
}
`;
const fieldType = 'data.__type.fields';
describe('Address introspection tests', () => {
it('should have the correct fields and types', async () => {
const result = await graphqlSync({ schema, source: query });
const addressFieldTypes = get(result, 'data.__type.fields');
const addressFieldTypes = get(result, fieldType);
const hasCorrectFieldTypes = expectSameTypeNameOrKind(addressFieldTypes, fields);
expect(hasCorrectFieldTypes).toBeTruthy();
});
it('should have a supplier connection', async () => {
const result = await graphqlSync({ schema, source: query });
const addressFieldTypes = get(result, 'data.__type.fields');
const addressFieldTypes = get(result, fieldType);
const supplierField = addressFieldTypes.find(field => field.name === 'suppliers');
expect(supplierField.type.kind).toBe('OBJECT');
expect(supplierField.type.name).toBe('suppliersConnection');
});
it('should have a store connection', async () => {
const result = await graphqlSync({ schema, source: query });
const addressFieldTypes = get(result, 'data.__type.fields');
const addressFieldTypes = get(result, fieldType);
const storeField = addressFieldTypes.find(field => field.name === 'stores');
expect(storeField.type.kind).toBe('OBJECT');
expect(storeField.type.name).toBe('storeConnection');
Expand Down
7 changes: 4 additions & 3 deletions server/gql/models/tests/products/products.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,24 @@ const query = `
}
}
`;
const fieldType = 'data.__type.fields';
describe('Product introspection tests', () => {
it('should have the correct fields and types', async () => {
const result = await graphqlSync({ schema, source: query });
const productFieldTypes = get(result, 'data.__type.fields');
const productFieldTypes = get(result, fieldType);
const hasCorrectFieldTypes = expectSameTypeNameOrKind(productFieldTypes, fields);
expect(hasCorrectFieldTypes).toBeTruthy();
});
it('should have a supplier connection', async () => {
const result = await graphqlSync({ schema, source: query });
const addressFieldTypes = get(result, 'data.__type.fields');
const addressFieldTypes = get(result, fieldType);
const supplierField = addressFieldTypes.find(field => field.name === 'suppliers');
expect(supplierField.type.kind).toBe('OBJECT');
expect(supplierField.type.name).toBe('suppliersConnection');
});
it('should have a store connection', async () => {
const result = await graphqlSync({ schema, source: query });
const addressFieldTypes = get(result, 'data.__type.fields');
const addressFieldTypes = get(result, fieldType);
const storeField = addressFieldTypes.find(field => field.name === 'stores');
expect(storeField.type.kind).toBe('OBJECT');
expect(storeField.type.name).toBe('storeConnection');
Expand Down
7 changes: 4 additions & 3 deletions server/gql/models/tests/storeProducts/storeProducts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,26 @@ const query = `
}
}
`;
const fieldType = 'data.__type.fields';
describe('Store Product introspection tests', () => {
it('should have the correct fields and types', async () => {
const result = await graphqlSync({ schema, source: query });
const storeProductFieldTypes = get(result, 'data.__type.fields');
const storeProductFieldTypes = get(result, fieldType);
const hasCorrectFieldTypes = expectSameTypeNameOrKind(storeProductFieldTypes, fields);
expect(hasCorrectFieldTypes).toBeTruthy();
});

it('should have a product field of type Product', async () => {
const result = await graphqlSync({ schema, source: query });
const purchasedProductFieldTypes = get(result, 'data.__type.fields');
const purchasedProductFieldTypes = get(result, fieldType);
const productField = purchasedProductFieldTypes.find(field => field.name === 'products');
expect(productField.type.name).toBe('productsConnection');
expect(productField.type.kind).toBe('OBJECT');
});

it('should have a store field of type Store', async () => {
const result = await graphqlSync({ schema, source: query });
const purchasedProductFieldTypes = get(result, 'data.__type.fields');
const purchasedProductFieldTypes = get(result, fieldType);
const productField = purchasedProductFieldTypes.find(field => field.name === 'stores');
expect(productField.type.name).toBe('storeConnection');
expect(productField.type.kind).toBe('OBJECT');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,26 @@ const query = `
}
}
`;
const fieldType = 'data.__type.fields';
describe('Supplier Product introspection tests', () => {
it('should have the correct fields and types', async () => {
const result = await graphqlSync({ schema, source: query });
const supplierProductFieldTypes = get(result, 'data.__type.fields');
const supplierProductFieldTypes = get(result, fieldType);
const hasCorrectFieldTypes = expectSameTypeNameOrKind(supplierProductFieldTypes, fields);
expect(hasCorrectFieldTypes).toBeTruthy();
});

it('should have a product field of type Product', async () => {
const result = await graphqlSync({ schema, source: query });
const purchasedProductFieldTypes = get(result, 'data.__type.fields');
const purchasedProductFieldTypes = get(result, fieldType);
const productField = purchasedProductFieldTypes.find(field => field.name === 'products');
expect(productField.type.name).toBe('productsConnection');
expect(productField.type.kind).toBe('OBJECT');
});

it('should have a supplier field of type Supplier', async () => {
const result = await graphqlSync({ schema, source: query });
const purchasedProductFieldTypes = get(result, 'data.__type.fields');
const purchasedProductFieldTypes = get(result, fieldType);
const supplierField = purchasedProductFieldTypes.find(field => field.name === 'suppliers');
expect(supplierField.type.name).toBe('suppliersConnection');
expect(supplierField.type.kind).toBe('OBJECT');
Expand Down
7 changes: 3 additions & 4 deletions server/middleware/gqlAuth/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable sonarjs/cognitive-complexity */
import { isLocalEnv, isTestEnv, logger } from '@utils';
import { convertToMap } from '@utils/gqlSchemaParsers';
import jwt from 'jsonwebtoken';
Expand Down Expand Up @@ -45,16 +46,14 @@ export const isPublicQuery = async req => {
return queries.every(({ queryName, operationType }) => GQL_QUERY_TYPES[operationType].whitelist.includes(queryName));
};

export const apolloServerContextResolver = async ({ req, res }) => {
const response = await new Promise((resolve, reject) => {
export const apolloServerContextResolver = async ({ req, res }) =>
await new Promise((resolve, reject) => {
isAuthenticated(req, res, () => {
resolve();
}).catch(err => {
reject(err);
});
});
return response;
};
export const isAuthenticated = async (req, res, next) => {
try {
// For accessing graphql without authentication when debugging.
Expand Down
Loading

0 comments on commit 84feba3

Please sign in to comment.