Skip to content

Commit

Permalink
feat: add should-be-fine support for flat configs (#343)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath authored Mar 21, 2024
1 parent 622c191 commit a3b6695
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 44 deletions.
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;

0 comments on commit a3b6695

Please sign in to comment.