Repository: azat-io/eslint-plugin-perfectionist
Pull request #541 (2025-05-05 20:00:30)

test: add additional JSON schema tests
### Description

This PR does the following:
- Adds tests for `common-json-schemas`.
- Strengthen a few JSON schemas by enforcing the following properties:
  - Forbid `fallbackSort: {}`.
  - Forbid `{}` objects inside `groups`.
  - Forbid `{}` in `{ pattern: string; flags?: string }` RegExp objects.
  - Forbid `partitionByComment: {}`.
  - Enforce `groupName` in `customGroups` array objects.

### What is the purpose of this pull request?

- [x] Other

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/pull/541?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`28d2170`)](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/commit/28d2170ae3eca413ab57c87feaf4d4a18689ab3d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.) to head [(`338c308`)](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/commit/338c308e46ec52e24996176791f54997be4b97ce?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.).
> Report is 1 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##              main      #541   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           99        99           
  Lines         8020      8032   +12     
  Branches      1621      1624    +3     
=========================================
+ Hits          8020      8032   +12     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/pull/541?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>

Patch:
diff --git a/utils/common-json-schemas.ts b/utils/common-json-schemas.ts
index fa2967d..9e101b7 100644
--- a/utils/common-json-schemas.ts
+++ b/utils/common-json-schemas.ts
@@ -58,6 +58,7 @@ let buildFallbackSortJsonSchema = ({
   },
   description: 'Fallback sort order.',
   additionalProperties: false,
+  minProperties: 1,
   type: 'object',
 })
 
@@ -102,6 +103,7 @@ export let groupsJsonSchema: JSONSchema4 = {
         properties: {
           newlinesBetween: newlinesBetweenJsonSchema,
         },
+        required: ['newlinesBetween'],
         additionalProperties: false,
         type: 'object',
       },
@@ -143,6 +145,7 @@ let singleRegexJsonSchema: JSONSchema4 = {
         },
       },
       additionalProperties: false,
+      required: ['pattern'],
       // https://github.com/azat-io/eslint-plugin-perfectionist/pull/490#issuecomment-2720969705
       // Uncomment the code below in the next major version (v5)
       // To uncomment: required: ['pattern'],
@@ -187,6 +190,7 @@ export let partitionByCommentJsonSchema: JSONSchema4 = {
         },
       },
       additionalProperties: false,
+      minProperties: 1,
       type: 'object',
     },
   ],
@@ -265,6 +269,7 @@ export let buildCustomGroupsArrayJsonSchema = ({
         },
         description: 'Custom group block.',
         additionalProperties: false,
+        required: ['groupName'],
         type: 'object',
       },
       {
@@ -276,6 +281,7 @@ export let buildCustomGroupsArrayJsonSchema = ({
         },
         description: 'Custom group.',
         additionalProperties: false,
+        required: ['groupName'],
         type: 'object',
       },
     ],


Test patch:
diff --git a/test/utils/common-json-schemas.test.ts b/test/utils/common-json-schemas.test.ts
new file mode 100644
index 0000000..f69b468
--- /dev/null
+++ b/test/utils/common-json-schemas.test.ts
@@ -0,0 +1,327 @@
+import { describe, expect, it } from 'vitest'
+import Ajv from 'ajv-draft-04'
+
+import {
+  buildCustomGroupsArrayJsonSchema,
+  partitionByCommentJsonSchema,
+  newlinesBetweenJsonSchema,
+  commonJsonSchemas,
+  groupsJsonSchema,
+  regexJsonSchema,
+} from '../../utils/common-json-schemas'
+
+describe('common-json-schemas', () => {
+  describe('commonJsonSchemas', () => {
+    let commonJsonSchemaValidator = new Ajv().compile({
+      properties: commonJsonSchemas,
+      additionalProperties: false,
+      type: 'object',
+    })
+
+    describe('type', () => {
+      it.each(['alphabetical', 'natural', 'line-length', 'custom', 'unsorted'])(
+        "should allow' %s'",
+        type => {
+          expect(
+            commonJsonSchemaValidator({
+              type,
+            }),
+          ).toBeTruthy()
+        },
+      )
+
+      it('should not allow invalid values', () => {
+        expect(
+          commonJsonSchemaValidator({
+            type: 'invalid',
+          }),
+        ).toBeFalsy()
+      })
+    })
+
+    describe('order', () => {
+      it.each(['asc', 'desc'])("should allow' %s'", order => {
+        expect(
+          commonJsonSchemaValidator({
+            order,
+          }),
+        ).toBeTruthy()
+      })
+
+      it('should not allow invalid values', () => {
+        expect(
+          commonJsonSchemaValidator({
+            order: 'invalid',
+          }),
+        ).toBeFalsy()
+      })
+    })
+
+    describe('specialCharacters', () => {
+      it.each(['remove', 'trim', 'keep'])(
+        "should allow' %s'",
+        specialCharacters => {
+          expect(
+            commonJsonSchemaValidator({
+              specialCharacters,
+            }),
+          ).toBeTruthy()
+        },
+      )
+
+      it('should not allow invalid values', () => {
+        expect(
+          commonJsonSchemaValidator({
+            specialCharacters: 'invalid',
+          }),
+        ).toBeFalsy()
+      })
+    })
+
+    describe('fallbackSort', () => {
+      describe('type', () => {
+        it.each([
+          'alphabetical',
+          'natural',
+          'line-length',
+          'custom',
+          'unsorted',
+        ])("should allow' %s'", type => {
+          expect(
+            commonJsonSchemaValidator({
+              fallbackSort: {
+                type,
+              },
+            }),
+          ).toBeTruthy()
+        })
+
+        it('should not allow invalid values', () => {
+          expect(
+            commonJsonSchemaValidator({
+              fallbackSort: {
+                type: 'invalid',
+              },
+            }),
+          ).toBeFalsy()
+        })
+
+        it('should not allow the empty object', () => {
+          expect(
+            commonJsonSchemaValidator({
+              fallbackSort: {},
+            }),
+          ).toBeFalsy()
+        })
+      })
+
+      describe('order', () => {
+        it.each(['asc', 'desc'])("should allow' %s'", order => {
+          expect(
+            commonJsonSchemaValidator({
+              fallbackSort: {
+                order,
+              },
+            }),
+          ).toBeTruthy()
+        })
+
+        it('should not allow invalid values', () => {
+          expect(
+            commonJsonSchemaValidator({
+              fallbackSort: {
+                order: 'invalid',
+              },
+            }),
+          ).toBeFalsy()
+        })
+      })
+
+      it('should not allow additional properties', () => {
+        expect(
+          commonJsonSchemaValidator({
+            fallbackSort: {
+              somethingElse: 'something',
+            },
+          }),
+        ).toBeFalsy()
+      })
+    })
+  })
+
+  describe('newlinesBetween', () => {
+    let newlinesBetweenJsonSchemaValidator = new Ajv().compile(
+      newlinesBetweenJsonSchema,
+    )
+
+    it.each(['ignore', 'always', 'never'])(
+      "should allow' %s'",
+      newlinesBetween => {
+        expect(newlinesBetweenJsonSchemaValidator(newlinesBetween)).toBeTruthy()
+      },
+    )
+
+    it('should not allow invalid values', () => {
+      expect(newlinesBetweenJsonSchemaValidator('invalid')).toBeFalsy()
+    })
+  })
+
+  describe('groups', () => {
+    let groupsJsonSchemaValidator = new Ajv().compile(groupsJsonSchema)
+
+    it('should allow an array of strings', () => {
+      expect(groupsJsonSchemaValidator(['group1', 'group2'])).toBeTruthy()
+    })
+
+    it('should allow an array of arrays of strings', () => {
+      expect(
+        groupsJsonSchemaValidator([['group1', 'group2'], ['group3']]),
+      ).toBeTruthy()
+    })
+
+    describe('newlinesBetween', () => {
+      it.each(['ignore', 'always', 'never'])(
+        "should allow' %s'",
+        newlinesBetween => {
+          expect(
+            groupsJsonSchemaValidator([
+              'group1',
+              { newlinesBetween },
+              'group2',
+            ]),
+          ).toBeTruthy()
+        },
+      )
+
+      it('should not allow invalid values', () => {
+        expect(
+          groupsJsonSchemaValidator([
+            'group1',
+            { newlinesBetween: 'invalid' },
+            'group2',
+          ]),
+        ).toBeFalsy()
+      })
+
+      it('should not allow additional properties', () => {
+        expect(
+          groupsJsonSchemaValidator([
+            'group1',
+            { newlinesBetween: 'always', something: 'something' },
+            'group2',
+          ]),
+        ).toBeFalsy()
+      })
+    })
+
+    it('should not allow the empty object', () => {
+      expect(groupsJsonSchemaValidator(['group1', {}, 'group2'])).toBeFalsy()
+    })
+  })
+
+  describe('customGroups', () => {
+    let customGroupsJsonSchema = new Ajv().compile(
+      buildCustomGroupsArrayJsonSchema({
+        singleCustomGroupJsonSchema: {
+          customGroupProperty: { type: 'string' },
+        },
+      }),
+    )
+
+    it('should allow arrays of custom groups', () => {
+      expect(
+        customGroupsJsonSchema([
+          {
+            customGroupProperty: 'value',
+            groupName: 'group',
+          },
+        ]),
+      ).toBeTruthy()
+    })
+
+    it("should allow arrays of 'anyOf' custom groups", () => {
+      expect(
+        customGroupsJsonSchema([
+          {
+            anyOf: [
+              {
+                customGroupProperty: 'ss',
+              },
+            ],
+            groupName: 'group',
+          },
+        ]),
+      ).toBeTruthy()
+    })
+
+    it("should enforce 'groupName'", () => {
+      expect(
+        customGroupsJsonSchema([
+          {
+            customGroupProperty: 'value',
+          },
+        ]),
+      ).toBeFalsy()
+    })
+  })
+
+  describe('partitionByComment', () => {
+    let partitionByCommentJsonSchemaValidator = new Ajv().compile(
+      partitionByCommentJsonSchema,
+    )
+
+    it('should allow boolean values', () => {
+      expect(partitionByCommentJsonSchemaValidator(true)).toBeTruthy()
+    })
+
+    it.each([{ block: true }, { line: true }, { block: true, line: true }])(
+      "should allow '%s'",
+      partitionByComment => {
+        expect(
+          partitionByCommentJsonSchemaValidator(partitionByComment),
+        ).toBeTruthy()
+      },
+    )
+
+    it('should not allow the empty object', () => {
+      expect(partitionByCommentJsonSchemaValidator({})).toBeFalsy()
+    })
+  })
+
+  describe('regex', () => {
+    let regexJsonSchemaValidator = new Ajv().compile(regexJsonSchema)
+
+    it('should allow string values', () => {
+      expect(regexJsonSchemaValidator('some string')).toBeTruthy()
+    })
+
+    it.each([{ pattern: 'pattern' }, { pattern: 'pattern', flags: 'flags' }])(
+      "should allow '%s'",
+      regex => {
+        expect(regexJsonSchemaValidator(regex)).toBeTruthy()
+      },
+    )
+
+    it("should enforce 'pattern'", () => {
+      expect(
+        regexJsonSchemaValidator({
+          something: 'something',
+          pattern: 'pattern',
+        }),
+      ).toBeFalsy()
+    })
+
+    it('should not allow additional properties', () => {
+      expect(
+        regexJsonSchemaValidator({
+          something: 'something',
+          pattern: 'pattern',
+        }),
+      ).toBeFalsy()
+    })
+
+    it('should not allow the empty object', () => {
+      expect(regexJsonSchemaValidator({})).toBeFalsy()
+    })
+  })
+})