Skip to content

Commit

Permalink
feat: adding eslint rule for converting toBe(true) to toBeTrue() etc (#…
Browse files Browse the repository at this point in the history
…2911)

* feat: adding eslint rule for converting toBe(true) to toBeTrue() etc

* minor

* minor

* feat: prefer resolveTo and rejectWith instead of returnValue(Promise.resolve()) (#2912)

* feat: prefer resolveTo and rejectWith instead of returnValue(Promise.resolve())

* feat: added deepFreeze to not pollute global mock data (#2913)

* feat: added deepFreeze to not pollute global mock data

* feat: added deepFreeze to not pollute global mock data - Part 2 (#2914)

* feat: added deepFreeze to not pollute global mock data - Part 2

* feat: added deepFreeze to not pollute global mock data - Part 3 (#2915)

* feat: added deepFreeze to not pollute global mock data - Part 3

* feat: added deepFreeze to not pollute global mock data - Part 4 (#2916)

* feat: added deepFreeze to not pollute global mock data - Part 4

* feat: added deepFreeze to not pollute global mock data - Part 5 (#2917)

* feat: added deepFreeze to not pollute global mock data - Part 5

* feat: added deepFreeze to not pollute global mock data - Part 6 (#2918)

* feat: added deepFreeze to not pollute global mock data - Part 6

* feat: added deepFreeze to not pollute global mock data - Part 7 (#2919)

* feat: added deepFreeze to not pollute global mock data - Part 7

* minor

* feat: added deepFreeze to not pollute global mock data - Part 8 (#2922)

* feat: added deepFreeze to not pollute global mock data - Part 8

* feat: added deepFreeze to not pollute global mock data - Part 9 (#2924)

* feat: added deepFreeze to not pollute global mock data - Part 9

* feat: added deepFreeze to not pollute global mock data - Part 10 (#2925)

* feat: added deepFreeze to not pollute global mock data - Part 10

* feat: added deepFreeze to not pollute global mock data - Part 11 (#2927)

* feat: added deepFreeze to not pollute global mock data - Part 11

* feat: added deepFreeze to not pollute global mock data - Part 12 (#2929)

* feat: added deepFreeze to not pollute global mock data - Part 12

* feat: added deepFreeze to not pollute global mock data - Part 13 (#2930)

* feat: added deepFreeze to not pollute global mock data - Part 13

* minor

* feat: added deepFreeze to not pollute global mock data - Part 14 (#2933)

* feat: added deepFreeze to not pollute global mock data - Part 14

* feat: added deepFreeze to not pollute global mock data - Part 15 (#2934)

* feat: added deepFreeze to not pollute global mock data - Part 15

* test: fixing tests - part 1 (#2939)

* test: fixing tests - part 1

* test: fixing tests - part 2 (#2940)

* test: fixing tests - part 2

* test: fixing tests - part 3 (#2941)

* test: fixing tests - part 3

* test: fixing tests - part 4 (#2943)

* test: fixing tests - part 4

* test: fixing tests - part 5 (#2945)

* minor
  • Loading branch information
suyashpatil78 authored May 4, 2024
1 parent 630e384 commit ae37934
Show file tree
Hide file tree
Showing 263 changed files with 3,888 additions and 3,092 deletions.
42 changes: 38 additions & 4 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,47 @@
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
"plugin:@angular-eslint/ng-cli-compat"
],
"rules": {
"jsdoc/newline-after-description": "off",
"custom-rules/space-before-it-blocks": "error"
"@angular-eslint/component-class-suffix": "off",
"@typescript-eslint/naming-convention": "off",
"@angular-eslint/component-selector": "off",
"@angular-eslint/directive-selector": "off",
"indent": "off",
"semi": "off",
"no-underscore-dangle": "off",
"@angular-eslint/template/no-negated-async": "off",
"@typescript-eslint/prefer-for-of": "off",
"prefer-arrow/prefer-arrow-functions": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/consistent-type-assertions": "off",
"@angular-eslint/no-conflicting-lifecycle": "off",
"lines-between-class-members": "off",
"@typescript-eslint/no-shadow": "off",
"complexity": "off",
"max-depth": "off",
"max-params-no-constructor/max-params-no-constructor": "off",
"max-len": "off",
"space-before-function-paren": "off",
"@typescript-eslint/quotes": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-unnecessary-type-assertion": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-inferrable-types": "off",
"no-unused-expressions": "off",
"custom-rules/space-before-it-blocks": "error",
"custom-rules/prefer-jasmine-matchers": "error",
"custom-rules/prefer-resolve-to-reject-with": "error"
}
}
]
Expand Down
2 changes: 2 additions & 0 deletions eslint-custom-rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ module.exports = {
rules: {
'prefer-deep-freeze': require('./rules/eslint-plugin-prefer-deep-freeze'),
'space-before-it-blocks': require('./rules/eslint-plugin-space-before-it-blocks'),
'prefer-jasmine-matchers': require('./rules/eslint-plugin-prefer-jasmine-matchers'),
'prefer-resolve-to-reject-with': require('./rules/eslint-plugin-prefer-resolve-to-reject-with')
},
};
134 changes: 134 additions & 0 deletions eslint-custom-rules/rules/eslint-plugin-prefer-jasmine-matchers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Use toBeNull() instead of toBe(null) or toEqual(null)
// Use toBeUndefined() instead of toBe(undefined) or toEqual(undefined)
// Use toBeTrue() instead of toBe(true) or toEqual(true)
// Use toBeFalse() instead of toBe(false) or toEqual(false)
// Use toBeNaN() instead of toBe(NaN) or toEqual(NaN)

module.exports = {
meta: {
type: "suggestion",
docs: {
description: "Enforce using toBeTrue(), toBeFalse(), toBeNull(), and toBeUndefined() instead of toBe() or toEqual() with true, false, null, or undefined",
category: "Best Practices",
recommended: true,
},
fixable: "code",
schema: [],
},

create: function (context) {
return {
CallExpression(node) {
const isToBe = node.callee.property && node.callee.property.name === "toBe";
const isToEqual = node.callee.property && node.callee.property.name === "toEqual";

if ((isToBe || isToEqual) && node.arguments.length === 1) {
const argValue = node.arguments[0].value;
if (argValue === true) {
context.report({
node,
message: "Prefer using toBeTrue() instead of toBe(true) or toEqual(true)",
fix: function (fixer) {
const replacementText = 'toBeTrue()';
const sourceCode = context.getSourceCode();
const nodeText = sourceCode.getText(node);

// Find the correct part of the code to replace
const match = nodeText.match(/\.toBe\((true)\)|\.toEqual\((true)\)/);
if (match) {
const start = node.callee.property.range[0];
const end = node.callee.property.range[1] + 6; // Adjust end position
return fixer.replaceTextRange([start, end], replacementText);
}

return null; // No match found, no fix needed
}
});
} else if (argValue === false) {
context.report({
node,
message: "Prefer using toBeFalse() instead of toBe(false) or toEqual(false)",
fix: function (fixer) {
const replacementText = 'toBeFalse()';
const sourceCode = context.getSourceCode();
const nodeText = sourceCode.getText(node);

// Find the correct part of the code to replace
const match = nodeText.match(/\.toBe\((false)\)|\.toEqual\((false)\)/);
if (match) {
const start = node.callee.property.range[0];
const end = node.callee.property.range[1] + 7; // Adjust end position
return fixer.replaceTextRange([start, end], replacementText);
}

return null; // No match found, no fix needed
}
});
} else if (argValue === null) {
context.report({
node,
message: "Prefer using toBeNull() instead of toBe(null) or toEqual(null)",
fix: function (fixer) {
const replacementText = 'toBeNull()';
const sourceCode = context.getSourceCode();
const nodeText = sourceCode.getText(node);

// Find the correct part of the code to replace
const match = nodeText.match(/\.toBe\((null)\)|\.toEqual\((null)\)/);
if (match) {
const start = node.callee.property.range[0];
const end = node.callee.property.range[1] + 6; // Adjust end position
return fixer.replaceTextRange([start, end], replacementText);
}

return null; // No match found, no fix needed
}
});
} else if (argValue === undefined && node.arguments[0].name === 'undefined') {
// Comparing the name of the argument to undefined since every variable is undefined by default in AST
context.report({
node,
message: "Prefer using toBeUndefined() instead of toBe(undefined) or toEqual(undefined)",
fix: function (fixer) {
const replacementText = 'toBeUndefined()';
const sourceCode = context.getSourceCode();
const nodeText = sourceCode.getText(node);

// Find the correct part of the code to replace
const match = nodeText.match(/\.toBe\((undefined)\)|\.toEqual\((undefined)\)/);
if (match) {
const start = node.callee.property.range[0];
const end = node.callee.property.range[1] + 11; // Adjust end position
return fixer.replaceTextRange([start, end], replacementText);
}

return null; // No match found, no fix needed
}
});
} else if (node.arguments[0].name === 'NaN') {
// Since NaN === NaN returns false, we are comparing the name of the argument to NaN
context.report({
node,
message: "Prefer using toBeNaN() instead of toBe(NaN) or toEqual(NaN)",
fix: function (fixer) {
const replacementText = 'toBeNaN()';
const sourceCode = context.getSourceCode();
const nodeText = sourceCode.getText(node);

// Find the correct part of the code to replace
const match = nodeText.match(/\.toBe\((NaN)\)|\.toEqual\((NaN)\)/);
if (match) {
const start = node.callee.property.range[0];
const end = node.callee.property.range[1] + 5; // Adjust end position
return fixer.replaceTextRange([start, end], replacementText);
}

return null; // No match found, no fix needed
}
});
}
}
}
};
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const SpyStrategyCall = `CallExpression:matches(
[callee.object.property.name=and],
[callee.object.callee.property.name=withArgs]
)`.replace(/\s+/g, ' ');

const ReturnStrategy = `${SpyStrategyCall}[callee.property.name=returnValue]`;

// Matches Promise.{resolve,reject}(X)
const PromiseCall = 'CallExpression[callee.object.name=Promise]';
const SettledPromise = `${PromiseCall}[callee.property.name=/resolve|reject/]`;

module.exports = {
meta: {
type: 'suggestion',
docs: {
description: "Enforce using resolveTo() and rejectWith() instead of Promise.resolve() and Promise.reject() in Jasmine tests",
category: "Best Practices",
recommended: true,
},
fixable: 'code',
schema: []
},

create: context => ({
[`${ReturnStrategy} > ${SettledPromise}.arguments:first-child`] (promiseCall) {
const returnStrategyCall = promiseCall.parent;
const returnValueMethod = returnStrategyCall.callee.property;
const preferredMethod = promiseCall.callee.property.name === 'resolve'
? 'resolveTo' : 'rejectWith';

context.report({
message: `Prefer ${preferredMethod}`,
loc: {
start: returnValueMethod.loc.start,
end: returnStrategyCall.loc.end
},
fix (fixer) {
const code = context.getSourceCode();
return [
// Replace Promise constructor call with its arguments
fixer.remove(promiseCall.callee),
fixer.remove(code.getTokenAfter(promiseCall.callee)),
fixer.remove(code.getLastToken(promiseCall)),

// Replace returnValue method with resolveTo or rejectWith
fixer.replaceText(returnValueMethod, preferredMethod)
];
}
})
}
})
};
6 changes: 4 additions & 2 deletions src/app/core/mock-data/account-option.data.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import deepFreeze from 'deep-freeze-strict';

import { AccountOption } from '../models/account-option.model';
import { multiplePaymentModesData } from '../test-data/accounts.service.spec.data';

export const accountOptionData1: AccountOption[] = [
export const accountOptionData1: AccountOption[] = deepFreeze([
{
label: 'account1',
value: multiplePaymentModesData[0],
Expand All @@ -10,4 +12,4 @@ export const accountOptionData1: AccountOption[] = [
label: 'account2',
value: multiplePaymentModesData[1],
},
];
]);
10 changes: 6 additions & 4 deletions src/app/core/mock-data/acess-token-data.data.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import deepFreeze from 'deep-freeze-strict';

import { AccessTokenData } from '../models/access-token-data.model';

export const apiAccessTokenRes: AccessTokenData = {
export const apiAccessTokenRes: AccessTokenData = deepFreeze({
iat: 1678349549,
iss: 'FyleApp',
user_id: 'usvKA4X8Ugcr',
Expand All @@ -12,9 +14,9 @@ export const apiAccessTokenRes: AccessTokenData = {
version: '3',
cluster_domain: '"https://staging.fyle.tech"',
exp: 1678353149,
};
});

export const apiTokenWithoutRoles: AccessTokenData = {
export const apiTokenWithoutRoles: AccessTokenData = deepFreeze({
iat: 1678349549,
iss: 'FyleApp',
user_id: 'usvKA4X8Ugcr',
Expand All @@ -25,4 +27,4 @@ export const apiTokenWithoutRoles: AccessTokenData = {
version: '3',
cluster_domain: '"https://staging.fyle.tech"',
exp: 1678353149,
};
});
18 changes: 10 additions & 8 deletions src/app/core/mock-data/action-sheet-options.data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const actionSheetOptionsData = [
import deepFreeze from 'deep-freeze-strict';

export const actionSheetOptionsData = deepFreeze([
{
text: 'Split Expense By Category',
handler: () => {},
Expand All @@ -19,8 +21,8 @@ export const actionSheetOptionsData = [
text: 'Remove Card Expense',
handler: () => {},
},
];
export const expectedActionSheetButtonRes = [
]);
export const expectedActionSheetButtonRes = deepFreeze([
{
text: 'Capture Receipt',
icon: 'assets/svg/camera.svg',
Expand All @@ -45,9 +47,9 @@ export const expectedActionSheetButtonRes = [
cssClass: 'capture-receipt',
handler: undefined,
},
];
]);

export const expectedActionSheetButtonsWithMileage = [
export const expectedActionSheetButtonsWithMileage = deepFreeze([
{
text: 'Capture Receipt',
icon: 'assets/svg/camera.svg',
Expand All @@ -66,9 +68,9 @@ export const expectedActionSheetButtonsWithMileage = [
cssClass: 'capture-receipt',
handler: undefined,
},
];
]);

export const expectedActionSheetButtonsWithPerDiem = [
export const expectedActionSheetButtonsWithPerDiem = deepFreeze([
{
text: 'Capture Receipt',
icon: 'assets/svg/camera.svg',
Expand All @@ -87,4 +89,4 @@ export const expectedActionSheetButtonsWithPerDiem = [
cssClass: 'capture-receipt',
handler: undefined,
},
];
]);
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import deepFreeze from 'deep-freeze-strict';

import { AddEditAdvanceRequestFormValue } from '../models/add-edit-advance-request-form-value.model';
import { recentlyUsedProjectRes } from './recently-used.data';

export const addEditAdvanceRequestFormValueData: AddEditAdvanceRequestFormValue = {
export const addEditAdvanceRequestFormValueData: AddEditAdvanceRequestFormValue = deepFreeze({
currencyObj: {
amount: 130,
currency: 'USD',
Expand All @@ -12,17 +14,17 @@ export const addEditAdvanceRequestFormValueData: AddEditAdvanceRequestFormValue
notes: 'Test notes',
project: null,
customFieldValues: null,
};
});

export const addEditAdvanceRequestFormValueData2: AddEditAdvanceRequestFormValue = {
export const addEditAdvanceRequestFormValueData2: AddEditAdvanceRequestFormValue = deepFreeze({
currencyObj: null,
purpose: null,
notes: null,
project: null,
customFieldValues: [],
};
});

export const addEditAdvanceRequestFormValueData3: AddEditAdvanceRequestFormValue = {
export const addEditAdvanceRequestFormValueData3: AddEditAdvanceRequestFormValue = deepFreeze({
...addEditAdvanceRequestFormValueData,
project: recentlyUsedProjectRes[0],
};
});
6 changes: 4 additions & 2 deletions src/app/core/mock-data/advance-platform.data.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import deepFreeze from 'deep-freeze-strict';

import { CustomFieldTypes } from '../enums/platform/v1/custom-fields-type.enum';
import { AdvancesPlatform } from '../models/platform/advances-platform.model';
import { PlatformApiResponse } from '../models/platform/platform-api-response.model';

export const advancePlatform: PlatformApiResponse<AdvancesPlatform> = {
export const advancePlatform: PlatformApiResponse<AdvancesPlatform> = deepFreeze({
count: 1,
offset: 0,
data: [
Expand Down Expand Up @@ -85,4 +87,4 @@ export const advancePlatform: PlatformApiResponse<AdvancesPlatform> = {
},
},
],
};
});
Loading

0 comments on commit ae37934

Please sign in to comment.