eslint-plugin-jest 23.17.1 → 23.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [23.18.0](https://github.com/jest-community/eslint-plugin-jest/compare/v23.17.1...v23.18.0) (2020-07-05)
2
+
3
+
4
+ ### Features
5
+
6
+ * **valid-title:** support `mustMatch` & `mustNotMatch` options ([#608](https://github.com/jest-community/eslint-plugin-jest/issues/608)) ([4c7207e](https://github.com/jest-community/eslint-plugin-jest/commit/4c7207ebbb274f7b584225ad65ffb96a4328240e)), closes [#233](https://github.com/jest-community/eslint-plugin-jest/issues/233)
7
+
1
8
  ## [23.17.1](https://github.com/jest-community/eslint-plugin-jest/compare/v23.17.0...v23.17.1) (2020-06-23)
2
9
 
3
10
 
@@ -152,9 +152,11 @@ describe('foo', () => {
152
152
  ## Options
153
153
 
154
154
  ```ts
155
- interface {
155
+ interface Options {
156
156
  ignoreTypeOfDescribeName?: boolean;
157
157
  disallowedWords?: string[];
158
+ mustNotMatch?: Partial<Record<'describe' | 'test' | 'it', string>> | string;
159
+ mustMatch?: Partial<Record<'describe' | 'test' | 'it', string>> | string;
158
160
  }
159
161
  ```
160
162
 
@@ -172,7 +174,7 @@ Default: `[]`
172
174
  A string array of words that are not allowed to be used in test titles. Matching
173
175
  is not case-sensitive, and looks for complete words:
174
176
 
175
- Examples of **incorrect** code using `disallowedWords`:
177
+ Examples of **incorrect** code when using `disallowedWords`:
176
178
 
177
179
  ```js
178
180
  // with disallowedWords: ['correct', 'all', 'every', 'properly']
@@ -190,3 +192,37 @@ it('correctly sets the value', () => {});
190
192
  test('that everything is as it should be', () => {});
191
193
  describe('the proper way to handle things', () => {});
192
194
  ```
195
+
196
+ #### `mustMatch` & `mustNotMatch`
197
+
198
+ Defaults: `{}`
199
+
200
+ Allows enforcing that titles must match or must not match a given Regular
201
+ Expression. An object can be provided to apply different Regular Expressions to
202
+ specific Jest test function groups (`describe`, `test`, and `it`).
203
+
204
+ Examples of **incorrect** code when using `mustMatch`:
205
+
206
+ ```js
207
+ // with mustMatch: '$that'
208
+ describe('the correct way to do things', () => {});
209
+ fit('this there!', () => {});
210
+
211
+ // with mustMatch: { test: '$that' }
212
+ describe('the tests that will be run', () => {});
213
+ test('the stuff works', () => {});
214
+ xtest('errors that are thrown have messages', () => {});
215
+ ```
216
+
217
+ Examples of **correct** code when using `mustMatch`:
218
+
219
+ ```js
220
+ // with mustMatch: '$that'
221
+ describe('that thing that needs to be done', () => {});
222
+ fit('that this there!', () => {});
223
+
224
+ // with mustMatch: { test: '$that' }
225
+ describe('the tests that will be run', () => {});
226
+ test('that the stuff works', () => {});
227
+ xtest('that errors that thrown have messages', () => {});
228
+ ```
package/lib/index.js CHANGED
@@ -32,45 +32,28 @@ interopRequireDefault(require(moduleName)).default;
32
32
 
33
33
  const rulesDir = (0, _path.join)(__dirname, 'rules');
34
34
  const excludedFiles = ['__tests__', 'utils'];
35
- const rules = (0, _fs.readdirSync)(rulesDir).map(rule => (0, _path.parse)(rule).name).filter(rule => !excludedFiles.includes(rule)).reduce((acc, curr) => Object.assign(acc, {
35
+ const rules = (0, _fs.readdirSync)(rulesDir).map(rule => (0, _path.parse)(rule).name).filter(rule => !excludedFiles.includes(rule)).reduce((acc, curr) => _objectSpread(_objectSpread({}, acc), {}, {
36
36
  [curr]: importDefault((0, _path.join)(rulesDir, curr))
37
37
  }), {});
38
+ const recommendedRules = Object.entries(rules).filter(([, rule]) => rule.meta.docs.recommended).reduce((acc, [name, rule]) => _objectSpread(_objectSpread({}, acc), {}, {
39
+ [`jest/${name}`]: rule.meta.docs.recommended
40
+ }), {});
38
41
  const allRules = Object.keys(rules).reduce((rules, key) => _objectSpread(_objectSpread({}, rules), {}, {
39
42
  [`jest/${key}`]: 'error'
40
43
  }), {});
44
+
45
+ const createConfig = rules => ({
46
+ plugins: ['jest'],
47
+ env: {
48
+ 'jest/globals': true
49
+ },
50
+ rules
51
+ });
52
+
41
53
  module.exports = {
42
54
  configs: {
43
- all: {
44
- plugins: ['jest'],
45
- env: {
46
- 'jest/globals': true
47
- },
48
- rules: allRules
49
- },
50
- recommended: {
51
- plugins: ['jest'],
52
- env: {
53
- 'jest/globals': true
54
- },
55
- rules: {
56
- 'jest/expect-expect': 'warn',
57
- 'jest/no-commented-out-tests': 'warn',
58
- 'jest/no-disabled-tests': 'warn',
59
- 'jest/no-export': 'error',
60
- 'jest/no-focused-tests': 'error',
61
- 'jest/no-identical-title': 'error',
62
- 'jest/no-jest-import': 'error',
63
- 'jest/no-mocks-import': 'error',
64
- 'jest/no-jasmine-globals': 'warn',
65
- 'jest/no-standalone-expect': 'error',
66
- 'jest/no-test-callback': 'error',
67
- 'jest/no-test-prefixes': 'error',
68
- 'jest/no-try-expect': 'error',
69
- 'jest/valid-describe': 'error',
70
- 'jest/valid-expect': 'error',
71
- 'jest/valid-expect-in-promise': 'error'
72
- }
73
- },
55
+ all: createConfig(allRules),
56
+ recommended: createConfig(recommendedRules),
74
57
  style: {
75
58
  plugins: ['jest'],
76
59
  rules: {
@@ -34,7 +34,7 @@ var _default = (0, _utils.createRule)({
34
34
  docs: {
35
35
  category: 'Best Practices',
36
36
  description: 'Enforce assertion to be made in a test body',
37
- recommended: false
37
+ recommended: 'warn'
38
38
  },
39
39
  messages: {
40
40
  noAssertions: 'Test has no assertions'
@@ -13,7 +13,7 @@ var _default = (0, _utils.createRule)({
13
13
  docs: {
14
14
  category: 'Best Practices',
15
15
  description: 'Disallow alias methods',
16
- recommended: 'warn'
16
+ recommended: false
17
17
  },
18
18
  messages: {
19
19
  replaceAlias: `Replace {{ alias }}() with its canonical name of {{ canonical }}()`
@@ -17,7 +17,7 @@ var _default = (0, _utils.createRule)({
17
17
  docs: {
18
18
  category: 'Best Practices',
19
19
  description: 'Disallow commented out tests',
20
- recommended: false
20
+ recommended: 'warn'
21
21
  },
22
22
  messages: {
23
23
  commentedTests: 'Some tests seem to be commented'
@@ -13,7 +13,7 @@ var _default = (0, _utils.createRule)({
13
13
  docs: {
14
14
  category: 'Best Practices',
15
15
  description: 'Disallow disabled tests',
16
- recommended: false
16
+ recommended: 'warn'
17
17
  },
18
18
  messages: {
19
19
  missingFunction: 'Test is missing function argument',
@@ -15,7 +15,7 @@ var _default = (0, _utils.createRule)({
15
15
  docs: {
16
16
  category: 'Best Practices',
17
17
  description: 'Prevent exporting from test files',
18
- recommended: false
18
+ recommended: 'error'
19
19
  },
20
20
  messages: {
21
21
  unexpectedExport: `Do not export from a test file.`
@@ -26,7 +26,7 @@ var _default = (0, _utils.createRule)({
26
26
  docs: {
27
27
  category: 'Best Practices',
28
28
  description: 'Disallow focused tests',
29
- recommended: false
29
+ recommended: 'error'
30
30
  },
31
31
  messages: {
32
32
  focusedTest: 'Unexpected focused test.'
@@ -15,7 +15,7 @@ var _default = (0, _utils.createRule)({
15
15
  docs: {
16
16
  category: 'Best Practices',
17
17
  description: 'Disallow Jasmine globals',
18
- recommended: 'error'
18
+ recommended: 'warn'
19
19
  },
20
20
  messages: {
21
21
  illegalGlobal: 'Illegal usage of global `{{ global }}`, prefer `{{ replacement }}`',
@@ -46,7 +46,7 @@ var _default = (0, _utils.createRule)({
46
46
  docs: {
47
47
  category: 'Best Practices',
48
48
  description: 'Prevents expects that are outside of an it or test block.',
49
- recommended: false
49
+ recommended: 'error'
50
50
  },
51
51
  messages: {
52
52
  unexpectedExpect: 'Expect must be inside of a test block.'
@@ -15,7 +15,7 @@ var _default = (0, _utils.createRule)({
15
15
  docs: {
16
16
  category: 'Best Practices',
17
17
  description: 'Avoid using a callback in asynchronous tests',
18
- recommended: false,
18
+ recommended: 'error',
19
19
  suggestion: true
20
20
  },
21
21
  messages: {
@@ -13,7 +13,7 @@ var _default = (0, _utils.createRule)({
13
13
  docs: {
14
14
  description: 'Prefer using toThrow for exception tests',
15
15
  category: 'Best Practices',
16
- recommended: false
16
+ recommended: 'error'
17
17
  },
18
18
  deprecated: true,
19
19
  replacedBy: ['no-conditional-expect'],
@@ -25,7 +25,7 @@ var _default = (0, _utils.createRule)({
25
25
  docs: {
26
26
  category: 'Possible Errors',
27
27
  description: 'Enforce valid `describe()` callback',
28
- recommended: 'warn'
28
+ recommended: 'error'
29
29
  },
30
30
  messages: {
31
31
  nameAndCallback: 'Describe requires name and callback arguments',
@@ -25,6 +25,23 @@ const doesBinaryExpressionContainStringNode = binaryExp => {
25
25
 
26
26
  const quoteStringValue = node => node.type === _experimentalUtils.AST_NODE_TYPES.TemplateLiteral ? `\`${node.quasis[0].value.raw}\`` : node.raw;
27
27
 
28
+ const compileMatcherPatterns = matchers => {
29
+ if (typeof matchers === 'string') {
30
+ const matcher = new RegExp(matchers, 'u');
31
+ return {
32
+ describe: matcher,
33
+ test: matcher,
34
+ it: matcher
35
+ };
36
+ }
37
+
38
+ return {
39
+ describe: matchers.describe ? new RegExp(matchers.describe, 'u') : null,
40
+ test: matchers.test ? new RegExp(matchers.test, 'u') : null,
41
+ it: matchers.it ? new RegExp(matchers.it, 'u') : null
42
+ };
43
+ };
44
+
28
45
  var _default = (0, _utils.createRule)({
29
46
  name: __filename,
30
47
  meta: {
@@ -38,7 +55,9 @@ var _default = (0, _utils.createRule)({
38
55
  emptyTitle: '{{ jestFunctionName }} should not have an empty title',
39
56
  duplicatePrefix: 'should not have duplicate prefix',
40
57
  accidentalSpace: 'should not have leading or trailing spaces',
41
- disallowedWord: '"{{ word }}" is not allowed in test titles.'
58
+ disallowedWord: '"{{ word }}" is not allowed in test titles.',
59
+ mustNotMatch: '{{ jestFunctionName }} should not match {{ pattern }}',
60
+ mustMatch: '{{ jestFunctionName }} should match {{ pattern }}'
42
61
  },
43
62
  type: 'suggestion',
44
63
  schema: [{
@@ -53,6 +72,44 @@ var _default = (0, _utils.createRule)({
53
72
  items: {
54
73
  type: 'string'
55
74
  }
75
+ },
76
+ mustNotMatch: {
77
+ oneOf: [{
78
+ type: 'string'
79
+ }, {
80
+ type: 'object',
81
+ properties: {
82
+ describe: {
83
+ type: 'string'
84
+ },
85
+ test: {
86
+ type: 'string'
87
+ },
88
+ it: {
89
+ type: 'string'
90
+ }
91
+ },
92
+ additionalProperties: false
93
+ }]
94
+ },
95
+ mustMatch: {
96
+ oneOf: [{
97
+ type: 'string'
98
+ }, {
99
+ type: 'object',
100
+ properties: {
101
+ describe: {
102
+ type: 'string'
103
+ },
104
+ test: {
105
+ type: 'string'
106
+ },
107
+ it: {
108
+ type: 'string'
109
+ }
110
+ },
111
+ additionalProperties: false
112
+ }]
56
113
  }
57
114
  },
58
115
  additionalProperties: false
@@ -66,9 +123,13 @@ var _default = (0, _utils.createRule)({
66
123
 
67
124
  create(context, [{
68
125
  ignoreTypeOfDescribeName,
69
- disallowedWords = []
126
+ disallowedWords = [],
127
+ mustNotMatch,
128
+ mustMatch
70
129
  }]) {
71
130
  const disallowedWordsRegexp = new RegExp(`\\b(${disallowedWords.join('|')})\\b`, 'iu');
131
+ const mustNotMatchPatterns = compileMatcherPatterns(mustNotMatch !== null && mustNotMatch !== void 0 ? mustNotMatch : {});
132
+ const mustMatchPatterns = compileMatcherPatterns(mustMatch !== null && mustMatch !== void 0 ? mustMatch : {});
72
133
  return {
73
134
  CallExpression(node) {
74
135
  if (!(0, _utils.isDescribe)(node) && !(0, _utils.isTestCase)(node)) {
@@ -142,6 +203,39 @@ var _default = (0, _utils.createRule)({
142
203
  fix: fixer => [fixer.replaceTextRange(argument.range, quoteStringValue(argument).replace(/^([`'"]).+? /u, '$1'))]
143
204
  });
144
205
  }
206
+
207
+ const [jestFunctionName] = nodeName.split('.');
208
+ const mustNotMatchPattern = mustNotMatchPatterns[jestFunctionName];
209
+
210
+ if (mustNotMatchPattern) {
211
+ if (mustNotMatchPattern.test(title)) {
212
+ context.report({
213
+ messageId: 'mustNotMatch',
214
+ node: argument,
215
+ data: {
216
+ jestFunctionName,
217
+ pattern: mustNotMatchPattern
218
+ }
219
+ });
220
+ return;
221
+ }
222
+ }
223
+
224
+ const mustMatchPattern = mustMatchPatterns[jestFunctionName];
225
+
226
+ if (mustMatchPattern) {
227
+ if (!mustMatchPattern.test(title)) {
228
+ context.report({
229
+ messageId: 'mustMatch',
230
+ node: argument,
231
+ data: {
232
+ jestFunctionName,
233
+ pattern: mustMatchPattern
234
+ }
235
+ });
236
+ return;
237
+ }
238
+ }
145
239
  }
146
240
 
147
241
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-jest",
3
- "version": "23.17.1",
3
+ "version": "23.18.0",
4
4
  "description": "Eslint rules for Jest",
5
5
  "keywords": [
6
6
  "eslint",
@@ -23,10 +23,8 @@
23
23
  "build": "babel --extensions .js,.ts src --out-dir lib --copy-files",
24
24
  "postbuild": "rimraf lib/__tests__ lib/**/__tests__",
25
25
  "lint": "eslint . --ignore-pattern '!.eslintrc.js' --ext js,ts",
26
- "prepare": "yarn build && yarn postbuild",
27
- "prepublishOnly": "yarn build",
26
+ "prepack": "yarn build",
28
27
  "prettylint": "prettylint docs/**/*.md README.md package.json",
29
- "pretest": "yarn build",
30
28
  "test": "jest",
31
29
  "tools:generate-rules-table": "ts-node -T tools/generate-rules-table",
32
30
  "typecheck": "tsc -p ."
@@ -120,7 +118,7 @@
120
118
  "eslint-plugin-prettier": "^3.0.0",
121
119
  "husky": "^3.0.9",
122
120
  "jest": "^25.2.0",
123
- "jest-runner-eslint": "^0.9.0",
121
+ "jest-runner-eslint": "^0.10.0",
124
122
  "lint-staged": "^9.4.2",
125
123
  "prettier": "^1.19.1",
126
124
  "prettylint": "^1.0.0",