eslint-plugin-jest-formatting 0.1.0 → 1.2.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.
Files changed (39) hide show
  1. package/.eslintrc +5 -5
  2. package/CHANGELOG.md +28 -6
  3. package/README.md +29 -9
  4. package/docs/rules/padding-around-after-all-blocks.md +25 -0
  5. package/docs/rules/padding-around-after-each-blocks.md +29 -0
  6. package/docs/rules/padding-around-all.md +13 -0
  7. package/docs/rules/padding-around-before-all-blocks.md +29 -0
  8. package/docs/rules/padding-around-before-each-blocks.md +29 -0
  9. package/docs/rules/padding-around-describe-blocks.md +33 -0
  10. package/docs/rules/padding-around-expect-groups.md +35 -0
  11. package/docs/rules/padding-around-test-blocks.md +39 -0
  12. package/lib/ast-utils.js +40 -0
  13. package/lib/index.js +238 -38
  14. package/lib/rules/padding.js +130 -158
  15. package/package.json +4 -2
  16. package/src/ast-utils.ts +78 -0
  17. package/src/index.ts +282 -43
  18. package/src/rules/padding.ts +261 -252
  19. package/tests/catfood.js +39 -0
  20. package/tests/dogfood.spec.js +16 -1
  21. package/tests/lib/ast-utils.spec.ts +94 -0
  22. package/tests/lib/rules/padding-around-after-all-blocks.spec.js +114 -0
  23. package/tests/lib/rules/padding-around-after-each-blocks.spec.js +112 -0
  24. package/tests/lib/rules/padding-around-before-all-blocks.spec.js +114 -0
  25. package/tests/lib/rules/padding-around-before-each-blocks.spec.js +114 -0
  26. package/tests/lib/rules/padding-around-describe-blocks.spec.js +152 -0
  27. package/tests/lib/rules/padding-around-expect-groups.spec.js +154 -0
  28. package/tests/lib/rules/padding-around-test-blocks.spec.js +161 -0
  29. package/tests/lib/rules/padding-before-after-all-blocks.spec.js +1 -7
  30. package/tests/lib/rules/padding-before-after-each-blocks.spec.js +1 -7
  31. package/tests/lib/rules/padding-before-before-all-blocks.spec.js +1 -7
  32. package/tests/lib/rules/padding-before-before-each-blocks.spec.js +1 -7
  33. package/tests/lib/rules/padding-before-describe-blocks.spec.js +1 -7
  34. package/tests/lib/rules/padding-before-expect-statements.spec.js +1 -7
  35. package/tests/lib/rules/padding-before-test-blocks.spec.js +1 -7
  36. package/tsconfig.json +1 -1
  37. package/yarn.lock +12 -10
  38. package/lib/utils.js +0 -15
  39. package/src/utils.ts +0 -40
@@ -1,115 +1,142 @@
1
1
  /**
2
- * @fileoverview Rule to require or disallow newlines between jest functions
3
- * Based on eslint/padding-line-between-statements by Toru Nagashima
4
- * See: https://github.com/eslint/eslint/blob/master/lib/rules/padding-line-between-statements.js
2
+ * Require/fix newlines around jest functions
5
3
  *
6
- * STATEMENT_LIST_PARENTS, isTokenOnSameLine and isSemiColonToken borrowed from
7
- * eslint ast-utils by Gyandeep Singh
8
- * See: https://github.com/eslint/eslint/blob/master/lib/rules/utils/ast-utils.js
4
+ * Based on eslint/padding-line-between-statements by Toru Nagashima
5
+ * See: https://github.com/eslint/eslint/blob/master/lib/rules/padding-line-between-statements.js
6
+ *
7
+ * Some helpers borrowed from eslint ast-utils by Gyandeep Singh
8
+ * See: https://github.com/eslint/eslint/blob/master/lib/rules/utils/ast-utils.js
9
9
  */
10
+
10
11
  import { AST, Rule, SourceCode } from 'eslint';
11
12
  import { Node } from 'estree';
13
+ import * as astUtils from '../ast-utils';
14
+
15
+ // Statement types we'll respond to
16
+ export const enum StatementType {
17
+ Any,
18
+ AfterAllToken,
19
+ AfterEachToken,
20
+ BeforeAllToken,
21
+ BeforeEachToken,
22
+ DescribeToken,
23
+ ExpectToken,
24
+ FdescribeToken,
25
+ FitToken,
26
+ ItToken,
27
+ TestToken,
28
+ XdescribeToken,
29
+ XitToken,
30
+ XtestToken,
31
+ }
12
32
 
13
- type StatementTypeTester = {
14
- [test: string]: (node: Node, sourceCode: SourceCode) => boolean;
15
- };
33
+ type StatementTypes = StatementType | StatementType[];
16
34
 
17
- type PaddingTypeTester = {
18
- [verify: string]: (
19
- context: Rule.RuleContext,
20
- prevNode: Node,
21
- nextNode: Node,
22
- paddingLines: AST.Token[][],
23
- ) => void;
24
- };
35
+ type StatementTester = (node: Node, sourceCode: SourceCode) => boolean;
25
36
 
26
- const STATEMENT_LIST_PARENTS = new Set([
27
- 'Program',
28
- 'BlockStatement',
29
- 'SwitchCase',
30
- 'SwitchStatement',
31
- ]);
37
+ // Padding type to apply between statements
38
+ export const enum PaddingType {
39
+ Any,
40
+ Always,
41
+ }
32
42
 
33
- const isTokenOnSameLine = (
34
- left: Node | AST.Token,
35
- right: Node | AST.Token,
36
- ): boolean => left.loc.end.line === right.loc.start.line;
43
+ type PaddingTester = (
44
+ prevNode: Node,
45
+ nextNode: Node,
46
+ paddingContext: PaddingContext,
47
+ ) => void;
48
+
49
+ // A configuration object for padding type and the two statement types
50
+ export interface Config {
51
+ paddingType: PaddingType;
52
+ prevStatementType: StatementTypes;
53
+ nextStatementType: StatementTypes;
54
+ }
37
55
 
38
- const isSemicolonToken = (token: AST.Token): boolean =>
39
- token.value === ';' && token.type === 'Punctuator';
56
+ // Tracks position in scope and prevNode. Used to compare current and prev node
57
+ // and then to walk back up to the parent scope or down into the next one.
58
+ // And so on...
59
+ interface Scope {
60
+ upper: Scope | null;
61
+ prevNode: Node | null;
62
+ }
40
63
 
41
- // NOTE: Should probably be configurable
42
- const isTestFile = (filename: string): boolean =>
43
- filename.includes('test') || filename.includes('spec');
64
+ interface ScopeInfo {
65
+ prevNode: Node | null;
66
+ enter: () => void;
67
+ exit: () => void;
68
+ }
44
69
 
45
- /**
46
- * Creates tester which check if an expression node has a certain name
47
- */
48
- function newJestTokenTester(name: string): StatementTypeTester {
49
- return {
50
- test: (node: Node, sourceCode: SourceCode): boolean => {
51
- const token = sourceCode.getFirstToken(node);
52
-
53
- return (
54
- node.type === 'ExpressionStatement' &&
55
- token.type === 'Identifier' &&
56
- token.value === name
57
- );
58
- },
59
- };
70
+ interface PaddingContext {
71
+ ruleContext: Rule.RuleContext;
72
+ sourceCode: SourceCode;
73
+ scopeInfo: ScopeInfo;
74
+ configs: Config[];
60
75
  }
61
76
 
62
- /**
63
- * Gets the actual last token.
64
- *
65
- * If a semicolon is semicolon-less style's semicolon, this ignores it.
66
- * For example:
67
- *
68
- * foo()
69
- * ;[1, 2, 3].forEach(bar)
70
- */
71
- function getActualLastToken(sourceCode: SourceCode, node: Node): AST.Token {
72
- const semiToken = sourceCode.getLastToken(node);
73
- const prevToken = sourceCode.getTokenBefore(semiToken);
74
- const nextToken = sourceCode.getTokenAfter(semiToken);
75
- const isSemicolonLessStyle = Boolean(
76
- prevToken &&
77
- nextToken &&
78
- prevToken.range[0] >= node.range[0] &&
79
- isSemicolonToken(semiToken) &&
80
- semiToken.loc.start.line !== prevToken.loc.end.line &&
81
- semiToken.loc.end.line === nextToken.loc.start.line,
82
- );
77
+ // Creates a StatementTester to test an ExpressionStatement's first token name
78
+ const createTokenTester = (tokenName: string): StatementTester => {
79
+ return (node: Node, sourceCode: SourceCode): boolean => {
80
+ const token = sourceCode.getFirstToken(node);
83
81
 
84
- return isSemicolonLessStyle ? prevToken : semiToken;
85
- }
82
+ return (
83
+ node.type === 'ExpressionStatement' &&
84
+ token.type === 'Identifier' &&
85
+ token.value === tokenName
86
+ );
87
+ };
88
+ };
89
+
90
+ // A mapping of StatementType to StatementTester for... testing statements
91
+ const statementTesters: { [T in StatementType]: StatementTester } = {
92
+ [StatementType.Any]: () => true,
93
+ [StatementType.AfterAllToken]: createTokenTester('afterAll'),
94
+ [StatementType.AfterEachToken]: createTokenTester('afterEach'),
95
+ [StatementType.BeforeAllToken]: createTokenTester('beforeAll'),
96
+ [StatementType.BeforeEachToken]: createTokenTester('beforeEach'),
97
+ [StatementType.DescribeToken]: createTokenTester('describe'),
98
+ [StatementType.ExpectToken]: createTokenTester('expect'),
99
+ [StatementType.FdescribeToken]: createTokenTester('fdescribe'),
100
+ [StatementType.FitToken]: createTokenTester('fit'),
101
+ [StatementType.ItToken]: createTokenTester('it'),
102
+ [StatementType.TestToken]: createTokenTester('test'),
103
+ [StatementType.XdescribeToken]: createTokenTester('xdescribe'),
104
+ [StatementType.XitToken]: createTokenTester('xit'),
105
+ [StatementType.XtestToken]: createTokenTester('xtest'),
106
+ };
86
107
 
87
108
  /**
88
- * Check and report statements for `always` configuration.
109
+ * Check and report statements for `PaddingType.Always` configuration.
89
110
  * This autofix inserts a blank line between the given 2 statements.
90
111
  * If the `prevNode` has trailing comments, it inserts a blank line after the
91
112
  * trailing comments.
92
113
  */
93
- function verifyForAlways(
94
- context: Rule.RuleContext,
114
+ const paddingAlwaysTester = (
95
115
  prevNode: Node,
96
116
  nextNode: Node,
97
- paddingLines: AST.Token[],
98
- ): void {
117
+ paddingContext: PaddingContext,
118
+ ): void => {
119
+ const { sourceCode, ruleContext } = paddingContext;
120
+ const paddingLines = astUtils.getPaddingLineSequences(
121
+ prevNode,
122
+ nextNode,
123
+ sourceCode,
124
+ );
125
+
126
+ // We've got some padding lines. Great.
99
127
  if (paddingLines.length > 0) {
100
128
  return;
101
129
  }
102
130
 
103
- context.report({
131
+ // Missing padding line
132
+ ruleContext.report({
104
133
  node: nextNode,
105
134
  message: 'Expected blank line before this statement.',
106
135
  fix(fixer: Rule.RuleFixer): Rule.Fix {
107
- const sourceCode = context.getSourceCode();
108
- let prevToken = getActualLastToken(sourceCode, prevNode);
136
+ let prevToken = astUtils.getActualLastToken(sourceCode, prevNode);
109
137
  const nextToken =
110
138
  sourceCode.getFirstTokenBetween(prevToken, nextNode, {
111
139
  includeComments: true,
112
-
113
140
  /**
114
141
  * Skip the trailing comments of the previous node.
115
142
  * This inserts a blank line after the last trailing comment.
@@ -128,7 +155,7 @@ function verifyForAlways(
128
155
  * bar();
129
156
  */
130
157
  filter(token: AST.Token): boolean {
131
- if (isTokenOnSameLine(prevToken, token)) {
158
+ if (astUtils.areTokensOnSameLine(prevToken, token)) {
132
159
  prevToken = token;
133
160
  return false;
134
161
  }
@@ -137,203 +164,185 @@ function verifyForAlways(
137
164
  },
138
165
  }) || nextNode;
139
166
 
140
- const insertText = isTokenOnSameLine(prevToken, nextToken)
167
+ const insertText = astUtils.areTokensOnSameLine(prevToken, nextToken)
141
168
  ? '\n\n'
142
169
  : '\n';
143
170
 
144
171
  return fixer.insertTextAfter(prevToken, insertText);
145
172
  },
146
173
  });
147
- }
148
-
149
- /**
150
- * Types of blank lines.
151
- * `any` and `always` are defined.
152
- * Those have `verify` method to check and report statements.
153
- */
154
- const PaddingTypes = {
155
- any: { verify: () => {} },
156
- always: { verify: verifyForAlways },
157
174
  };
158
175
 
159
- /**
160
- * Types of statements.
161
- * Those have `test` method to check it matches to the given statement.
162
- */
163
- const StatementTypes = {
164
- '*': { test: () => true },
165
- afterAll: newJestTokenTester('afterAll'),
166
- afterEach: newJestTokenTester('afterEach'),
167
- beforeAll: newJestTokenTester('beforeAll'),
168
- beforeEach: newJestTokenTester('beforeEach'),
169
- describe: newJestTokenTester('describe'),
170
- expect: newJestTokenTester('expect'),
171
- it: newJestTokenTester('it'),
172
- test: newJestTokenTester('test'),
176
+ // A mapping of PaddingType to PaddingTester
177
+ const paddingTesters: { [T in PaddingType]: PaddingTester } = {
178
+ [PaddingType.Any]: () => true,
179
+ [PaddingType.Always]: paddingAlwaysTester,
173
180
  };
174
181
 
175
- //------------------------------------------------------------------------------
176
- // Rule Definition
177
- //------------------------------------------------------------------------------
182
+ const createScopeInfo = (): ScopeInfo => {
183
+ return (() => {
184
+ let scope: Scope = null;
178
185
 
179
- export default <Rule.RuleModule>{
180
- meta: {
181
- fixable: 'whitespace',
182
- schema: {
183
- definitions: {
184
- paddingType: {
185
- enum: Object.keys(PaddingTypes),
186
- },
187
- statementType: {
188
- anyOf: [
189
- { enum: Object.keys(StatementTypes) },
190
- {
191
- type: 'array',
192
- items: { enum: Object.keys(StatementTypes) },
193
- minItems: 1,
194
- uniqueItems: true,
195
- additionalItems: false,
196
- },
197
- ],
198
- },
186
+ return {
187
+ get prevNode() {
188
+ return scope.prevNode;
199
189
  },
200
- type: 'array',
201
- items: {
202
- type: 'object',
203
- properties: {
204
- blankLine: { $ref: '#/definitions/paddingType' },
205
- prev: { $ref: '#/definitions/statementType' },
206
- next: { $ref: '#/definitions/statementType' },
207
- },
208
- additionalProperties: false,
209
- required: ['blankLine', 'prev', 'next'],
190
+ set prevNode(node) {
191
+ scope.prevNode = node;
210
192
  },
211
- additionalItems: false,
212
- },
213
- },
214
- create(context: Rule.RuleContext): Rule.RuleListener {
215
- const filename = context.getFilename();
216
-
217
- if (!isTestFile(filename)) {
218
- return {};
219
- }
220
-
221
- const sourceCode = context.getSourceCode();
222
- const configureList = context.options || [];
223
- let scopeInfo = null;
224
-
225
- function enterScope(): void {
226
- scopeInfo = { upper: scopeInfo, prevNode: null };
227
- }
228
-
229
- function exitScope(): void {
230
- scopeInfo = scopeInfo.upper;
231
- }
232
-
233
- /**
234
- * Checks whether the given node matches the given type.
235
- */
236
- function match(node: Node, type: string | string[]): boolean {
237
- let innerStatementNode = node;
238
-
239
- while (innerStatementNode.type === 'LabeledStatement') {
240
- innerStatementNode = innerStatementNode.body;
241
- }
242
-
243
- if (Array.isArray(type)) {
244
- return type.some(match.bind(null, innerStatementNode));
245
- }
246
-
247
- return StatementTypes[type].test(innerStatementNode, sourceCode);
248
- }
193
+ enter() {
194
+ scope = { upper: scope, prevNode: null };
195
+ },
196
+ exit() {
197
+ scope = scope.upper;
198
+ },
199
+ };
200
+ })();
201
+ };
249
202
 
250
- /**
251
- * Finds the last matched configure from configureList.
252
- */
253
- function getPaddingType(prevNode: Node, nextNode: Node): PaddingTypeTester {
254
- for (let i = configureList.length - 1; i >= 0; --i) {
255
- const { prev, next, blankLine } = configureList[i];
203
+ /**
204
+ * Check whether the given node matches the statement type
205
+ */
206
+ const nodeMatchesType = (
207
+ node: Node,
208
+ statementType: StatementTypes,
209
+ paddingContext: PaddingContext,
210
+ ): boolean => {
211
+ let innerStatementNode = node;
212
+ const { sourceCode } = paddingContext;
213
+
214
+ // Dig into LabeledStatement body until it's not that anymore
215
+ while (innerStatementNode.type === 'LabeledStatement') {
216
+ innerStatementNode = innerStatementNode.body;
217
+ }
256
218
 
257
- if (match(prevNode, prev) && match(nextNode, next)) {
258
- return PaddingTypes[blankLine];
259
- }
260
- }
219
+ // If it's an array recursively check if any of the statement types match
220
+ // the node
221
+ if (Array.isArray(statementType)) {
222
+ return statementType.some(type =>
223
+ nodeMatchesType(innerStatementNode, type, paddingContext),
224
+ );
225
+ }
261
226
 
262
- return PaddingTypes.any;
263
- }
227
+ return statementTesters[statementType](innerStatementNode, sourceCode);
228
+ };
264
229
 
265
- /**
266
- * Gets padding line sequences between the given 2 statements.
267
- * Comments are separators of the padding line sequences.
268
- */
269
- function getPaddingLineSequences(
270
- prevNode: Node,
271
- nextNode: Node,
272
- ): AST.Token[][] {
273
- const pairs: AST.Token[][] = [];
274
- let prevToken = getActualLastToken(sourceCode, prevNode);
275
-
276
- if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
277
- do {
278
- const token = sourceCode.getTokenAfter(prevToken, {
279
- includeComments: true,
280
- });
281
-
282
- if (token.loc.start.line - prevToken.loc.end.line >= 2) {
283
- pairs.push([prevToken, token]);
284
- }
285
-
286
- prevToken = token;
287
- } while (prevToken.range[0] < nextNode.range[0]);
288
- }
289
-
290
- return pairs;
230
+ /**
231
+ * Executes matching padding tester for last matched padding config for given
232
+ * nodes
233
+ */
234
+ const testPadding = (
235
+ prevNode: Node,
236
+ nextNode: Node,
237
+ paddingContext: PaddingContext,
238
+ ): void => {
239
+ const { configs } = paddingContext;
240
+
241
+ const testType = (type: PaddingType) =>
242
+ paddingTesters[type](prevNode, nextNode, paddingContext);
243
+
244
+ for (let i = configs.length - 1; i >= 0; --i) {
245
+ const {
246
+ prevStatementType: prevType,
247
+ nextStatementType: nextType,
248
+ paddingType,
249
+ } = configs[i];
250
+
251
+ if (
252
+ nodeMatchesType(prevNode, prevType, paddingContext) &&
253
+ nodeMatchesType(nextNode, nextType, paddingContext)
254
+ ) {
255
+ return testType(paddingType);
291
256
  }
257
+ }
292
258
 
293
- /**
294
- * Verify padding lines between the given node and the previous node.
295
- */
296
- function verify(node): void {
297
- const parentType = node.parent.type;
298
- const validParent = STATEMENT_LIST_PARENTS.has(parentType);
299
-
300
- if (!validParent) {
301
- return;
302
- }
259
+ // There were no matching padding rules for the prevNode, nextNode,
260
+ // paddingType combination... so we'll use PaddingType.Any which is always ok
261
+ return testType(PaddingType.Any);
262
+ };
303
263
 
304
- // Save this node as the current previous statement.
305
- const { prevNode } = scopeInfo;
264
+ /**
265
+ * Verify padding lines between the given node and the previous node.
266
+ */
267
+ const verifyNode = (node: Node, paddingContext: PaddingContext): void => {
268
+ const { scopeInfo } = paddingContext;
269
+
270
+ // NOTE: ESLint types use ESTree which provides a Node type, however
271
+ // ESTree.Node doesn't support the parent property which is added by
272
+ // ESLint during traversal. Our best bet is to ignore the property access
273
+ // here as it's the only place that it's checked.
274
+ // @ts-ignore
275
+ if (!astUtils.isValidParent(node.parent.type)) {
276
+ return;
277
+ }
306
278
 
307
- // Verify.
308
- if (prevNode) {
309
- const type = getPaddingType(prevNode, node);
310
- const paddingLines = getPaddingLineSequences(prevNode, node);
279
+ if (scopeInfo.prevNode) {
280
+ testPadding(scopeInfo.prevNode, node, paddingContext);
281
+ }
311
282
 
312
- type.verify(context, prevNode, node, paddingLines);
313
- }
283
+ scopeInfo.prevNode = node;
284
+ };
314
285
 
315
- scopeInfo.prevNode = node;
316
- }
286
+ /**
287
+ * Creates an ESLint rule for a given set of padding Config objects.
288
+ *
289
+ * The algorithm is approximately this:
290
+ *
291
+ * For each 'scope' in the program
292
+ * - Enter the scope (store the parent scope and previous node)
293
+ * - For each statement in the scope
294
+ * - Check the current node and previous node against the Config objects
295
+ * - If the current node and previous node match a Config, check the padding.
296
+ * Otherwise, ignore it.
297
+ * - If the padding is missing (and required), report and fix
298
+ * - Store the current node as the previous
299
+ * - Repeat
300
+ * - Exit scope (return to parent scope and clear previous node)
301
+ *
302
+ * The items we're looking for with this rule are ExpressionStatement nodes
303
+ * where the first token is an Identifier with a name matching one of the Jest
304
+ * functions. It's not foolproof, of course, but it's probably good enough for
305
+ * almost all cases.
306
+ *
307
+ * The Config objects specify a padding type, a previous statement type, and a
308
+ * next statement type. Wildcard statement types and padding types are
309
+ * supported. The current node and previous node are checked against the
310
+ * statement types. If they match then the specified padding type is
311
+ * tested/enforced.
312
+ *
313
+ * See src/index.ts for examples of Config usage.
314
+ */
315
+ export const createRule = (
316
+ configs: Config[],
317
+ deprecated: boolean = false,
318
+ ): Rule.RuleModule => ({
319
+ meta: {
320
+ fixable: 'whitespace',
321
+ deprecated,
322
+ },
323
+ create(context: Rule.RuleContext) {
324
+ const paddingContext = {
325
+ ruleContext: context,
326
+ sourceCode: context.getSourceCode(),
327
+ scopeInfo: createScopeInfo(),
328
+ configs,
329
+ };
317
330
 
318
- /**
319
- * Verify padding lines between the given node and the previous node.
320
- * Then process to enter to new scope.
321
- */
322
- function verifyThenEnterScope(node: Node): void {
323
- verify(node);
324
- enterScope();
325
- }
331
+ const { scopeInfo } = paddingContext;
326
332
 
327
333
  return {
328
- Program: enterScope,
329
- BlockStatement: enterScope,
330
- SwitchStatement: enterScope,
331
- 'Program:exit': exitScope,
332
- 'BlockStatement:exit': exitScope,
333
- 'SwitchStatement:exit': exitScope,
334
- ':statement': verify,
335
- SwitchCase: verifyThenEnterScope,
336
- 'SwitchCase:exit': exitScope,
334
+ Program: scopeInfo.enter,
335
+ 'Program:exit': scopeInfo.enter,
336
+ BlockStatement: scopeInfo.enter,
337
+ 'BlockStatement:exit': scopeInfo.exit,
338
+ SwitchStatement: scopeInfo.enter,
339
+ 'SwitchStatement:exit': scopeInfo.exit,
340
+ ':statement': (node: Node) => verifyNode(node, paddingContext),
341
+ SwitchCase: (node: Node) => {
342
+ verifyNode(node, paddingContext);
343
+ scopeInfo.enter();
344
+ },
345
+ 'SwitchCase:exit': scopeInfo.exit,
337
346
  };
338
347
  },
339
- };
348
+ });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * This file should be IGNORED by jest-formatting due to the `overrides.files`
3
+ * value in `recommended` and `strict` config. This file does not match the
4
+ * globs.
5
+ */
6
+
7
+ beforeAll(() => {});
8
+ beforeEach(() => {});
9
+ afterAll(() => {});
10
+ afterEach(() => {});
11
+ describe('no padding on top', () => {
12
+ it('has no padding above', () => {
13
+ expect(true);
14
+ });
15
+ expect(true);
16
+ expect(1);
17
+ xit('has padding above', () => {
18
+ expect(true);
19
+ });
20
+ it('also has padding above but not below', () => {
21
+ expect(true);
22
+ });
23
+ });
24
+ xdescribe('padding above', () => {
25
+ it('has no padding above or below', () => {
26
+ expect(true);
27
+ });
28
+ it('has no padding above or below', () => {
29
+ expect(true);
30
+ });
31
+ });
32
+ describe('padding above', () => {
33
+ it('has no padding above or below', () => {
34
+ expect(true);
35
+ });
36
+ it('has no padding above or below', () => {
37
+ expect(true);
38
+ });
39
+ });
@@ -1,15 +1,30 @@
1
+ beforeAll(() => {});
2
+
3
+ beforeEach(() => {});
4
+
5
+ afterAll(() => {});
6
+
7
+ afterEach(() => {});
8
+
1
9
  describe('no padding on top', () => {
2
10
  it('has no padding above', () => {
3
11
  expect(true);
4
12
  });
5
13
 
14
+ expect(true);
15
+ expect(1);
16
+
6
17
  it('has padding above', () => {
7
18
  expect(true);
8
19
  });
20
+
21
+ it('also has padding above but not below', () => {
22
+ expect(true);
23
+ });
9
24
  });
10
25
 
11
26
  describe('padding above', () => {
12
- it('has no padding above', () => {
27
+ it('has no padding above or below', () => {
13
28
  expect(true);
14
29
  });
15
30
  });