Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add should-be-fine support for flat configs #343

Merged
merged 8 commits into from
Mar 21, 2024
10 changes: 10 additions & 0 deletions .eslint-doc-generatorrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @type {import('eslint-doc-generator').GenerateOptions} */
const config = {
ignoreConfig: [
'all',
'flat/all',
'flat/recommended',
],
};

module.exports = config;
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ This library has a required `peerDependencies` listing for [`ESLint`](https://es

## Usage

> [!NOTE]
>
> `eslint.config.js` is supported, though most of the plugin documentation still
> currently uses `.eslintrc` syntax; compatible versions of configs are available
> prefixed with `flat/` and may be subject to small breaking changes while ESLint
> v9 is being finalized.
>
> Refer to the
> [ESLint documentation on the new configuration file format](https://eslint.org/docs/latest/use/configure/configuration-files-new)
> for more.

Add `jest-dom` to the plugins section of your `.eslintrc.js` configuration file.
You can omit the `eslint-plugin-` prefix:

Expand Down Expand Up @@ -78,8 +89,7 @@ This plugin exports a recommended configuration that enforces good `jest-dom`
practices _(you can find more info about enabled rules in
[Supported Rules section](#supported-rules))_.

To enable this configuration use the `extends` property in your `.eslintrc.js`
config file:
To enable this configuration with `.eslintrc`, use the `extends` property:

```javascript
module.exports = {
Expand All @@ -90,6 +100,20 @@ module.exports = {
};
```

To enable this configuration with `eslint.config.js`, use
`jestDom.configs['flat/recommended']`:

```javascript
module.exports = [
{
files: [
/* glob matching your test files */
],
...require("eslint-plugin-jest-dom").configs["flat/recommended"],
},
];
```

## Supported Rules

<!-- begin auto-generated rules list -->
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"scripts": {
"build": "kcd-scripts build",
"pregenerate-readme-table": "npm run build",
"generate-readme-table": "eslint-doc-generator --ignore-config all",
"generate-readme-table": "eslint-doc-generator",
"lint": "kcd-scripts lint",
"lint:generate-readme-table": "npm run generate-readme-table -- --check",
"setup": "npm install && npm run validate -s",
Expand Down
89 changes: 74 additions & 15 deletions src/__tests__/index.test.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,81 @@
import { generateRecommendedConfig, rules } from "../";
import plugin, { configs, rules } from "../";

it("includes the configs and rules on the plugin", () => {
expect(plugin).toHaveProperty("configs", configs);
expect(plugin).toHaveProperty("rules", rules);
});

it("should have all the rules", () => {
expect(Object.keys(rules).length).toBeGreaterThan(0);
expect(Object.keys(rules)).toHaveLength(11);
});

it.each(Object.keys(rules))("%s should export required fields", (ruleName) => {
const rule = rules[ruleName];
expect(rule).toHaveProperty("create", expect.any(Function));
expect(rule.meta.docs.url).not.toBe("");
expect(rule.meta.docs.category).toBe("Best Practices");
expect(rule.meta.docs.description).not.toBe("");
it.each(Object.entries(rules))(
"%s should export required fields",
(name, rule) => {
expect(rule).toHaveProperty("create", expect.any(Function));
expect(rule.meta.docs.url).not.toBe("");
expect(rule.meta.docs.category).toBe("Best Practices");
expect(rule.meta.docs.description).not.toBe("");
}
);

it("has the expected recommended config", () => {
expect(configs.recommended).toMatchInlineSnapshot(`
Object {
plugins: Array [
jest-dom,
],
rules: Object {
jest-dom/prefer-checked: error,
jest-dom/prefer-empty: error,
jest-dom/prefer-enabled-disabled: error,
jest-dom/prefer-focus: error,
jest-dom/prefer-in-document: error,
jest-dom/prefer-required: error,
jest-dom/prefer-to-have-attribute: error,
jest-dom/prefer-to-have-class: error,
jest-dom/prefer-to-have-style: error,
jest-dom/prefer-to-have-text-content: error,
jest-dom/prefer-to-have-value: error,
},
}
`);
});

it("should have a recommended config with recommended rules", () => {
expect(
generateRecommendedConfig({
good: { meta: { docs: { recommended: true } } },
bad: { meta: { docs: { recommended: false } } },
})
).toEqual({ "jest-dom/good": "error" });
it("has the expected recommended flat config", () => {
const expectJestDomPlugin = expect.objectContaining({
meta: {
name: "eslint-plugin-jest-dom",
version: expect.any(String),
},
});

expect(configs["flat/recommended"]).toMatchInlineSnapshot(
{ plugins: { "jest-dom": expectJestDomPlugin } },
`
Object {
plugins: Object {
jest-dom: ObjectContaining {
meta: Object {
name: eslint-plugin-jest-dom,
version: Any<String>,
},
},
},
rules: Object {
jest-dom/prefer-checked: error,
jest-dom/prefer-empty: error,
jest-dom/prefer-enabled-disabled: error,
jest-dom/prefer-focus: error,
jest-dom/prefer-in-document: error,
jest-dom/prefer-required: error,
jest-dom/prefer-to-have-attribute: error,
jest-dom/prefer-to-have-class: error,
jest-dom/prefer-to-have-style: error,
jest-dom/prefer-to-have-text-content: error,
jest-dom/prefer-to-have-value: error,
},
}
`
);
});
71 changes: 45 additions & 26 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,58 @@
//------------------------------------------------------------------------------

import requireIndex from "requireindex";
import {
name as packageName,
version as packageVersion,
} from "../package.json";

//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------

// import all rules in src/rules
// import all rules in src/rules and re-export them for .eslintrc configs
export const rules = requireIndex(`${__dirname}/rules`);

export const generateRecommendedConfig = (allRules) =>
Object.entries(allRules).reduce(
(memo, [name, rule]) => ({
...memo,
...(rule.meta.docs.recommended ? { [`jest-dom/${name}`]: "error" } : {}),
}),
{}
);

export const generateAllRulesConfig = (allRules) =>
Object.entries(allRules).reduce(
(memo, [name]) => ({
...memo,
...{ [`jest-dom/${name}`]: "error" },
}),
{}
);

export const configs = {
recommended: {
plugins: ["jest-dom"],
rules: generateRecommendedConfig(rules),
const allRules = Object.entries(rules).reduce(
(memo, [name]) => ({
...memo,
...{ [`jest-dom/${name}`]: "error" },
}),
{}
);

const recommendedRules = allRules;

const plugin = {
meta: {
name: packageName,
version: packageVersion,
},
all: {
plugins: ["jest-dom"],
rules: generateAllRulesConfig(rules),
configs: {
recommended: {
plugins: ["jest-dom"],
rules: recommendedRules,
},
all: {
plugins: ["jest-dom"],
rules: allRules,
},
},
rules,
};

plugin.configs["flat/recommended"] = {
plugins: { "jest-dom": plugin },
rules: recommendedRules,
};
plugin.configs["flat/all"] = {
plugins: { "jest-dom": plugin },
rules: allRules,
};

export default plugin;

// explicitly export config to allow using this plugin in CJS-based
// eslint.config.js files without needing to deal with the .default
// and also retain backwards compatibility with `.eslintrc` configs
export const configs = plugin.configs;
Loading