Skip to content

Commit

Permalink
Refactor prefer rules
Browse files Browse the repository at this point in the history
  • Loading branch information
xfumihiro committed Nov 26, 2017
1 parent 819ff47 commit 67c6560
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 135 deletions.
17 changes: 16 additions & 1 deletion rules/__tests__/prefer_to_be_defined.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,24 @@ const rules = require('../../').rules;
const ruleTester = new RuleTester();

ruleTester.run('prefer_to_be_defined', rules['prefer-to-be-defined'], {
valid: ['expect(true).toBeDefined();'],
valid: [
'expect(true).toBeDefined();',
'expect(true).not.toBeDefined();',
'expect(true).toBe(true);',
],

invalid: [
{
code: 'expect(true).not.toBe(undefined);',
errors: [
{
message: 'Use toBeDefined() instead',
column: 14,
line: 1,
},
],
output: 'expect(true).toBeDefined();',
},
{
code: 'expect(true).not.toEqual(undefined);',
errors: [
Expand Down
5 changes: 4 additions & 1 deletion rules/__tests__/prefer_to_be_undefined.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ const rules = require('../../').rules;
const ruleTester = new RuleTester();

ruleTester.run('prefer_to_be_undefined', rules['prefer-to-be-undefined'], {
valid: ['expect(undefined).toBeUndefined();'],
valid: [
'expect(undefined).toBeUndefined();',
'expect(true).not.toBeUndefined();',
],

invalid: [
{
Expand Down
76 changes: 33 additions & 43 deletions rules/prefer_to_be_defined.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,43 @@
'use strict';
const {
expectNotToBeCase,
expectNotToEqualCase,
expectNotToBeUndefinedCase,
argument2,
method,
method2,
} = require('./util');

module.exports = context => {
return {
CallExpression(node) {
const calleeName = node.callee.name;

if (
calleeName === 'expect' &&
node.arguments.length == 1 &&
node.parent &&
node.parent.type === 'MemberExpression' &&
node.parent.parent &&
node.parent.parent.type === 'MemberExpression'
expectNotToBeCase(node, undefined) ||
expectNotToEqualCase(node, undefined) ||
expectNotToBeUndefinedCase(node)
) {
const parentProperty = node.parent.property;
const propertyName = parentProperty.name;
const parentProperty2 = node.parent.parent.property;
const propertyName2 = parentProperty2.name;
const argument = node.parent.parent.parent.arguments[0];

if (
(propertyName === 'not' &&
(propertyName2 === 'toBe' || propertyName2 === 'toEqual') &&
argument.value === undefined) ||
(propertyName === 'not' && propertyName2 === 'toBeUndefined')
) {
context.report({
fix(fixer) {
const propertyDot = context
.getSourceCode()
.getFirstTokenBetween(
parentProperty,
parentProperty2,
token => token.value === '.'
);
const fixes = [
fixer.remove(parentProperty),
fixer.remove(propertyDot),
fixer.replaceText(parentProperty2, 'toBeDefined'),
];
if (argument) {
fixes.push(fixer.remove(argument));
}
return fixes;
},
message: 'Use toBeDefined() instead',
node: parentProperty,
});
}
context.report({
fix(fixer) {
const propertyDot = context
.getSourceCode()
.getFirstTokenBetween(
method(node),
method2(node),
token => token.value === '.'
);
const fixes = [
fixer.remove(method(node)),
fixer.remove(propertyDot),
fixer.replaceText(method2(node), 'toBeDefined'),
];
if (argument2(node)) {
fixes.push(fixer.remove(argument2(node)));
}
return fixes;
},
message: 'Use toBeDefined() instead',
node: method(node),
});
}
},
};
Expand Down
45 changes: 17 additions & 28 deletions rules/prefer_to_be_null.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,25 @@
'use strict';
const {
expectToBeCase,
expectToEqualCase,
argument,
method,
} = require('./util');

module.exports = context => {
return {
CallExpression(node) {
const calleeName = node.callee.name;

if (
calleeName === 'expect' &&
node.arguments.length == 1 &&
node.parent &&
node.parent.type === 'MemberExpression' &&
node.parent.parent
) {
const parentProperty = node.parent.property;
const propertyName = parentProperty.name;
const argument = node.parent.parent.arguments[0];

if (
(propertyName === 'toBe' || propertyName === 'toEqual') &&
argument.value === null
) {
context.report({
fix(fixer) {
return [
fixer.replaceText(parentProperty, 'toBeNull'),
fixer.remove(argument),
];
},
message: 'Use toBeNull() instead',
node: parentProperty,
});
}
if (expectToBeCase(node, null) || expectToEqualCase(node, null)) {
context.report({
fix(fixer) {
return [
fixer.replaceText(method(node), 'toBeNull'),
fixer.remove(argument(node)),
];
},
message: 'Use toBeNull() instead',
node: method(node),
});
}
},
};
Expand Down
44 changes: 18 additions & 26 deletions rules/prefer_to_be_undefined.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,28 @@
'use strict';
const {
expectToBeCase,
expectToEqualCase,
argument,
method,
} = require('./util');

module.exports = context => {
return {
CallExpression(node) {
const calleeName = node.callee.name;

if (
calleeName === 'expect' &&
node.arguments.length == 1 &&
node.parent &&
node.parent.type === 'MemberExpression' &&
node.parent.parent
expectToBeCase(node, undefined) ||
expectToEqualCase(node, undefined)
) {
const parentProperty = node.parent.property;
const propertyName = parentProperty.name;
const argument = node.parent.parent.arguments[0];

if (
(propertyName === 'toBe' || propertyName === 'toEqual') &&
argument.value === undefined
) {
context.report({
fix(fixer) {
return [
fixer.replaceText(parentProperty, 'toBeUndefined'),
fixer.remove(argument),
];
},
message: 'Use toBeUndefined() instead',
node: parentProperty,
});
}
context.report({
fix(fixer) {
return [
fixer.replaceText(method(node), 'toBeUndefined'),
fixer.remove(argument(node)),
];
},
message: 'Use toBeUndefined() instead',
node: method(node),
});
}
},
};
Expand Down
70 changes: 34 additions & 36 deletions rules/prefer_to_have_length.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
'use strict';
const {
expectCase,
expectNotCase,
expectResolveCase,
expectRejectCase,
method,
} = require('./util');

module.exports = context => {
return {
CallExpression(node) {
const calleeName = node.callee.name;

if (
calleeName === 'expect' &&
node.arguments.length == 1 &&
node.parent &&
node.parent.type === 'MemberExpression' &&
node.parent.parent
!(
expectNotCase(node) ||
expectResolveCase(node) ||
expectRejectCase(node)
) &&
expectCase(node) &&
(method(node).name === 'toBe' || method(node).name === 'toEqual') &&
node.arguments[0].property &&
node.arguments[0].property.name === 'length'
) {
const parentProperty = node.parent.property;
const propertyName = parentProperty.name;
const argumentObject = node.arguments[0].object;
const argumentProperty = node.arguments[0].property;

if (
(propertyName === 'toBe' || propertyName === 'toEqual') &&
argumentProperty &&
argumentProperty.name === 'length'
) {
const propertyDot = context
.getSourceCode()
.getFirstTokenBetween(
argumentObject,
argumentProperty,
token => token.value === '.'
);
context.report({
fix(fixer) {
return [
fixer.remove(propertyDot),
fixer.remove(argumentProperty),
fixer.replaceText(parentProperty, 'toHaveLength'),
];
},
message: 'Use toHaveLength() instead',
node: parentProperty,
});
}
const propertyDot = context
.getSourceCode()
.getFirstTokenBetween(
node.arguments[0].object,
node.arguments[0].property,
token => token.value === '.'
);
context.report({
fix(fixer) {
return [
fixer.remove(propertyDot),
fixer.remove(node.arguments[0].property),
fixer.replaceText(method(node), 'toHaveLength'),
];
},
message: 'Use toHaveLength() instead',
node: method(node),
});
}
},
};
Expand Down
82 changes: 82 additions & 0 deletions rules/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
'use strict';

const expectCase = node =>
node.callee.name === 'expect' &&
node.arguments.length == 1 &&
node.parent &&
node.parent.type === 'MemberExpression' &&
node.parent.parent;

const expectNotCase = node =>
expectCase(node) &&
node.parent.parent.type === 'MemberExpression' &&
methodName(node) === 'not';

const expectResolveCase = node =>
expectCase(node) &&
node.parent.parent.type === 'MemberExpression' &&
methodName(node) === 'resolve';

const expectRejectCase = node =>
expectCase(node) &&
node.parent.parent.type === 'MemberExpression' &&
methodName(node) === 'reject';

const expectToBeCase = (node, arg) =>
!(expectNotCase(node) || expectResolveCase(node) || expectRejectCase(node)) &&
expectCase(node) &&
methodName(node) === 'toBe' &&
argument(node).value === arg;

const expectNotToBeCase = (node, arg) =>
expectNotCase(node) &&
methodName2(node) === 'toBe' &&
argument2(node).value === arg;

const expectToEqualCase = (node, arg) =>
!(expectNotCase(node) || expectResolveCase(node) || expectRejectCase(node)) &&
expectCase(node) &&
methodName(node) === 'toEqual' &&
argument(node).value === arg;

const expectNotToEqualCase = (node, arg) =>
expectNotCase(node) &&
methodName2(node) === 'toEqual' &&
argument2(node).value === arg;

const expectToBeUndefinedCase = node =>
!(expectNotCase(node) || expectResolveCase(node) || expectRejectCase(node)) &&
expectCase(node) &&
methodName(node) === 'toBeUndefined';

const expectNotToBeUndefinedCase = node =>
expectNotCase(node) && methodName2(node) === 'toBeUndefined';

const method = node => node.parent.property;

const method2 = node => node.parent.parent.property;

const methodName = node => method(node).name;

const methodName2 = node => method2(node).name;

const argument = node => node.parent.parent.arguments[0];

const argument2 = node => node.parent.parent.parent.arguments[0];

module.exports = {
method: method,
method2: method2,
argument: argument,
argument2: argument2,
expectCase: expectCase,
expectNotCase: expectNotCase,
expectResolveCase: expectResolveCase,
expectRejectCase: expectRejectCase,
expectToBeCase: expectToBeCase,
expectNotToBeCase: expectNotToBeCase,
expectToEqualCase: expectToEqualCase,
expectNotToEqualCase: expectNotToEqualCase,
expectToBeUndefinedCase: expectToBeUndefinedCase,
expectNotToBeUndefinedCase: expectNotToBeUndefinedCase,
};

0 comments on commit 67c6560

Please sign in to comment.