From d3d38b6eefc1cb127910103ce374f98c87ff0584 Mon Sep 17 00:00:00 2001 From: Thomas Knickman Date: Thu, 19 Dec 2019 12:30:45 -0500 Subject: [PATCH 1/5] feat(rule): add data-testid rule --- README.md | 1 + docs/rules/data-testid.md | 46 +++++++ lib/index.js | 1 + lib/rules/data-testid.js | 81 ++++++++++++ tests/lib/rules/data-testid.js | 217 +++++++++++++++++++++++++++++++++ 5 files changed, 346 insertions(+) create mode 100644 docs/rules/data-testid.md create mode 100644 lib/rules/data-testid.js create mode 100644 tests/lib/rules/data-testid.js diff --git a/README.md b/README.md index 190e1159..243ce7be 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ To enable this configuration use the `extends` property in your | [no-dom-import](docs/rules/no-dom-import.md) | Disallow importing from DOM Testing Library | ![angular-badge][] ![react-badge][] ![vue-badge][] | ![fixable-badge][] | | [prefer-expect-query-by](docs/rules/prefer-expect-query-by.md) | Disallow the use of `expect(getBy*)` | ![recommended-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | | | [prefer-explicit-assert](docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than just `getBy*` queries | | | +| [data-testid](docs/rules/data-testid.md) | Ensure `data-testid` values match a provided regex. | | | [build-badge]: https://img.shields.io/travis/Belco90/eslint-plugin-testing-library?style=flat-square [build-url]: https://travis-ci.org/belco90/eslint-plugin-testing-library diff --git a/docs/rules/data-testid.md b/docs/rules/data-testid.md new file mode 100644 index 00000000..96c3a3a8 --- /dev/null +++ b/docs/rules/data-testid.md @@ -0,0 +1,46 @@ +# Enforces consistent naming for the data-testid attribute (data-testid) + +Ensure `data-testid` values match a provided regex. This rule is un-opinionated, and requires configuration. + +## Rule Details + +> Assuming the rule has been configured with the following regex: `^TestId(\_\_[A-Z]*)?$` + +Examples of **incorrect** code for this rule: + +```js +const foo = props =>
...
; +const foo = props =>
...
; +const foo = props =>
...
; +``` + +Examples of **correct** code for this rule: + +```js +const foo = props =>
...
; + +const bar = props =>
...
; + +const baz = props =>
...
; +``` + +## Options + +| Option | Details | Example | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | +| testIdPattern | A regex used to validate the format of the `data-testid` value. `{componentName}` 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 fileName is `index.js` | `'^{componentName}(\_\_([A-Z]+[a-z]_?)+)_\$'` | +| excludePaths | An array of path strings to exclude from the check | `["__tests__"]` | + +## Example + +```json +{ + "testing-library/data-testid": [ + 2, + { + "testIdPattern": "^TestId(__[A-Z]*)?$", + "excludePaths": ["__tests__"] + } + ] +} +``` diff --git a/lib/index.js b/lib/index.js index 21b3cd4d..d2f06bec 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,6 +3,7 @@ const rules = { 'await-async-query': require('./rules/await-async-query'), 'await-fire-event': require('./rules/await-fire-event'), + 'data-testid': require('./rules/data-testid'), 'no-await-sync-query': require('./rules/no-await-sync-query'), 'no-debug': require('./rules/no-debug'), 'no-dom-import': require('./rules/no-dom-import'), diff --git a/lib/rules/data-testid.js b/lib/rules/data-testid.js new file mode 100644 index 00000000..cdc210c8 --- /dev/null +++ b/lib/rules/data-testid.js @@ -0,0 +1,81 @@ +'use strict'; + +module.exports = { + meta: { + docs: { + description: 'Ensures consistent usage of `data-testid`', + category: 'Best Practices', + recommended: false, + }, + messages: { + invalidTestId: '`data-testid` "{{value}}" should match `{{regex}}`', + }, + fixable: null, + schema: [ + { + type: 'object', + additionalProperties: false, + properties: { + testIdPattern: { + type: 'string', + default: '', + }, + excludePaths: { + type: 'array', + items: { type: 'string' }, + default: [], + }, + }, + }, + ], + }, + + create: function(context) { + const { options, getFilename } = context; + const defaultOptions = { testIdPattern: '', excludePaths: [] }; + const ruleOptions = options.length ? options[0] : defaultOptions; + + function getComponentData() { + const splitPath = getFilename().split('/'); + const exclude = ruleOptions.excludePaths.some(path => + splitPath.includes(path) + ); + const fileNameWithExtension = splitPath.pop(); + const parent = splitPath.pop(); + const fileName = fileNameWithExtension.split('.').shift(); + + return { + componentDescriptor: fileName === 'index' ? parent : fileName, + exclude, + }; + } + + function getTestIdValidator({ componentName }) { + return new RegExp( + ruleOptions.testIdPattern.replace('{componentName}', componentName) + ); + } + + return { + 'JSXIdentifier[name=data-testid]': node => { + const { value } = (node && node.parent && node.parent.value) || {}; + const { + componentDescriptor: componentName, + exclude, + } = getComponentData(); + const regex = getTestIdValidator({ componentName }); + + if (!exclude && value && !regex.test(value)) { + context.report({ + node, + messageId: 'invalidTestId', + data: { + value, + regex, + }, + }); + } + }, + }; + }, +}; diff --git a/tests/lib/rules/data-testid.js b/tests/lib/rules/data-testid.js new file mode 100644 index 00000000..a1c9681e --- /dev/null +++ b/tests/lib/rules/data-testid.js @@ -0,0 +1,217 @@ +'use strict'; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/data-testid'); +const RuleTester = require('eslint').RuleTester; + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const parserOptions = { + ecmaVersion: 2018, + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, +}; + +const ruleTester = new RuleTester({ parserOptions }); +ruleTester.run('data-testid', rule, { + valid: [ + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [], + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [{ testIdPattern: 'cool' }], + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [{ testIdPattern: 'cool' }], + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + }, + ], + filename: '/my/cool/file/path/Awesome.js', + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + }, + ], + filename: '/my/cool/file/path/Awesome.js', + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + }, + ], + filename: '/my/cool/file/Parent/index.js', + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + excludePaths: ['__tests__'], + }, + ], + filename: '/my/cool/__tests__/Parent/index.js', + }, + ], + invalid: [ + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [{ testIdPattern: 'error' }], + errors: [ + { + message: '`data-testid` "Awesome__CoolStuff" should match `/error/`', + }, + ], + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: 'matchMe', + excludePaths: ['__mocks__'], + }, + ], + filename: '/my/cool/__tests__/Parent/index.js', + errors: [ + { + message: '`data-testid` "Nope" should match `/matchMe/`', + }, + ], + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + excludePaths: ['__mocks__'], + }, + ], + filename: '/my/cool/__tests__/Parent/index.js', + errors: [ + { + message: + '`data-testid` "WrongComponent__cool" should match `/^Parent(__([A-Z]+[a-z]*?)+)*$/`', + }, + ], + }, + ], +}); From c7aa60f0e957252badd18f0ce48958c07276750f Mon Sep 17 00:00:00 2001 From: Thomas Knickman Date: Fri, 20 Dec 2019 11:00:53 -0500 Subject: [PATCH 2/5] chore(consistent-data-testid): address pr feedback --- README.md | 2 +- ...ta-testid.md => consistent-data-testid.md} | 14 +++----- lib/index.js | 2 +- ...ta-testid.js => consistent-data-testid.js} | 26 ++++---------- ...ta-testid.js => consistent-data-testid.js} | 36 +++++++++++++------ 5 files changed, 40 insertions(+), 40 deletions(-) rename docs/rules/{data-testid.md => consistent-data-testid.md} (60%) rename lib/rules/{data-testid.js => consistent-data-testid.js} (65%) rename tests/lib/rules/{data-testid.js => consistent-data-testid.js} (84%) diff --git a/README.md b/README.md index 243ce7be..a5b2f21b 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ To enable this configuration use the `extends` property in your | [no-dom-import](docs/rules/no-dom-import.md) | Disallow importing from DOM Testing Library | ![angular-badge][] ![react-badge][] ![vue-badge][] | ![fixable-badge][] | | [prefer-expect-query-by](docs/rules/prefer-expect-query-by.md) | Disallow the use of `expect(getBy*)` | ![recommended-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | | | [prefer-explicit-assert](docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than just `getBy*` queries | | | -| [data-testid](docs/rules/data-testid.md) | Ensure `data-testid` values match a provided regex. | | | +| [consistent-data-testid](docs/rules/consistent-data-testid.md) | Ensure `data-testid` values match a provided regex. | | | [build-badge]: https://img.shields.io/travis/Belco90/eslint-plugin-testing-library?style=flat-square [build-url]: https://travis-ci.org/belco90/eslint-plugin-testing-library diff --git a/docs/rules/data-testid.md b/docs/rules/consistent-data-testid.md similarity index 60% rename from docs/rules/data-testid.md rename to docs/rules/consistent-data-testid.md index 96c3a3a8..e56d143f 100644 --- a/docs/rules/data-testid.md +++ b/docs/rules/consistent-data-testid.md @@ -1,4 +1,4 @@ -# Enforces consistent naming for the data-testid attribute (data-testid) +# Enforces consistent naming for the data-testid attribute (consistent-data-testid) Ensure `data-testid` values match a provided regex. This rule is un-opinionated, and requires configuration. @@ -18,18 +18,15 @@ Examples of **correct** code for this rule: ```js const foo = props =>
...
; - const bar = props =>
...
; - const baz = props =>
...
; ``` ## Options -| Option | Details | Example | -| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | -| testIdPattern | A regex used to validate the format of the `data-testid` value. `{componentName}` 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 fileName is `index.js` | `'^{componentName}(\_\_([A-Z]+[a-z]_?)+)_\$'` | -| excludePaths | An array of path strings to exclude from the check | `["__tests__"]` | +| Option | Details | Example | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- | +| testIdPattern | 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 fileName is `index.js` | `'^{fileName}(\_\_([A-Z]+[a-z]_?)+)_\$'` | ## Example @@ -38,8 +35,7 @@ const baz = props =>
...
; "testing-library/data-testid": [ 2, { - "testIdPattern": "^TestId(__[A-Z]*)?$", - "excludePaths": ["__tests__"] + "testIdPattern": "^TestId(__[A-Z]*)?$" } ] } diff --git a/lib/index.js b/lib/index.js index d2f06bec..04a2fb1f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,7 +3,7 @@ const rules = { 'await-async-query': require('./rules/await-async-query'), 'await-fire-event': require('./rules/await-fire-event'), - 'data-testid': require('./rules/data-testid'), + 'consistent-data-testid': require('./rules/consistent-data-testid'), 'no-await-sync-query': require('./rules/no-await-sync-query'), 'no-debug': require('./rules/no-debug'), 'no-dom-import': require('./rules/no-dom-import'), diff --git a/lib/rules/data-testid.js b/lib/rules/consistent-data-testid.js similarity index 65% rename from lib/rules/data-testid.js rename to lib/rules/consistent-data-testid.js index cdc210c8..2c61c775 100644 --- a/lib/rules/data-testid.js +++ b/lib/rules/consistent-data-testid.js @@ -20,11 +20,6 @@ module.exports = { type: 'string', default: '', }, - excludePaths: { - type: 'array', - items: { type: 'string' }, - default: [], - }, }, }, ], @@ -35,37 +30,30 @@ module.exports = { const defaultOptions = { testIdPattern: '', excludePaths: [] }; const ruleOptions = options.length ? options[0] : defaultOptions; - function getComponentData() { + function getFileNameData() { const splitPath = getFilename().split('/'); - const exclude = ruleOptions.excludePaths.some(path => - splitPath.includes(path) - ); const fileNameWithExtension = splitPath.pop(); const parent = splitPath.pop(); const fileName = fileNameWithExtension.split('.').shift(); return { - componentDescriptor: fileName === 'index' ? parent : fileName, - exclude, + fileName: fileName === 'index' ? parent : fileName, }; } - function getTestIdValidator({ componentName }) { + function getTestIdValidator({ fileName }) { return new RegExp( - ruleOptions.testIdPattern.replace('{componentName}', componentName) + ruleOptions.testIdPattern.replace('{fileName}', fileName) ); } return { 'JSXIdentifier[name=data-testid]': node => { const { value } = (node && node.parent && node.parent.value) || {}; - const { - componentDescriptor: componentName, - exclude, - } = getComponentData(); - const regex = getTestIdValidator({ componentName }); + const { fileName } = getFileNameData(); + const regex = getTestIdValidator({ fileName }); - if (!exclude && value && !regex.test(value)) { + if (value && !regex.test(value)) { context.report({ node, messageId: 'invalidTestId', diff --git a/tests/lib/rules/data-testid.js b/tests/lib/rules/consistent-data-testid.js similarity index 84% rename from tests/lib/rules/data-testid.js rename to tests/lib/rules/consistent-data-testid.js index a1c9681e..dadc8149 100644 --- a/tests/lib/rules/data-testid.js +++ b/tests/lib/rules/consistent-data-testid.js @@ -4,7 +4,7 @@ // Requirements // ------------------------------------------------------------------------------ -const rule = require('../../../lib/rules/data-testid'); +const rule = require('../../../lib/rules/consistent-data-testid'); const RuleTester = require('eslint').RuleTester; // ------------------------------------------------------------------------------ @@ -20,7 +20,7 @@ const parserOptions = { }; const ruleTester = new RuleTester({ parserOptions }); -ruleTester.run('data-testid', rule, { +ruleTester.run('consistent-data-testid', rule, { valid: [ { code: ` @@ -78,7 +78,7 @@ ruleTester.run('data-testid', rule, { `, options: [ { - testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + testIdPattern: '^{fileName}(__([A-Z]+[a-z]*?)+)*$', }, ], filename: '/my/cool/file/path/Awesome.js', @@ -97,7 +97,7 @@ ruleTester.run('data-testid', rule, { `, options: [ { - testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + testIdPattern: '^{fileName}(__([A-Z]+[a-z]*?)+)*$', }, ], filename: '/my/cool/file/path/Awesome.js', @@ -116,7 +116,7 @@ ruleTester.run('data-testid', rule, { `, options: [ { - testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', + testIdPattern: '^{fileName}(__([A-Z]+[a-z]*?)+)*$', }, ], filename: '/my/cool/file/Parent/index.js', @@ -135,8 +135,26 @@ ruleTester.run('data-testid', rule, { `, options: [ { - testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', - excludePaths: ['__tests__'], + testIdPattern: '^{fileName}(__([A-Z]+[a-z]*?)+)*$', + }, + ], + filename: '/my/cool/__tests__/Parent/index.js', + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '{fileName}', }, ], filename: '/my/cool/__tests__/Parent/index.js', @@ -177,7 +195,6 @@ ruleTester.run('data-testid', rule, { options: [ { testIdPattern: 'matchMe', - excludePaths: ['__mocks__'], }, ], filename: '/my/cool/__tests__/Parent/index.js', @@ -201,8 +218,7 @@ ruleTester.run('data-testid', rule, { `, options: [ { - testIdPattern: '^{componentName}(__([A-Z]+[a-z]*?)+)*$', - excludePaths: ['__mocks__'], + testIdPattern: '^{fileName}(__([A-Z]+[a-z]*?)+)*$', }, ], filename: '/my/cool/__tests__/Parent/index.js', From 6ebcb4a9b51d09669ac88158f4f60753315f6651 Mon Sep 17 00:00:00 2001 From: Thomas Knickman Date: Mon, 13 Jan 2020 10:59:20 -0500 Subject: [PATCH 3/5] feat(testid): support configurable attribute --- lib/rules/consistent-data-testid.js | 21 +++++--- tests/lib/rules/consistent-data-testid.js | 64 +++++++++++++++++------ 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/lib/rules/consistent-data-testid.js b/lib/rules/consistent-data-testid.js index 2c61c775..6a1ecfa8 100644 --- a/lib/rules/consistent-data-testid.js +++ b/lib/rules/consistent-data-testid.js @@ -1,5 +1,7 @@ 'use strict'; +const FILENAME_PLACEHOLDER = '{fileName}'; + module.exports = { meta: { docs: { @@ -8,17 +10,22 @@ module.exports = { recommended: false, }, messages: { - invalidTestId: '`data-testid` "{{value}}" should match `{{regex}}`', + invalidTestId: '`{{attr}}` "{{value}}" should match `{{regex}}`', }, fixable: null, schema: [ { type: 'object', + default: {}, additionalProperties: false, + required: ['testIdPattern'], properties: { testIdPattern: { type: 'string', - default: '', + }, + testIdAttribute: { + type: 'string', + default: 'data-testid', }, }, }, @@ -27,8 +34,7 @@ module.exports = { create: function(context) { const { options, getFilename } = context; - const defaultOptions = { testIdPattern: '', excludePaths: [] }; - const ruleOptions = options.length ? options[0] : defaultOptions; + const { testIdPattern, testIdAttribute: attr } = options[0]; function getFileNameData() { const splitPath = getFilename().split('/'); @@ -42,13 +48,11 @@ module.exports = { } function getTestIdValidator({ fileName }) { - return new RegExp( - ruleOptions.testIdPattern.replace('{fileName}', fileName) - ); + return new RegExp(testIdPattern.replace(FILENAME_PLACEHOLDER, fileName)); } return { - 'JSXIdentifier[name=data-testid]': node => { + [`JSXIdentifier[name=${attr}]`]: node => { const { value } = (node && node.parent && node.parent.value) || {}; const { fileName } = getFileNameData(); const regex = getTestIdValidator({ fileName }); @@ -58,6 +62,7 @@ module.exports = { node, messageId: 'invalidTestId', data: { + attr, value, regex, }, diff --git a/tests/lib/rules/consistent-data-testid.js b/tests/lib/rules/consistent-data-testid.js index dadc8149..1ab7ff85 100644 --- a/tests/lib/rules/consistent-data-testid.js +++ b/tests/lib/rules/consistent-data-testid.js @@ -22,20 +22,6 @@ const parserOptions = { const ruleTester = new RuleTester({ parserOptions }); ruleTester.run('consistent-data-testid', rule, { valid: [ - { - code: ` - import React from 'react'; - - const TestComponent = props => { - return ( -
- Hello -
- ) - }; - `, - options: [], - }, { code: ` import React from 'react'; @@ -135,7 +121,7 @@ ruleTester.run('consistent-data-testid', rule, { `, options: [ { - testIdPattern: '^{fileName}(__([A-Z]+[a-z]*?)+)*$', + testIdPattern: '{fileName}', }, ], filename: '/my/cool/__tests__/Parent/index.js', @@ -146,7 +132,26 @@ ruleTester.run('consistent-data-testid', rule, { const TestComponent = props => { return ( -
+
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^right(.*)$', + testIdAttribute: 'custom-attr', + }, + ], + }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + return ( +
Hello
) @@ -155,6 +160,7 @@ ruleTester.run('consistent-data-testid', rule, { options: [ { testIdPattern: '{fileName}', + testIdAttribute: 'data-test-id', }, ], filename: '/my/cool/__tests__/Parent/index.js', @@ -208,6 +214,32 @@ ruleTester.run('consistent-data-testid', rule, { code: ` import React from 'react'; + const TestComponent = props => { + return ( +
+ Hello +
+ ) + }; + `, + options: [ + { + testIdPattern: '^{fileName}(__([A-Z]+[a-z]*?)+)*$', + testIdAttribute: 'my-custom-attr', + }, + ], + filename: '/my/cool/__tests__/Parent/index.js', + errors: [ + { + message: + '`my-custom-attr` "WrongComponent__cool" should match `/^Parent(__([A-Z]+[a-z]*?)+)*$/`', + }, + ], + }, + { + code: ` + import React from 'react'; + const TestComponent = props => { return (
From 4dca4f03bf063eeb8a9b8c567373f854580ce306 Mon Sep 17 00:00:00 2001 From: Thomas Knickman Date: Mon, 13 Jan 2020 11:11:35 -0500 Subject: [PATCH 4/5] chore(consistent-data-testid): update docs --- docs/rules/consistent-data-testid.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/rules/consistent-data-testid.md b/docs/rules/consistent-data-testid.md index e56d143f..9ec5589e 100644 --- a/docs/rules/consistent-data-testid.md +++ b/docs/rules/consistent-data-testid.md @@ -24,9 +24,10 @@ const baz = props =>
...
; ## Options -| Option | Details | Example | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- | -| testIdPattern | 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 fileName is `index.js` | `'^{fileName}(\_\_([A-Z]+[a-z]_?)+)_\$'` | +| Option | Required | Default | Details | Example | +| ----------------- | -------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | +| `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` | `^{fileName}(\_\_([A-Z]+[a-z]_?)+)_\$` | +| `testIdAttribute` | No | `data-testid` | A string 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` | ## Example From e171edf42e53480e6c183de1a61af2b7f14ddea2 Mon Sep 17 00:00:00 2001 From: Thomas Knickman Date: Mon, 13 Jan 2020 11:21:24 -0500 Subject: [PATCH 5/5] chore(consistent-data-testid): fix coverage --- lib/rules/consistent-data-testid.js | 3 ++- tests/lib/rules/consistent-data-testid.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/rules/consistent-data-testid.js b/lib/rules/consistent-data-testid.js index 6a1ecfa8..9c06c362 100644 --- a/lib/rules/consistent-data-testid.js +++ b/lib/rules/consistent-data-testid.js @@ -53,7 +53,8 @@ module.exports = { return { [`JSXIdentifier[name=${attr}]`]: node => { - const { value } = (node && node.parent && node.parent.value) || {}; + const value = + node && node.parent && node.parent.value && node.parent.value.value; const { fileName } = getFileNameData(); const regex = getTestIdValidator({ fileName }); diff --git a/tests/lib/rules/consistent-data-testid.js b/tests/lib/rules/consistent-data-testid.js index 1ab7ff85..401995f1 100644 --- a/tests/lib/rules/consistent-data-testid.js +++ b/tests/lib/rules/consistent-data-testid.js @@ -165,6 +165,21 @@ ruleTester.run('consistent-data-testid', rule, { ], filename: '/my/cool/__tests__/Parent/index.js', }, + { + code: ` + import React from 'react'; + + const TestComponent = props => { + const dynamicTestId = 'somethingDynamic'; + return ( +
+ Hello +
+ ) + }; + `, + options: [{ testIdPattern: 'somethingElse' }], + }, ], invalid: [ {