/** * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ import { describe, expect, it } from "vitest"; import config from "../src/index.ts"; import { commentsRules } from "../src/rules/comments.ts"; import { deprecationRules } from "../src/rules/deprecation.ts"; import { eslintRules } from "../src/rules/eslint.ts"; import { importRules } from "../src/rules/import.ts"; import { jsdocRules } from "../src/rules/jsdoc.ts"; import { playwrightRules } from "../src/rules/playwright.ts"; import { reactRules } from "../src/rules/react.ts"; import { sortKeysFixRules } from "../src/rules/sortKeysFix.ts"; import { stylisticRules } from "../src/rules/stylistic.ts"; import { typescriptEslintRules, typescriptEslintRulesWithTypes, } from "../src/rules/typescriptEslint.ts"; import { unicornRules } from "../src/rules/unicorn.ts"; import { vitestRules } from "../src/rules/vitest.ts"; import type { Linter } from "eslint"; // #region Custom matcher expect.extend({ toContainRules(received, expected) { const missingRules: Array = []; const mismatchedRules: Array = []; for (const [ key, value ] of Object.entries(expected)) { if (!(key in received)) { missingRules.push(key); } else if (!this.equals(received[key], value)) { mismatchedRules.push(key); } } const pass = missingRules.length === 0 && mismatchedRules.length === 0; let message = ""; // eslint-disable-next-line no-negated-condition -- This is a test. if (!pass) { message = `${message}Expected rules to contain all specified rules.\n`; if (missingRules.length > 0) { message = `${message}Missing rules: ${missingRules.join(", ")}\n`; } if (mismatchedRules.length > 0) { message = `${message}Mismatched rules: ${mismatchedRules.join(", ")}\n`; } } else { message = "Expected rules not to contain all specified rules"; } return { message: (): string => { return message; }, pass: pass, }; }, }); // #endregion // #region Helper function const baseProperties = ( ruleset: Linter.Config, isNoTypes: boolean, ): void => { expect(ruleset?.plugins, "missing @typescript-eslint plugin").toHaveProperty( "@typescript-eslint", ); // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- This is a test. isNoTypes ? expect( ruleset?.plugins, "should not have deprecation plugin", ).not.toHaveProperty("deprecation") : expect(ruleset?.plugins, "missing deprecation plugin").toHaveProperty( "deprecation", ); expect(ruleset?.plugins, "missing import plugin").toHaveProperty("import"); expect(ruleset?.plugins, "missing jsdoc plugin").toHaveProperty("jsdoc"); expect(ruleset?.plugins, "missing sort-keys-fix plugin").toHaveProperty( "sort-keys-fix", ); expect(ruleset?.plugins, "missing stylistic plugin").toHaveProperty( "stylistic", ); expect(ruleset?.plugins, "missing unicorn plugin").toHaveProperty("unicorn"); expect(ruleset?.rules, "missing eslint rules").toContainRules(eslintRules); expect(ruleset?.rules, "missing typescript-eslint rules").toContainRules( typescriptEslintRules, ); // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- This is a test. isNoTypes ? expect( ruleset?.rules, "should not have deprecation rules", ).not.toContainRules(deprecationRules) : expect(ruleset?.rules, "missing deprecation rules").toContainRules( deprecationRules, ); expect(ruleset?.rules, "missing import rules").toContainRules(importRules); expect(ruleset?.rules, "missing jsdoc rules").toContainRules(jsdocRules); expect(ruleset?.rules, "missing sort-keys-fix rules").toContainRules( sortKeysFixRules, ); expect(ruleset?.rules, "missing stylistic rules").toContainRules( stylisticRules, ); expect(ruleset?.rules, "missing unicorn rules").toContainRules(unicornRules); // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- This is a test. isNoTypes ? expect( ruleset?.rules, "should not have typescript-eslint rules with types", ).not.toContainRules(typescriptEslintRulesWithTypes) : expect( ruleset?.rules, "missing typescript-eslint rules with types", ).toContainRules(typescriptEslintRulesWithTypes); expect(ruleset?.rules, "missing comment rules").toContainRules(commentsRules); }; // #endregion describe("global config", () => { // #region Typescript it("should apply the expected plugins for typescript", () => { expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("src/**/*.ts"); }); expect(ruleset, "ruleset is not defined").toBeDefined(); expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined(); expect( ruleset?.plugins, "should not have vitest plugin", ).not.toHaveProperty("vitest"); expect( ruleset?.plugins, "should not have playwright plugin", ).not.toHaveProperty("playwright"); expect(ruleset?.plugins, "should not have react plugin").not.toHaveProperty( "react", ); expect(ruleset?.rules, "ruleset does not have rules").toBeDefined(); expect(ruleset?.rules, "should not have vitest rules").not.toContainRules( vitestRules, ); expect( ruleset?.rules, "should not have playwright rules", ).not.toContainRules(playwrightRules); expect(ruleset?.rules, "should not have react rules").not.toContainRules( reactRules, ); baseProperties(ruleset as Linter.Config, false); expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", ).toHaveLength(8); }); // #endregion // #region Vitest it("should apply the expected plugins for vitest files", () => { expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("test/**/*.spec.ts"); }); expect(ruleset, "ruleset is not defined").toBeDefined(); expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined(); expect(ruleset?.plugins, "missing vitest plugin").toHaveProperty("vitest"); expect( ruleset?.plugins, "should not have playwright plugin", ).not.toHaveProperty("playwright"); expect(ruleset?.plugins, "should not have react plugin").not.toHaveProperty( "react", ); expect(ruleset?.rules, "ruleset does not have rules").toBeDefined(); expect(ruleset?.rules, "missing vitest rules").toContainRules(vitestRules); expect( ruleset?.rules, "should not have playwright rules", ).not.toContainRules(playwrightRules); expect(ruleset?.rules, "should not have react rules").not.toContainRules( reactRules, ); baseProperties(ruleset as Linter.Config, true); expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", ).toHaveLength(8); }); // #endregion // #region Playwright it("should apply the expected plugins for playwright", () => { expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("e2e/**/*.spec.ts"); }); expect(ruleset, "ruleset is not defined").toBeDefined(); expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined(); expect( ruleset?.plugins, "should not have vitest plugin", ).not.toHaveProperty("vitest"); expect(ruleset?.plugins, "missing playwright plugin").toHaveProperty( "playwright", ); expect(ruleset?.plugins, "should not have react plugin").not.toHaveProperty( "react", ); expect(ruleset?.rules, "ruleset does not have rules").toBeDefined(); expect(ruleset?.rules, "should not have vitest rules").not.toContainRules( vitestRules, ); expect(ruleset?.rules, "missing playwright rules").toContainRules( playwrightRules, ); expect(ruleset?.rules, "should not have react rules").not.toContainRules( reactRules, ); baseProperties(ruleset as Linter.Config, true); expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", ).toHaveLength(8); }); // #endregion // #region React it("should apply the expected plugins for react", () => { expect.assertions(27); const ruleset = config.find((rule) => { return rule?.files?.includes("src/**/*.tsx"); }); expect(ruleset, "ruleset is not defined").toBeDefined(); expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined(); expect( ruleset?.plugins, "should not have vitest plugin", ).not.toHaveProperty("vitest"); expect( ruleset?.plugins, "should not have playwright plugin", ).not.toHaveProperty("playwright"); expect(ruleset?.plugins, "missing react plugin").toHaveProperty("react"); expect(ruleset?.rules, "ruleset does not have rules").toBeDefined(); expect(ruleset?.rules, "should not have vitest rules").not.toContainRules( vitestRules, ); expect( ruleset?.rules, "should not have playwright rules", ).not.toContainRules(playwrightRules); expect(ruleset?.rules, "missing react rules").toContainRules(reactRules); baseProperties(ruleset as Linter.Config, false); expect( Object.keys(ruleset?.plugins ?? {}), "should not have extraneous plugins", ).toHaveLength(9); }); // #endregion });