Skip to content
268 changes: 154 additions & 114 deletions src/rules/__tests__/consistent-test-it.test.ts

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/rules/__tests__/expect-expect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ ruleTester.run('expect-expect', rule, {
].join('\n'),
options: [{ assertFunctionNames: ['td.verify'] }],
},
{
code: 'it("should pass", () => expect(true).toBeDefined())',
options: [{ assertFunctionNames: undefined }],
},
],

invalid: [
Expand Down
1 change: 1 addition & 0 deletions src/rules/__tests__/no-hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ ruleTester.run('no-hooks', rule, {
code: 'afterEach(() => {}); afterAll(() => {});',
options: [{ allow: [HookName.afterEach, HookName.afterAll] }],
},
{ code: 'test("foo")', options: [{ allow: undefined }] },
],
invalid: [
{
Expand Down
52 changes: 32 additions & 20 deletions src/rules/consistent-test-it.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils';
import { createRule, getNodeName, isDescribe, isTestCase } from './utils';
import {
TestCaseName,
createRule,
getNodeName,
isDescribe,
isTestCase,
} from './utils';

export default createRule({
export default createRule<
[
Partial<{
fn: TestCaseName.it | TestCaseName.test;
withinDescribe: TestCaseName.it | TestCaseName.test;
}>,
],
'consistentMethod' | 'consistentMethodWithinDescribe'
>({
name: __filename,
meta: {
docs: {
Expand All @@ -13,36 +27,31 @@ export default createRule({
messages: {
consistentMethod:
"Prefer using '{{ testKeyword }}' instead of '{{ oppositeTestKeyword }}'",
consistentMethodWithingDescribe:
consistentMethodWithinDescribe:
"Prefer using '{{ testKeywordWithinDescribe }}' instead of '{{ oppositeTestKeyword }}' within describe",
},
schema: [
{
type: 'object',
properties: {
fn: {
enum: ['it', 'test'],
enum: [TestCaseName.it, TestCaseName.test],
},
withinDescribe: {
enum: ['it', 'test'],
enum: [TestCaseName.it, TestCaseName.test],
},
},
additionalProperties: false,
},
],
type: 'suggestion',
},
defaultOptions: [
{ fn: 'test', withinDescribe: 'it' } as {
fn?: 'it' | 'test';
withinDescribe?: 'it' | 'test';
},
],
defaultOptions: [{ fn: TestCaseName.test, withinDescribe: TestCaseName.it }],
create(context) {
const configObj = context.options[0] || {};
const testKeyword = configObj.fn || 'test';
const testKeyword = configObj.fn || TestCaseName.test;
const testKeywordWithinDescribe =
configObj.withinDescribe || configObj.fn || 'it';
configObj.withinDescribe || configObj.fn || TestCaseName.it;

let describeNestingLevel = 0;

Expand Down Expand Up @@ -91,7 +100,7 @@ export default createRule({
);

context.report({
messageId: 'consistentMethodWithingDescribe',
messageId: 'consistentMethodWithinDescribe',
node: node.callee,
data: { testKeywordWithinDescribe, oppositeTestKeyword },
fix(fixer) {
Expand All @@ -118,9 +127,12 @@ export default createRule({
},
});

function getPreferredNodeName(nodeName: string, preferredTestKeyword: string) {
function getPreferredNodeName(
nodeName: string,
preferredTestKeyword: TestCaseName.test | TestCaseName.it,
) {
switch (nodeName) {
case 'fit':
case TestCaseName.fit:
return 'test.only';
default:
return nodeName.startsWith('f') || nodeName.startsWith('x')
Expand All @@ -129,10 +141,10 @@ function getPreferredNodeName(nodeName: string, preferredTestKeyword: string) {
}
}

function getOppositeTestKeyword(test: string) {
if (test === 'test') {
return 'it';
function getOppositeTestKeyword(test: TestCaseName.test | TestCaseName.it) {
if (test === TestCaseName.test) {
return TestCaseName.it;
}

return 'test';
return TestCaseName.test;
}
11 changes: 7 additions & 4 deletions src/rules/expect-expect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import { createRule, getNodeName } from './utils';
import { TestCaseName, createRule, getNodeName } from './utils';

export default createRule({
export default createRule<
[Partial<{ assertFunctionNames: readonly string[] }>],
'noAssertions'
>({
name: __filename,
meta: {
docs: {
Expand All @@ -35,13 +38,13 @@ export default createRule({
type: 'suggestion',
},
defaultOptions: [{ assertFunctionNames: ['expect'] }],
create(context, [{ assertFunctionNames }]) {
create(context, [{ assertFunctionNames = ['expect'] }]) {
const unchecked: TSESTree.CallExpression[] = [];

return {
CallExpression(node) {
const name = getNodeName(node.callee);
if (name === 'it' || name === 'test') {
if (name === TestCaseName.it || name === TestCaseName.test) {
unchecked.push(node);
} else if (name && assertFunctionNames.includes(name)) {
// Return early in case of nested `it` statements.
Expand Down
18 changes: 14 additions & 4 deletions src/rules/lowercase-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
import {
DescribeAlias,
JestFunctionCallExpressionWithIdentifierCallee,
JestFunctionName,
TestCaseName,
createRule,
isDescribe,
Expand All @@ -19,8 +18,13 @@ interface FirstArgumentStringCallExpression extends TSESTree.CallExpression {
arguments: [ArgumentLiteral];
}

type IgnorableFunctionExpressions =
| TestCaseName.it
| TestCaseName.test
| DescribeAlias.describe;

type CallExpressionWithCorrectCalleeAndArguments = JestFunctionCallExpressionWithIdentifierCallee<
TestCaseName.it | TestCaseName.test | DescribeAlias.describe
IgnorableFunctionExpressions
> &
FirstArgumentStringCallExpression;

Expand Down Expand Up @@ -80,7 +84,7 @@ const jestFunctionName = (
export default createRule<
[
Partial<{
ignore: readonly JestFunctionName[];
ignore: readonly IgnorableFunctionExpressions[];
allowedPrefixes: readonly string[];
}>,
],
Expand All @@ -105,7 +109,13 @@ export default createRule<
properties: {
ignore: {
type: 'array',
items: { enum: ['describe', 'test', 'it'] },
items: {
enum: [
DescribeAlias.describe,
TestCaseName.test,
TestCaseName.it,
],
},
additionalItems: false,
},
allowedPrefixes: {
Expand Down
2 changes: 1 addition & 1 deletion src/rules/no-commented-out-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default createRule({
},
schema: [],
type: 'suggestion',
} as const,
},
defaultOptions: [],
create(context) {
const sourceCode = context.getSourceCode();
Expand Down
9 changes: 6 additions & 3 deletions src/rules/no-hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { HookName, createRule, isHook } from './utils';

export default createRule({
export default createRule<
[Partial<{ allow: readonly HookName[] }>],
'unexpectedHook'
>({
name: __filename,
meta: {
docs: {
Expand All @@ -25,8 +28,8 @@ export default createRule({
],
type: 'suggestion',
},
defaultOptions: [{ allow: [] } as { allow: readonly HookName[] }],
create(context, [{ allow }]) {
defaultOptions: [{ allow: [] }],
create(context, [{ allow = [] }]) {
return {
CallExpression(node) {
if (isHook(node) && !allow.includes(node.callee.name)) {
Expand Down