generated from nhcarrigan/template
feat: add testing for the global configs
We want to make sure we aren't missing anything important.
This commit is contained in:
parent
2974c76c48
commit
70fcc1a49a
@ -8,7 +8,10 @@ export default [
|
|||||||
"import/no-default-export": "off",
|
"import/no-default-export": "off",
|
||||||
"import/namespace": "off",
|
"import/namespace": "off",
|
||||||
"import/no-deprecated": "off",
|
"import/no-deprecated": "off",
|
||||||
"@typescript-eslint/consistent-type-assertions": "off"
|
"@typescript-eslint/consistent-type-assertions": "off",
|
||||||
|
"max-lines-per-function": "off",
|
||||||
|
"complexity": "off",
|
||||||
|
"max-nested-callbacks": "off"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
109
src/index.ts
109
src/index.ts
@ -35,18 +35,15 @@ import { vitestRules } from "./rules/vitest.js";
|
|||||||
import type { ESLint, Linter } from "eslint";
|
import type { ESLint, Linter } from "eslint";
|
||||||
|
|
||||||
const config: Array<Linter.Config> = [
|
const config: Array<Linter.Config> = [
|
||||||
|
// #region Typescript Config
|
||||||
{
|
{
|
||||||
files: [ "src/**/*.ts" ],
|
files: [ "src/**/*.ts" ],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
globals: {
|
globals: {
|
||||||
...globals.node,
|
...globals.node,
|
||||||
...globals.browser,
|
|
||||||
},
|
},
|
||||||
parser: parser,
|
parser: parser,
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
ecmaVersion: 11,
|
ecmaVersion: 11,
|
||||||
project: true,
|
project: true,
|
||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
@ -60,15 +57,10 @@ const config: Array<Linter.Config> = [
|
|||||||
"deprecation": fixupPluginRules(deprecation),
|
"deprecation": fixupPluginRules(deprecation),
|
||||||
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
||||||
"jsdoc": jsdoc,
|
"jsdoc": jsdoc,
|
||||||
// @ts-expect-error I'm not sure what's going on here, to be honest.
|
|
||||||
"playwright": fixupPluginRules(playwright),
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- No typedef means it's unsafe...
|
|
||||||
"react": react,
|
|
||||||
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
||||||
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||||
"stylistic": fixupPluginRules(stylistic),
|
"stylistic": fixupPluginRules(stylistic),
|
||||||
"unicorn": unicorn,
|
"unicorn": unicorn,
|
||||||
"vitest": vitest,
|
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
...eslintRules,
|
...eslintRules,
|
||||||
@ -81,11 +73,11 @@ const config: Array<Linter.Config> = [
|
|||||||
...stylisticRules,
|
...stylisticRules,
|
||||||
...unicornRules,
|
...unicornRules,
|
||||||
...sortKeysFixRules,
|
...sortKeysFixRules,
|
||||||
...vitestRules,
|
|
||||||
...playwrightRules,
|
|
||||||
...reactRules,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Vitest Config
|
||||||
{
|
{
|
||||||
files: [ "test/**/*.spec.ts" ],
|
files: [ "test/**/*.spec.ts" ],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
@ -119,11 +111,94 @@ const config: Array<Linter.Config> = [
|
|||||||
...stylisticRules,
|
...stylisticRules,
|
||||||
...unicornRules,
|
...unicornRules,
|
||||||
...sortKeysFixRules,
|
...sortKeysFixRules,
|
||||||
// Overrides
|
},
|
||||||
"complexity": "off",
|
},
|
||||||
"import/no-extraneous-dependencies": "error",
|
// #endregion
|
||||||
"max-lines-per-function": "off",
|
|
||||||
"max-nested-callbacks": "off",
|
// #region Playwright Config
|
||||||
|
{
|
||||||
|
files: [ "e2e/**/*.spec.ts" ],
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
parser: parser,
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 11,
|
||||||
|
sourceType: "module",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
// @ts-expect-error It's a config. It's just not the narrow config. SMH.
|
||||||
|
"@typescript-eslint": tslint,
|
||||||
|
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
||||||
|
"jsdoc": jsdoc,
|
||||||
|
// @ts-expect-error I'm not actually sure what's going on here...
|
||||||
|
"playwright": playwright,
|
||||||
|
|
||||||
|
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
||||||
|
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||||
|
"stylistic": fixupPluginRules(stylistic),
|
||||||
|
"unicorn": unicorn,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
...eslintRules,
|
||||||
|
...disabledEslintRules,
|
||||||
|
...typescriptEslintRules,
|
||||||
|
...playwrightRules,
|
||||||
|
...importRules,
|
||||||
|
...jsdocRules,
|
||||||
|
...stylisticRules,
|
||||||
|
...unicornRules,
|
||||||
|
...sortKeysFixRules,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region React Config
|
||||||
|
{
|
||||||
|
files: [ "src/**/*.tsx" ],
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
},
|
||||||
|
parser: parser,
|
||||||
|
parserOptions: {
|
||||||
|
ecmaFeatures: {
|
||||||
|
jsx: true,
|
||||||
|
},
|
||||||
|
ecmaVersion: 11,
|
||||||
|
project: true,
|
||||||
|
sourceType: "module",
|
||||||
|
tsconfigRootDir: process.cwd(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
// @ts-expect-error It's a config. It's just not the narrow config. SMH.
|
||||||
|
"@typescript-eslint": tslint,
|
||||||
|
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||||
|
"deprecation": fixupPluginRules(deprecation),
|
||||||
|
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
||||||
|
"jsdoc": jsdoc,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- No typedef means it's unsafe...
|
||||||
|
"react": react,
|
||||||
|
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
||||||
|
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||||
|
"stylistic": fixupPluginRules(stylistic),
|
||||||
|
"unicorn": unicorn,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
...eslintRules,
|
||||||
|
...disabledEslintRules,
|
||||||
|
...typescriptEslintRules,
|
||||||
|
...typescriptEslintRulesWithTypes,
|
||||||
|
...importRules,
|
||||||
|
...jsdocRules,
|
||||||
|
...deprecationRules,
|
||||||
|
...stylisticRules,
|
||||||
|
...unicornRules,
|
||||||
|
...sortKeysFixRules,
|
||||||
|
...reactRules,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
268
test/config.spec.ts
Normal file
268
test/config.spec.ts
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import config from "../src/index.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<string> = [];
|
||||||
|
const mismatchedRules: Array<string> = [];
|
||||||
|
|
||||||
|
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
|
||||||
|
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<Linter.RulesRecord>,
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
describe("global config", () => {
|
||||||
|
// #region Typescript
|
||||||
|
it("should apply the expected plugins for typescript", () => {
|
||||||
|
expect.assertions(26);
|
||||||
|
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<Linter.RulesRecord>, false);
|
||||||
|
expect(
|
||||||
|
Object.keys(ruleset?.plugins ?? {}),
|
||||||
|
"should not have extraneous plugins",
|
||||||
|
).toHaveLength(7);
|
||||||
|
});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Vitest
|
||||||
|
it("should apply the expected plugins for vitest files", () => {
|
||||||
|
expect.assertions(26);
|
||||||
|
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<Linter.RulesRecord>, true);
|
||||||
|
expect(
|
||||||
|
Object.keys(ruleset?.plugins ?? {}),
|
||||||
|
"should not have extraneous plugins",
|
||||||
|
).toHaveLength(7);
|
||||||
|
});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Playwright
|
||||||
|
it("should apply the expected plugins for playwright", () => {
|
||||||
|
expect.assertions(26);
|
||||||
|
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<Linter.RulesRecord>, true);
|
||||||
|
expect(
|
||||||
|
Object.keys(ruleset?.plugins ?? {}),
|
||||||
|
"should not have extraneous plugins",
|
||||||
|
).toHaveLength(7);
|
||||||
|
});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region React
|
||||||
|
it("should apply the expected plugins for react", () => {
|
||||||
|
expect.assertions(26);
|
||||||
|
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<Linter.RulesRecord>, false);
|
||||||
|
expect(
|
||||||
|
Object.keys(ruleset?.plugins ?? {}),
|
||||||
|
"should not have extraneous plugins",
|
||||||
|
).toHaveLength(8);
|
||||||
|
});
|
||||||
|
// #endregion
|
||||||
|
});
|
19
test/vitest.d.ts
vendored
Normal file
19
test/vitest.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/// <reference types="vitest" />
|
||||||
|
|
||||||
|
import type { Assertion, AsymmetricMatchersContaining } from 'vitest';
|
||||||
|
|
||||||
|
interface CustomMatchers<R = unknown> {
|
||||||
|
toContainRules(expected: Record<string, unknown>): R;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'vitest' {
|
||||||
|
interface Assertion<T = any> extends CustomMatchers<T> {}
|
||||||
|
interface AsymmetricMatchersContaining extends CustomMatchers {}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'vitest' {
|
||||||
|
// @ts-expect-error We need to extend the TestAPI interface
|
||||||
|
export interface TestAPI {
|
||||||
|
extend: <T>(matchers: Record<string, (this: T, ...args: any[]) => any>) => void;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user