From 79b380fb459fe1f4638d46bc692a375cfc5fa937 Mon Sep 17 00:00:00 2001 From: Patrick Ahmetovic <23729362+patriscus@users.noreply.github.com> Date: Mon, 23 Jan 2023 14:30:57 +0100 Subject: [PATCH] feat(consistent-data-testid): add support for custom error message (#719) Closes #718 * feat(consistent-data-testid): add support for custom message in the rule configuration * feat(consistent-data-testid): update docs * feat(consistent-data-testid): use undefined as default value for customMessage * feat(consistent-data-testid): add comment to test case Co-authored-by: Patrick Ahmetovic --- docs/rules/consistent-data-testid.md | 12 +++++++ lib/rules/consistent-data-testid.ts | 24 +++++++++++-- .../lib/rules/consistent-data-testid.test.ts | 36 +++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/docs/rules/consistent-data-testid.md b/docs/rules/consistent-data-testid.md index 0cfc3406..fb7f9940 100644 --- a/docs/rules/consistent-data-testid.md +++ b/docs/rules/consistent-data-testid.md @@ -34,6 +34,7 @@ const baz = (props) =>
...
; | ----------------- | -------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | | `testIdPattern` | Yes | None | A regex used to validate the format of the `data-testid` value. `{fileName}` can optionally be used as a placeholder and will be substituted with the name of the file OR the name of the files parent directory in the case when the file name is `index.js` OR empty string in the case of dynamically changing routes (that contain square brackets) with `Gatsby.js` or `Next.js` | `^{fileName}(\_\_([A-Z]+[a-z]_?)+)_\$` | | `testIdAttribute` | No | `data-testid` | A string (or array of strings) used to specify the attribute used for querying by ID. This is only required if data-testid has been explicitly overridden in the [RTL configuration](https://testing-library.com/docs/dom-testing-library/api-queries#overriding-data-testid) | `data-my-test-attribute`, `["data-testid", "testId"]` | +| `customMessage` | No | `undefined` | A string used to display a custom message whenever warnings/errors are reported. | `A custom message` | ## Example @@ -59,6 +60,17 @@ const baz = (props) =>
...
; } ``` +```json +{ + "testing-library/consistent-data-testid": [ + 2, + { + "customMessage": "A custom message" + } + ] +} +``` + ## Notes - If you are using Gatsby.js's [client-only routes](https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api/#syntax-client-only-routes) or Next.js's [dynamic routes](https://nextjs.org/docs/routing/dynamic-routes) and therefore have square brackets (`[]`) in the filename (e.g. `../path/to/[component].js`), the `{fileName}` placeholder will be replaced with an empty string. This is because a linter cannot know what the dynamic content will be at run time. diff --git a/lib/rules/consistent-data-testid.ts b/lib/rules/consistent-data-testid.ts index e71bcb5e..7760776c 100644 --- a/lib/rules/consistent-data-testid.ts +++ b/lib/rules/consistent-data-testid.ts @@ -2,11 +2,14 @@ import { createTestingLibraryRule } from '../create-testing-library-rule'; import { isJSXAttribute, isLiteral } from '../node-utils'; export const RULE_NAME = 'consistent-data-testid'; -export type MessageIds = 'consistentDataTestId'; +export type MessageIds = + | 'consistentDataTestId' + | 'consistentDataTestIdCustomMessage'; export type Options = [ { testIdAttribute?: string[] | string; testIdPattern: string; + customMessage?: string; } ]; @@ -28,6 +31,7 @@ export default createTestingLibraryRule({ }, messages: { consistentDataTestId: '`{{attr}}` "{{value}}" should match `{{regex}}`', + consistentDataTestIdCustomMessage: '`{{message}}`', }, schema: [ { @@ -53,6 +57,10 @@ export default createTestingLibraryRule({ }, ], }, + customMessage: { + default: undefined, + type: 'string', + }, }, }, ], @@ -61,6 +69,7 @@ export default createTestingLibraryRule({ { testIdPattern: '', testIdAttribute: 'data-testid', + customMessage: undefined, }, ], detectionOptions: { @@ -69,7 +78,7 @@ export default createTestingLibraryRule({ create: (context, [options]) => { const { getFilename } = context; - const { testIdPattern, testIdAttribute: attr } = options; + const { testIdPattern, testIdAttribute: attr, customMessage } = options; function getFileNameData() { const splitPath = getFilename().split('/'); @@ -100,6 +109,14 @@ export default createTestingLibraryRule({ } } + function getErrorMessageId(): MessageIds { + if (customMessage === undefined) { + return 'consistentDataTestId'; + } + + return 'consistentDataTestIdCustomMessage'; + } + return { JSXIdentifier: (node) => { if ( @@ -118,11 +135,12 @@ export default createTestingLibraryRule({ if (value && typeof value === 'string' && !regex.test(value)) { context.report({ node, - messageId: 'consistentDataTestId', + messageId: getErrorMessageId(), data: { attr: node.name, value, regex, + message: customMessage, }, }); } diff --git a/tests/lib/rules/consistent-data-testid.test.ts b/tests/lib/rules/consistent-data-testid.test.ts index cb7487c1..7edaf7c6 100644 --- a/tests/lib/rules/consistent-data-testid.test.ts +++ b/tests/lib/rules/consistent-data-testid.test.ts @@ -283,6 +283,7 @@ const invalidTestCases: InvalidTestCase[] = [ attr: 'data-testid', value: 'Awesome__CoolStuff', regex: '/error/', + message: '', }, }, ], @@ -312,6 +313,7 @@ const invalidTestCases: InvalidTestCase[] = [ attr: 'data-testid', value: 'Nope', regex: '/matchMe/', + message: '', }, }, ], @@ -342,6 +344,7 @@ const invalidTestCases: InvalidTestCase[] = [ attr: 'my-custom-attr', value: 'WrongComponent__cool', regex: '/^Parent(__([A-Z]+[a-z]*?)+)*$/', + message: '', }, }, ], @@ -380,6 +383,7 @@ const invalidTestCases: InvalidTestCase[] = [ attr: 'another-custom-attr', value: 'wrong', regex: '/^right$/', + message: '', }, }, ], @@ -409,6 +413,38 @@ const invalidTestCases: InvalidTestCase[] = [ attr: 'data-testid', value: 'WrongComponent__cool', regex: '/^Parent(__([A-Z]+[a-z]*?)+)*$/', + message: '', + }, + }, + ], + }, + { + code: ` // test for custom message + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^([a-z][a-z0-9]*)(-[a-z0-9]+)*$', //kebab-case + customMessage: 'Please use kebab-cased data-testid values.', + }, + ], + filename: '/my/cool/__tests__/Parent/index.js', + errors: [ + { + messageId: 'consistentDataTestIdCustomMessage', + data: { + attr: 'data-testid', + value: 'snake_case_value', + regex: '^([a-z][a-z0-9]*)(-[a-z0-9]+)*$', + message: 'Please use kebab-cased data-testid values.', }, }, ],