source: frontend/node_modules/eslint-plugin-jest/lib/rules/valid-title.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 13 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.4 KB
RevLine 
[9af201e]1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _experimentalUtils = require("@typescript-eslint/experimental-utils");
9
10var _utils = require("./utils");
11
12const trimFXprefix = word => ['f', 'x'].includes(word.charAt(0)) ? word.substr(1) : word;
13
14const doesBinaryExpressionContainStringNode = binaryExp => {
15 if ((0, _utils.isStringNode)(binaryExp.right)) {
16 return true;
17 }
18
19 if (binaryExp.left.type === _experimentalUtils.AST_NODE_TYPES.BinaryExpression) {
20 return doesBinaryExpressionContainStringNode(binaryExp.left);
21 }
22
23 return (0, _utils.isStringNode)(binaryExp.left);
24};
25
26const quoteStringValue = node => node.type === _experimentalUtils.AST_NODE_TYPES.TemplateLiteral ? `\`${node.quasis[0].value.raw}\`` : node.raw;
27
28const compileMatcherPattern = matcherMaybeWithMessage => {
29 const [matcher, message] = Array.isArray(matcherMaybeWithMessage) ? matcherMaybeWithMessage : [matcherMaybeWithMessage];
30 return [new RegExp(matcher, 'u'), message];
31};
32
33const compileMatcherPatterns = matchers => {
34 if (typeof matchers === 'string' || Array.isArray(matchers)) {
35 const compiledMatcher = compileMatcherPattern(matchers);
36 return {
37 describe: compiledMatcher,
38 test: compiledMatcher,
39 it: compiledMatcher
40 };
41 }
42
43 return {
44 describe: matchers.describe ? compileMatcherPattern(matchers.describe) : null,
45 test: matchers.test ? compileMatcherPattern(matchers.test) : null,
46 it: matchers.it ? compileMatcherPattern(matchers.it) : null
47 };
48};
49
50const MatcherAndMessageSchema = {
51 type: 'array',
52 items: {
53 type: 'string'
54 },
55 minItems: 1,
56 maxItems: 2,
57 additionalItems: false
58};
59
60var _default = (0, _utils.createRule)({
61 name: __filename,
62 meta: {
63 docs: {
64 category: 'Best Practices',
65 description: 'Enforce valid titles',
66 recommended: 'error'
67 },
68 messages: {
69 titleMustBeString: 'Title must be a string',
70 emptyTitle: '{{ jestFunctionName }} should not have an empty title',
71 duplicatePrefix: 'should not have duplicate prefix',
72 accidentalSpace: 'should not have leading or trailing spaces',
73 disallowedWord: '"{{ word }}" is not allowed in test titles.',
74 mustNotMatch: '{{ jestFunctionName }} should not match {{ pattern }}',
75 mustMatch: '{{ jestFunctionName }} should match {{ pattern }}',
76 mustNotMatchCustom: '{{ message }}',
77 mustMatchCustom: '{{ message }}'
78 },
79 type: 'suggestion',
80 schema: [{
81 type: 'object',
82 properties: {
83 ignoreTypeOfDescribeName: {
84 type: 'boolean',
85 default: false
86 },
87 disallowedWords: {
88 type: 'array',
89 items: {
90 type: 'string'
91 }
92 }
93 },
94 patternProperties: {
95 [/^must(?:Not)?Match$/u.source]: {
96 oneOf: [{
97 type: 'string'
98 }, MatcherAndMessageSchema, {
99 type: 'object',
100 propertyNames: {
101 enum: ['describe', 'test', 'it']
102 },
103 additionalProperties: {
104 oneOf: [{
105 type: 'string'
106 }, MatcherAndMessageSchema]
107 }
108 }]
109 }
110 },
111 additionalProperties: false
112 }],
113 fixable: 'code'
114 },
115 defaultOptions: [{
116 ignoreTypeOfDescribeName: false,
117 disallowedWords: []
118 }],
119
120 create(context, [{
121 ignoreTypeOfDescribeName,
122 disallowedWords = [],
123 mustNotMatch,
124 mustMatch
125 }]) {
126 const disallowedWordsRegexp = new RegExp(`\\b(${disallowedWords.join('|')})\\b`, 'iu');
127 const mustNotMatchPatterns = compileMatcherPatterns(mustNotMatch !== null && mustNotMatch !== void 0 ? mustNotMatch : {});
128 const mustMatchPatterns = compileMatcherPatterns(mustMatch !== null && mustMatch !== void 0 ? mustMatch : {});
129 return {
130 CallExpression(node) {
131 var _mustNotMatchPatterns, _mustMatchPatterns$je;
132
133 if (!(0, _utils.isDescribeCall)(node) && !(0, _utils.isTestCaseCall)(node)) {
134 return;
135 }
136
137 const [argument] = node.arguments;
138
139 if (!argument) {
140 return;
141 }
142
143 if (!(0, _utils.isStringNode)(argument)) {
144 if (argument.type === _experimentalUtils.AST_NODE_TYPES.BinaryExpression && doesBinaryExpressionContainStringNode(argument)) {
145 return;
146 }
147
148 if (argument.type !== _experimentalUtils.AST_NODE_TYPES.TemplateLiteral && !(ignoreTypeOfDescribeName && (0, _utils.isDescribeCall)(node))) {
149 context.report({
150 messageId: 'titleMustBeString',
151 loc: argument.loc
152 });
153 }
154
155 return;
156 }
157
158 const title = (0, _utils.getStringValue)(argument);
159
160 if (!title) {
161 context.report({
162 messageId: 'emptyTitle',
163 data: {
164 jestFunctionName: (0, _utils.isDescribeCall)(node) ? _utils.DescribeAlias.describe : _utils.TestCaseName.test
165 },
166 node
167 });
168 return;
169 }
170
171 if (disallowedWords.length > 0) {
172 const disallowedMatch = disallowedWordsRegexp.exec(title);
173
174 if (disallowedMatch) {
175 context.report({
176 data: {
177 word: disallowedMatch[1]
178 },
179 messageId: 'disallowedWord',
180 node: argument
181 });
182 return;
183 }
184 }
185
186 if (title.trim().length !== title.length) {
187 context.report({
188 messageId: 'accidentalSpace',
189 node: argument,
190 fix: fixer => [fixer.replaceTextRange(argument.range, quoteStringValue(argument).replace(/^([`'"]) +?/u, '$1').replace(/ +?([`'"])$/u, '$1'))]
191 });
192 }
193
194 const nodeName = trimFXprefix((0, _utils.getNodeName)(node));
195 const [firstWord] = title.split(' ');
196
197 if (firstWord.toLowerCase() === nodeName) {
198 context.report({
199 messageId: 'duplicatePrefix',
200 node: argument,
201 fix: fixer => [fixer.replaceTextRange(argument.range, quoteStringValue(argument).replace(/^([`'"]).+? /u, '$1'))]
202 });
203 }
204
205 const [jestFunctionName] = nodeName.split('.');
206 const [mustNotMatchPattern, mustNotMatchMessage] = (_mustNotMatchPatterns = mustNotMatchPatterns[jestFunctionName]) !== null && _mustNotMatchPatterns !== void 0 ? _mustNotMatchPatterns : [];
207
208 if (mustNotMatchPattern) {
209 if (mustNotMatchPattern.test(title)) {
210 context.report({
211 messageId: mustNotMatchMessage ? 'mustNotMatchCustom' : 'mustNotMatch',
212 node: argument,
213 data: {
214 jestFunctionName,
215 pattern: mustNotMatchPattern,
216 message: mustNotMatchMessage
217 }
218 });
219 return;
220 }
221 }
222
223 const [mustMatchPattern, mustMatchMessage] = (_mustMatchPatterns$je = mustMatchPatterns[jestFunctionName]) !== null && _mustMatchPatterns$je !== void 0 ? _mustMatchPatterns$je : [];
224
225 if (mustMatchPattern) {
226 if (!mustMatchPattern.test(title)) {
227 context.report({
228 messageId: mustMatchMessage ? 'mustMatchCustom' : 'mustMatch',
229 node: argument,
230 data: {
231 jestFunctionName,
232 pattern: mustMatchPattern,
233 message: mustMatchMessage
234 }
235 });
236 return;
237 }
238 }
239 }
240
241 };
242 }
243
244});
245
246exports.default = _default;
Note: See TracBrowser for help on using the repository browser.