-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1878 from SUI-Components/feat-create-default-comp…
…onent-test-rule Feat create default component test rule
- Loading branch information
Showing
6 changed files
with
260 additions
and
3 deletions.
There are no files selected for viewing
60 changes: 60 additions & 0 deletions
60
packages/eslint-plugin-sui/docs/rules/default-component-test.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Detect default component test cases that haven't been customized (`default-component-test`) | ||
|
||
This rule detects when a component's test file only contains the default test cases generated by the component generator. This indicates that the developer has created a new component but hasn't written specific tests for its functionality. | ||
|
||
## Rule Details | ||
|
||
The component generator creates a default test file with three basic test cases that only verify basic React component requirements. While these tests are useful as a starting point, they don't validate the specific functionality of your component. | ||
|
||
This rule will warn you when: | ||
- You have only default test cases in your test file | ||
- Individual test cases that match the default generated ones | ||
|
||
Examples of **incorrect** code for this rule: | ||
|
||
```js | ||
describe.context.default('MyComponent', () => { | ||
it('should render without crashing', () => { | ||
// Default test implementation | ||
}) | ||
|
||
it('should NOT render null', () => { | ||
// Default test implementation | ||
}) | ||
|
||
it('should NOT extend classNames', () => { | ||
// Default test implementation | ||
}) | ||
}) | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```js | ||
describe.context.default('MyComponent', () => { | ||
it('should render without crashing', () => { | ||
// Default test implementation | ||
}) | ||
|
||
it('should show error message when invalid input', () => { | ||
// Custom test validating specific component behavior | ||
}) | ||
|
||
it('should trigger onSubmit when form is valid', () => { | ||
// Custom test validating specific component behavior | ||
}) | ||
}) | ||
``` | ||
|
||
### Options | ||
|
||
This rule has no options. | ||
|
||
## When Not To Use It | ||
|
||
If you are working with non-component code or if you're satisfied with the basic React component validation that the default tests provide. | ||
|
||
## Further Reading | ||
|
||
- [React Testing Best Practices](https://reactjs.org/docs/testing.html) | ||
- [Component Testing Guidelines](https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
packages/eslint-plugin-sui/src/rules/default-component-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/** | ||
* @fileoverview Detect default component test cases that haven't been customized | ||
*/ | ||
'use strict' | ||
|
||
const dedent = require('string-dedent') | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Rule Definition | ||
// ------------------------------------------------------------------------------ | ||
|
||
/** @type {import('eslint').Rule.RuleModule} */ | ||
module.exports = { | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: 'Detect when component test file only contains default test cases', | ||
recommended: true, | ||
url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' | ||
}, | ||
schema: [], | ||
messages: { | ||
defaultTestCase: dedent` | ||
This seems to be a default test case generated by the component generator. | ||
Please add specific test cases that validate your component's functionality. | ||
`, | ||
onlyDefaultTests: dedent` | ||
This test file only contains default test cases. | ||
Please add specific tests that validate your component's functionality. | ||
` | ||
} | ||
}, | ||
|
||
create(context) { | ||
// Track the test cases we find | ||
const defaultTestCases = new Set([ | ||
'should render without crashing', | ||
'should NOT render null', | ||
'should NOT extend classNames' | ||
]) | ||
|
||
const foundTestCases = new Set() | ||
let totalTestCases = 0 | ||
|
||
function isComponentTestFile(filename) { | ||
return filename.includes('/components/') && filename.endsWith('.test.js') | ||
} | ||
|
||
return { | ||
Program(node) { | ||
// Reset counters for each file | ||
foundTestCases.clear() | ||
totalTestCases = 0 | ||
}, | ||
|
||
CallExpression(node) { | ||
const filename = context.getFilename() | ||
// Solo procesar si estamos en un archivo de test de componente | ||
if (!isComponentTestFile(filename)) return | ||
|
||
// Look for it() calls | ||
if (node.callee.name !== 'it') return | ||
|
||
const testName = node.arguments[0]?.value | ||
if (!testName) return | ||
|
||
totalTestCases++ | ||
|
||
// Check if this is one of the default test cases | ||
if (defaultTestCases.has(testName)) { | ||
foundTestCases.add(testName) | ||
|
||
context.report({ | ||
node: node.arguments[0], | ||
messageId: 'defaultTestCase' | ||
}) | ||
} | ||
|
||
// After processing all tests in this block, check if they are all default ones | ||
if ( | ||
totalTestCases > 0 && | ||
foundTestCases.size === defaultTestCases.size && | ||
[...foundTestCases].every(test => defaultTestCases.has(test)) | ||
) { | ||
context.report({ | ||
node: node.parent, | ||
messageId: 'onlyDefaultTests' | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
packages/eslint-plugin-sui/test/server/default-component-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import dedent from 'dedent' | ||
import {RuleTester} from 'eslint' | ||
|
||
import rule from '../../src/rules/default-component-test.js' | ||
|
||
const resolvedBabelPresetSui = require.resolve('babel-preset-sui') | ||
const parser = require.resolve('@babel/eslint-parser') | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Tests | ||
// ------------------------------------------------------------------------------ | ||
|
||
const ruleTester = new RuleTester({ | ||
parser, | ||
parserOptions: { | ||
babelOptions: {configFile: resolvedBabelPresetSui} | ||
} | ||
}) | ||
|
||
ruleTester.run('default-component-test', rule, { | ||
valid: [ | ||
// Should ignore non-component test files | ||
{ | ||
filename: '/domain/value-objects/test/car.test.js', | ||
code: dedent` | ||
describe.context.default('Car', () => { | ||
it('should render without crashing', () => {}) | ||
it('should NOT render null', () => {}) | ||
it('should NOT extend classNames', () => {}) | ||
}) | ||
` | ||
}, | ||
// Should be valid when there are custom tests along with default ones | ||
{ | ||
filename: '/components/card/alert/test/index.test.js', | ||
code: dedent` | ||
describe.context.default('CardAlert', Component => { | ||
it('should render without crashing', () => {}) | ||
it('should NOT render null', () => {}) | ||
it('should show custom alert message', () => {}) | ||
it('should trigger onClose callback', () => {}) | ||
}) | ||
` | ||
}, | ||
// Should be valid when all tests are custom | ||
{ | ||
filename: '/components/card/alert/test/index.test.js', | ||
code: dedent` | ||
describe.context.default('CardAlert', Component => { | ||
it('should show title correctly', () => {}) | ||
it('should handle click events', () => {}) | ||
}) | ||
` | ||
} | ||
], | ||
|
||
invalid: [ | ||
// Should detect when only default tests are present | ||
{ | ||
filename: '/components/card/alert/test/index.test.js', | ||
code: dedent` | ||
describe.context.default('CardAlert', Component => { | ||
it('should render without crashing', () => {}) | ||
it('should NOT render null', () => {}) | ||
it('should NOT extend classNames', () => {}) | ||
}) | ||
`, | ||
errors: [ | ||
{ | ||
messageId: 'defaultTestCase', | ||
line: 2 | ||
}, | ||
{ | ||
messageId: 'defaultTestCase', | ||
line: 3 | ||
}, | ||
{ | ||
messageId: 'defaultTestCase', | ||
line: 4 | ||
} | ||
] | ||
}, | ||
// Should detect individual default tests | ||
{ | ||
filename: '/components/card/alert/test/index.test.js', | ||
code: dedent` | ||
describe.context.default('CardAlert', Component => { | ||
it('should render without crashing', () => {}) | ||
it('should handle click events', () => {}) | ||
}) | ||
`, | ||
errors: [ | ||
{ | ||
messageId: 'defaultTestCase', | ||
line: 2 | ||
} | ||
] | ||
} | ||
] | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters