Skip to content

Commit

Permalink
chore: introduce eslint rule to ensure describe() has component name …
Browse files Browse the repository at this point in the history
…as title (#2747)
  • Loading branch information
jeripeierSBB authored Jun 13, 2024
1 parent 72b8893 commit c39cd13
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 9 deletions.
6 changes: 6 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ export default [
'import-x/namespace': 'off',
},
},
{
files: ['src/storybook/**/*.ts'],
rules: {
'lyne/test-describe-title': 'off',
},
},
{
files: ['**/*.ts'],
rules: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["sbb-card-button renders DOM"] =
snapshots["sbb-card-link renders DOM"] =
`<sbb-card
color="white"
data-action-role="link"
Expand All @@ -21,9 +21,9 @@ snapshots["sbb-card-button renders DOM"] =
Content text
</sbb-card>
`;
/* end snapshot sbb-card-button renders DOM */
/* end snapshot sbb-card-link renders DOM */

snapshots["sbb-card-button renders Shadow DOM"] =
snapshots["sbb-card-link renders Shadow DOM"] =
`<span class="sbb-card">
<slot name="action">
</slot>
Expand All @@ -37,9 +37,9 @@ snapshots["sbb-card-button renders Shadow DOM"] =
</span>
</span>
`;
/* end snapshot sbb-card-button renders Shadow DOM */
/* end snapshot sbb-card-link renders Shadow DOM */

snapshots["sbb-card-button renders A11y tree Chrome"] =
snapshots["sbb-card-link renders A11y tree Chrome"] =
`<p>
{
"role": "WebArea",
Expand All @@ -57,9 +57,9 @@ snapshots["sbb-card-button renders A11y tree Chrome"] =
}
</p>
`;
/* end snapshot sbb-card-button renders A11y tree Chrome */
/* end snapshot sbb-card-link renders A11y tree Chrome */

snapshots["sbb-card-button renders A11y tree Firefox"] =
snapshots["sbb-card-link renders A11y tree Firefox"] =
`<p>
{
"role": "document",
Expand All @@ -78,5 +78,5 @@ snapshots["sbb-card-button renders A11y tree Firefox"] =
}
</p>
`;
/* end snapshot sbb-card-button renders A11y tree Firefox */
/* end snapshot sbb-card-link renders A11y tree Firefox */

2 changes: 1 addition & 1 deletion src/elements/card/card-link/card-link.snapshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { SbbCardElement } from '../card.js';
import '../card.js';
import './card-link.js';

describe(`sbb-card-button`, () => {
describe(`sbb-card-link`, () => {
let element: SbbCardElement;

describe('renders', () => {
Expand Down
2 changes: 2 additions & 0 deletions tools/eslint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as importExtensionRule from './import-extension-rule.js';
import * as useLocalName from './local-name-rule.js';
import * as missingComponentDocumentation from './missing-component-documentation-rule.js';
import * as needsSuperCall from './needs-super-call-rule.js';
import * as testDescribeTitle from './test-describe-title.js';
import * as tabKeyRule from './test-tabkey-rule.js';

const plugin: Omit<Required<TSESLint.FlatConfig.Plugin>, 'processors'> = {
Expand All @@ -21,6 +22,7 @@ const plugin: Omit<Required<TSESLint.FlatConfig.Plugin>, 'processors'> = {
[customElementDecoratorPosition.name]: customElementDecoratorPosition.rule,
[needsSuperCall.name]: needsSuperCall.rule,
[tabKeyRule.name]: tabKeyRule.rule,
[testDescribeTitle.name]: testDescribeTitle.rule,
},
};

Expand Down
78 changes: 78 additions & 0 deletions tools/eslint/test-describe-title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { ESLintUtils } from '@typescript-eslint/utils';

const createRule = ESLintUtils.RuleCreator(
(name) =>
`https://github.com/sbb-design-systems/lyne-components/blob/main/tools/eslint/${name}.ts`,
);

type MessageIds = 'testDescribeTitle';

export const name = 'test-describe-title';
export const rule: TSESLint.RuleModule<MessageIds, never[]> = createRule<never[], MessageIds>({
create(context) {
return {
['Program > ExpressionStatement > CallExpression > Identifier[name="describe"]'](
node: TSESTree.Identifier,
) {
const fileName = context.getFilename();
const expression = node.parent as TSESTree.CallExpression;
const expressionArguments = expression.arguments;
const componentName = fileName.match(/\/([^/]+)\/?.spec.ts$/)?.[1]?.match(/^(.*)\./)?.[1];

if (!componentName || !expressionArguments.length) {
return;
}

const titleArgument = expressionArguments[0] as
| TSESTree.TemplateLiteral
| TSESTree.StringLiteral;

/**
* Read full TemplateLiteral raw string
* @param node
*/
function getTemplateLiteralRawString(node: TSESTree.TemplateLiteral): string {
return context.getSourceCode().text.substring(node.range[0] + 1, node.range[1] - 1);
}

const currentTitle =
titleArgument.type === 'TemplateLiteral'
? getTemplateLiteralRawString(titleArgument)
: titleArgument.value;

const expectedTitle = fileName.endsWith('ssr.spec.ts')
? `sbb-${componentName} \${fixture.name}`
: `sbb-${componentName}`;

if (currentTitle !== expectedTitle) {
context.report({
node,
messageId: 'testDescribeTitle',
data: {
currentTitle,
expectedTitle,
},
fix: (fixer) => fixer.replaceTextRange(titleArgument.range, `\`${expectedTitle}\``),
});
}
},
};
},
name,
meta: {
docs: {
description: 'describe() title has to be aligned with component name.',
recommended: 'recommended',
},
messages: {
testDescribeTitle:
'describe() title `{{ currentTitle }}` has to be aligned with component name and should be `{{ expectedTitle }}`.',
},
fixable: 'code',
type: 'problem',
schema: [],
hasSuggestions: true,
},
defaultOptions: [],
});

0 comments on commit c39cd13

Please sign in to comment.