feat: replace no only tests with vitest (!2)

This gives us a much more robust configuration for our rules. Additionally, it expects tests to be converted to the `expect` API.

Reviewed-on: https://codeberg.org/nhcarrigan/eslint-config/pulls/2
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
This commit is contained in:
Naomi Carrigan 2024-09-26 00:21:31 +00:00 committed by Naomi the Technomancer
parent 9b128c1bf1
commit 883274a3e4
9 changed files with 172 additions and 213 deletions

View File

@ -35,11 +35,11 @@
"@stylistic/eslint-plugin": "2.3.0",
"@typescript-eslint/eslint-plugin": "rc-v8",
"@typescript-eslint/parser": "rc-v8",
"@vitest/eslint-plugin": "1.1.4",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-deprecation": "3.0.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "48.8.3",
"eslint-plugin-no-only-tests": "3.1.0",
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-sort-keys-fix": "1.1.2",
"eslint-plugin-unicorn": "55.0.0",

34
pnpm-lock.yaml generated
View File

@ -26,6 +26,9 @@ importers:
'@typescript-eslint/parser':
specifier: rc-v8
version: 8.0.0-alpha.54(eslint@9.7.0)(typescript@5.5.4)
'@vitest/eslint-plugin':
specifier: 1.1.4
version: 1.1.4(eslint@9.7.0)(typescript@5.5.4)(vitest@2.0.4(@types/node@20.14.12))
eslint:
specifier: '>=9'
version: 9.7.0
@ -41,9 +44,6 @@ importers:
eslint-plugin-jsdoc:
specifier: 48.8.3
version: 48.8.3(eslint@9.7.0)
eslint-plugin-no-only-tests:
specifier: 3.1.0
version: 3.1.0
eslint-plugin-prettier:
specifier: 5.2.1
version: 5.2.1(@types/eslint@9.6.0)(eslint-config-prettier@9.1.0(eslint@9.7.0))(eslint@9.7.0)(prettier@3.3.3)
@ -541,6 +541,21 @@ packages:
resolution: {integrity: sha512-lS8wrI6Vxw6ebIi+ehocAjXLG43bN5JCC8+wtGDD3Xw9O/EVpanAVdftefJs/mlK87eyccvVIiiHgD294TpIEQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@vitest/eslint-plugin@1.1.4':
resolution: {integrity: sha512-kudjgefmJJ7xQ2WfbUU6pZbm7Ou4gLYRaao/8Ynide3G0QhVKHd978sDyWX4KOH0CCMH9cyrGAkFd55eGzJ48Q==}
peerDependencies:
'@typescript-eslint/utils': '>= 8.0'
eslint: '>= 8.57.0'
typescript: '>= 5.0.0'
vitest: '*'
peerDependenciesMeta:
'@typescript-eslint/utils':
optional: true
typescript:
optional: true
vitest:
optional: true
'@vitest/expect@2.0.4':
resolution: {integrity: sha512-39jr5EguIoanChvBqe34I8m1hJFI4+jxvdOpD7gslZrVQBKhh8H9eD7J/LJX4zakrw23W+dITQTDqdt43xVcJw==}
@ -856,10 +871,6 @@ packages:
peerDependencies:
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
eslint-plugin-no-only-tests@3.1.0:
resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==}
engines: {node: '>=5.0.0'}
eslint-plugin-prettier@5.2.1:
resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==}
engines: {node: ^14.18.0 || >=16.0.0}
@ -2167,6 +2178,13 @@ snapshots:
'@typescript-eslint/types': 8.0.0-alpha.54
eslint-visitor-keys: 3.4.3
'@vitest/eslint-plugin@1.1.4(eslint@9.7.0)(typescript@5.5.4)(vitest@2.0.4(@types/node@20.14.12))':
dependencies:
eslint: 9.7.0
optionalDependencies:
typescript: 5.5.4
vitest: 2.0.4(@types/node@20.14.12)
'@vitest/expect@2.0.4':
dependencies:
'@vitest/spy': 2.0.4
@ -2573,8 +2591,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-no-only-tests@3.1.0: {}
eslint-plugin-prettier@5.2.1(@types/eslint@9.6.0)(eslint-config-prettier@9.1.0(eslint@9.7.0))(eslint@9.7.0)(prettier@3.3.3):
dependencies:
eslint: 9.7.0

View File

@ -8,10 +8,10 @@ import { fixupPluginRules } from "@eslint/compat";
import stylistic from "@stylistic/eslint-plugin";
import tslint from "@typescript-eslint/eslint-plugin";
import parser from "@typescript-eslint/parser";
import vitest from "@vitest/eslint-plugin";
import deprecation from "eslint-plugin-deprecation";
import importPlugin from "eslint-plugin-import";
import jsdoc from "eslint-plugin-jsdoc";
import noOnlyTests from "eslint-plugin-no-only-tests";
import sortKeysFix from "eslint-plugin-sort-keys-fix";
import unicorn from "eslint-plugin-unicorn";
import globals from "globals";
@ -19,12 +19,12 @@ import { deprecationRules } from "./rules/deprecation.js";
import { disabledEslintRules, eslintRules } from "./rules/eslint.js";
import { importRules } from "./rules/import.js";
import { jsdocRules } from "./rules/jsdoc.js";
import { noOnlyTestsRules } from "./rules/noOnlyTests.js";
import { sortKeysFixRules } from "./rules/sortKeysFix.js";
import { stylisticRules } from "./rules/stylistic.js";
import { typescriptEslintRules, typescriptEslintRulesWithTypes }
from "./rules/typescriptEslint.js";
import { unicornRules } from "./rules/unicorn.js";
import { vitestRules } from "./rules/vitest.js";
import type { ESLint, Linter } from "eslint";
const config: Array<Linter.Config> = [
@ -49,24 +49,24 @@ const config: Array<Linter.Config> = [
"deprecation": fixupPluginRules(deprecation),
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
"jsdoc": jsdoc,
"no-only-tests": noOnlyTests 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
"stylistic": fixupPluginRules(stylistic),
"unicorn": unicorn,
"vitest": vitest,
},
rules: {
...eslintRules,
...disabledEslintRules,
...typescriptEslintRules,
...typescriptEslintRulesWithTypes,
...noOnlyTestsRules,
...importRules,
...jsdocRules,
...deprecationRules,
...stylisticRules,
...unicornRules,
...sortKeysFixRules,
...vitestRules,
},
},
{
@ -86,17 +86,17 @@ const config: Array<Linter.Config> = [
"@typescript-eslint": tslint,
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
"jsdoc": jsdoc,
"no-only-tests": noOnlyTests 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
"stylistic": fixupPluginRules(stylistic),
"unicorn": unicorn,
"vitest": vitest,
},
rules: {
...eslintRules,
...disabledEslintRules,
...typescriptEslintRules,
...noOnlyTestsRules,
...vitestRules,
...importRules,
...jsdocRules,
...stylisticRules,

View File

@ -1,17 +0,0 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { Linter } from "eslint";
export const noOnlyTestsRules: Linter.RulesRecord = {
"no-only-tests/no-only-tests": [
"warn",
{
block: [ "test", "expect", "assert", "describe", "bench" ],
focus: [ "only", "skip" ],
},
],
};

57
src/rules/vitest.ts Normal file
View File

@ -0,0 +1,57 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { Linter } from "eslint";
export const vitestRules: Linter.RulesRecord = {
"vitest/consistent-test-filename":
[ "warn", { pattern: /^[\da-z-]+\.spec\.ts$/ } ],
"vitest/consistent-test-it": "warn",
"vitest/expect-expect": "warn",
"vitest/max-nested-describe": [ "warn", { max: 2 } ],
"vitest/no-alias-methods": "warn",
"vitest/no-commented-out-tests": "warn",
"vitest/no-conditional-expect": "warn",
"vitest/no-conditional-in-test": "warn",
"vitest/no-conditional-tests": "warn",
"vitest/no-disabled-tests": "warn",
"vitest/no-done-callback": "warn",
"vitest/no-duplicate-hooks": "warn",
"vitest/no-focused-tests": "warn",
"vitest/no-identical-title": "warn",
"vitest/no-import-node-test": "warn",
"vitest/no-interpolation-in-snapshots": "warn",
"vitest/no-restricted-vi-methods": "warn",
"vitest/no-standalone-expect": "warn",
"vitest/no-test-prefixes": "warn",
"vitest/no-test-return-statement": "warn",
"vitest/prefer-called-with": "warn",
"vitest/prefer-comparison-matcher": "warn",
"vitest/prefer-each": "warn",
"vitest/prefer-equality-matcher": "warn",
"vitest/prefer-expect-assertions": "warn",
"vitest/prefer-expect-resolves": "warn",
"vitest/prefer-hooks-in-order": "warn",
"vitest/prefer-hooks-on-top": "warn",
"vitest/prefer-lowercase-title": "warn",
"vitest/prefer-mock-promise-shorthand": "warn",
"vitest/prefer-spy-on": "warn",
"vitest/prefer-strict-equal": "warn",
"vitest/prefer-to-be": "warn",
"vitest/prefer-to-be-falsy": "warn",
"vitest/prefer-to-be-object": "warn",
"vitest/prefer-to-be-truthy": "warn",
"vitest/prefer-to-contain": "warn",
"vitest/prefer-to-have-length": "warn",
"vitest/prefer-todo": "warn",
"vitest/require-hook": "warn",
"vitest/require-to-throw-message": "warn",
"vitest/require-top-level-describe": "warn",
"vitest/valid-describe-callback": "warn",
"vitest/valid-expect":
[ "warn", { maxArgs: 2, minArgs: 2 } ],
"vitest/valid-title": "warn",
};

View File

@ -4,42 +4,27 @@
* @author Naomi Carrigan
*/
import { suite, assert, test } from "vitest";
import { describe, expect, it } from "vitest";
import { disabledEslintRules, eslintRules } from "../src/rules/eslint.ts";
suite("ESLint Configs", () => {
test("should not enable disabled rules", () => {
describe("eslint configs", () => {
it("should not enable disabled rules", () => {
expect.assertions(20);
const disabled = Object.keys(disabledEslintRules);
const enabled = Object.keys(eslintRules);
for (const key of disabled) {
assert.notInclude(
enabled,
key,
`Disabled rule ${key} has been re-enabled!`,
);
expect(enabled, `Disabled rule ${key} has been re-enabled!`).not.toContain(key);
}
});
test("all disabled rules should be off", () => {
it("all disabled rules should be off", () => {
expect.assertions(20);
const rules = Object.entries(disabledEslintRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.strictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.strictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned on - disabled rules should be explicitly turned off.`).toBe("off");
continue;
}
});
});

View File

@ -4,174 +4,83 @@
* @author Naomi Carrigan
*/
import { suite, assert, test } from "vitest";
import { describe, expect, it } from "vitest";
import { eslintRules } from "../src/rules/eslint.ts";
import { importRules } from "../src/rules/import.js";
import { jsdocRules } from "../src/rules/jsdoc.js";
import { noOnlyTestsRules } from "../src/rules/noOnlyTests.js";
import { stylisticRules } from "../src/rules/stylistic.ts";
import { typescriptEslintRules } from "../src/rules/typescriptEslint.js";
import { unicornRules } from "../src/rules/unicorn.js";
import { vitestRules } from "../src/rules/vitest.js";
suite("No rules should be turned off in", () => {
test("eslint rules", () => {
describe("no rules should be turned off in", () => {
it("eslint rules", () => {
expect.assertions(148);
const rules = Object.entries(eslintRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.notStrictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.notStrictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
}
});
test("import rules", () => {
it("import rules", () => {
expect.assertions(29);
const rules = Object.entries(importRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.notStrictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.notStrictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
}
});
test("jsdoc rules", () => {
it("jsdoc rules", () => {
expect.assertions(43);
const rules = Object.entries(jsdocRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.notStrictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.notStrictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
}
});
test("no-only-tests rules", () => {
const rules = Object.entries(noOnlyTestsRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.notStrictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.notStrictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
}
});
test("stylistic rules", () => {
it("stylistic rules", () => {
expect.assertions(65);
const rules = Object.entries(stylisticRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.notStrictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.notStrictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
}
});
test("typescript-eslint rules", () => {
it("typescript-eslint rules", () => {
expect.assertions(59);
const rules = Object.entries(typescriptEslintRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.notStrictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.notStrictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
}
});
test("unicorn rules", () => {
it("unicorn rules", () => {
expect.assertions(73);
const rules = Object.entries(unicornRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.notStrictEqual(
rule.at(0),
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
if (typeof rule === "string") {
assert.notStrictEqual(
rule,
"off",
`${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
}
});
it("vitest rules", () => {
expect.assertions(45);
const rules = Object.entries(vitestRules);
for (const [ name, rule ] of rules) {
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
}
});
});

View File

@ -4,30 +4,18 @@
* @author Naomi Carrigan
*/
import { suite, assert, test } from "vitest";
import { describe, expect, it } from "vitest";
import { stylisticRules } from "../src/rules/stylistic.ts";
suite("Stylistic Configs", () => {
test("should never be an error", () => {
describe("stylistic configs", () => {
it("should never be an error", () => {
expect.assertions(65);
const rules = Object.entries(stylisticRules);
for (const [ name, rule ] of rules) {
if (Array.isArray(rule)) {
assert.include(
[ "off", "warn" ],
rule.at(0),
`${name} appears to be set to an error!`,
);
continue;
}
if (typeof rule === "string") {
assert.include(
[ "off", "warn" ],
rule,
`${name} appears to be set to an error!`,
);
continue;
}
assert.fail(`Could not determine rule type for ${name}!`);
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be set to an error!`).not.toBe("error");
continue;
}
});
});

21
test/vitest.spec.ts Normal file
View File

@ -0,0 +1,21 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { describe, expect, it } from "vitest";
import { vitestRules } from "../src/rules/vitest.ts";
describe("vitest configs", () => {
it("should never be an error", () => {
expect.assertions(45);
const rules = Object.entries(vitestRules);
for (const [ name, rule ] of rules) {
expect(Array.isArray(rule)
? rule.at(0)
: rule, `${name} appears to be set to an error!`).not.toBe("error");
continue;
}
});
});