Socket
Socket
Sign inDemoInstall

eslint-plugin-jest-dom

Package Overview
Dependencies
Maintainers
1
Versions
60
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-jest-dom - npm Package Compare versions

Comparing version 4.0.2 to 4.0.3

19

dist/assignment-ast.js

@@ -9,5 +9,3 @@ "use strict";

exports.getQueryNodeFrom = getQueryNodeFrom;
var _queries = require("./queries");
/**

@@ -25,9 +23,6 @@ * Gets the inner relevant node (CallExpression, Identity, et al.) given a generic expression node

return getInnerNodeFrom(expression.expression);
case "AwaitExpression":
return getInnerNodeFrom(expression.argument);
case "MemberExpression":
return getInnerNodeFrom(expression.object);
default:

@@ -37,2 +32,3 @@ return expression;

}
/**

@@ -45,4 +41,2 @@ * Get the node corresponding to the latest assignment to a variable named `identifierName`

*/
function getAssignmentForIdentifier(context, identifierName) {

@@ -53,3 +47,2 @@ const variable = context.getScope().set.get(identifierName);

let assignmentNode;
if (init) {

@@ -62,12 +55,10 @@ // let foo = bar;

const assignmentRef = variable.references.reverse().find(ref => !!ref.writeExpr);
if (!assignmentRef) {
return;
}
assignmentNode = getInnerNodeFrom(assignmentRef.writeExpr);
}
return assignmentNode;
}
/**

@@ -81,7 +72,4 @@ * get query node, arg and isDTLQuery flag for a given node. useful for rules that you only

*/
function getQueryNodeFrom(context, nodeWithValueProp) {
const queryNode = nodeWithValueProp.type === "Identifier" ? getAssignmentForIdentifier(context, nodeWithValueProp.name) : getInnerNodeFrom(nodeWithValueProp);
if (!queryNode || !queryNode.callee) {

@@ -94,8 +82,5 @@ return {

}
const query = queryNode.callee.name || queryNode.callee.property && queryNode.callee.property.name;
const queryArg = queryNode.arguments[0] && queryNode.arguments[0].value;
const isDTLQuery = _queries.queries.includes(query);
return {

@@ -102,0 +87,0 @@ queryArg,

@@ -7,5 +7,3 @@ "use strict";

exports.default = void 0;
var _assignmentAst = require("./assignment-ast");
var _default = ({

@@ -17,6 +15,5 @@ preferred,

const getCorrectFunctionFor = (node, negated = false) => (node.arguments.length === 1 || node.arguments[1].value === true || node.arguments[1].type !== "Literal" || typeof node.arguments[1].value === "string" && node.arguments[1].value.toLowerCase() === "true" || node.arguments[1].value === "") && !negated ? preferred : negatedPreferred;
const isBannedArg = node => node.arguments.length && attributes.some(attr => attr === node.arguments[0].value);
const isBannedArg = node => node.arguments.length && attributes.some(attr => attr === node.arguments[0].value); //expect(el).not.toBeEnabled() => expect(el).toBeDisabled()
//expect(el).not.toBeEnabled() => expect(el).toBeDisabled()
return {

@@ -27,3 +24,2 @@ [`CallExpression[callee.property.name=/${preferred}|${negatedPreferred}/][callee.object.property.name='not'][callee.object.object.callee.name='expect']`](node) {

}
const incorrectFunction = node.callee.property.name;

@@ -37,3 +33,2 @@ const correctFunction = incorrectFunction === preferred ? negatedPreferred : preferred;

},
//expect(getByText('foo').<attribute>).toBeTruthy()

@@ -44,3 +39,2 @@ "CallExpression[callee.property.name=/toBe(Truthy|Falsy)?|toEqual/][callee.object.callee.name='expect']"(node) {

}
const {

@@ -57,7 +51,5 @@ arguments: [{

const matcherArg = node.arguments.length && node.arguments[0].value;
if (!attributes.some(attr => attr === name)) {
return;
}
const {

@@ -75,3 +67,2 @@ isDTLQuery

},
"CallExpression[callee.property.name=/toHaveProperty|toHaveAttribute/][callee.object.property.name='not'][callee.object.object.callee.name='expect']"(node) {

@@ -81,3 +72,2 @@ if (!isBannedArg(node)) {

}
const arg = node.arguments[0].value;

@@ -92,3 +82,2 @@ const correctFunction = getCorrectFunctionFor(node, true);

},
"CallExpression[callee.object.callee.name='expect'][callee.property.name=/toHaveProperty|toHaveAttribute/]"(node) {

@@ -98,3 +87,2 @@ if (!isBannedArg(node)) {

}
const {

@@ -118,3 +106,2 @@ isDTLQuery

}
return null;

@@ -124,6 +111,4 @@ }

}
};
};
exports.default = _default;

16

dist/index.js
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {

@@ -9,5 +8,3 @@ value: true

exports.rules = exports.generateRecommendedConfig = exports.generateAllRulesConfig = exports.configs = void 0;
var _requireindex = _interopRequireDefault(require("requireindex"));
/**

@@ -17,13 +14,16 @@ * @fileoverview lint rules for use with jest-dom

*/
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------
// import all rules in src/rules
const rules = (0, _requireindex.default)(`${__dirname}/rules`);
exports.rules = rules;
const generateRecommendedConfig = allRules => Object.entries(allRules).reduce((memo, [name, rule]) => ({ ...memo,
const generateRecommendedConfig = allRules => Object.entries(allRules).reduce((memo, [name, rule]) => ({
...memo,
...(rule.meta.docs.recommended ? {

@@ -33,6 +33,5 @@ [`jest-dom/${name}`]: "error"

}), {});
exports.generateRecommendedConfig = generateRecommendedConfig;
const generateAllRulesConfig = allRules => Object.entries(allRules).reduce((memo, [name]) => ({ ...memo,
const generateAllRulesConfig = allRules => Object.entries(allRules).reduce((memo, [name]) => ({
...memo,
...{

@@ -42,3 +41,2 @@ [`jest-dom/${name}`]: "error"

}), {});
exports.generateAllRulesConfig = generateAllRulesConfig;

@@ -45,0 +43,0 @@ const configs = {

@@ -7,6 +7,4 @@ "use strict";

exports.queries = void 0;
var _dom = require("@testing-library/dom");
const queries = Object.keys(_dom.queries);
exports.queries = queries;
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {

@@ -9,5 +8,3 @@ value: true

exports.meta = exports.create = void 0;
var _createBannedAttributeRule = _interopRequireDefault(require("../createBannedAttributeRule"));
/**

@@ -17,2 +14,3 @@ * @fileoverview prefer toBeDisabled or toBeEnabled over attribute checks

*/
const meta = {

@@ -19,0 +17,0 @@ docs: {

@@ -7,3 +7,2 @@ "use strict";

exports.meta = exports.create = void 0;
/**

@@ -13,2 +12,3 @@ * @fileoverview Prefer toBeEmpty over checking innerHTML

*/
const meta = {

@@ -22,6 +22,4 @@ docs: {

fixable: "code" // or "code" or "whitespace"
};
exports.meta = meta;
const create = context => {

@@ -31,3 +29,2 @@ function isNonEmptyStringOrTemplateLiteral(node) {

}
return {

@@ -42,3 +39,2 @@ [`BinaryExpression[left.property.name='innerHTML'][right.value=''][parent.callee.name='expect'][parent.parent.property.name=/toBe$|to(Strict)?Equal/]`](node) {

},
[`BinaryExpression[left.property.name='firstChild'][right.value=null][parent.callee.name='expect'][parent.parent.property.name=/toBe$|to(Strict)?Equal/]`](node) {

@@ -52,10 +48,7 @@ context.report({

},
[`MemberExpression[property.name = 'innerHTML'][parent.callee.name = 'expect'][parent.parent.property.name = /toBe$|to(Strict)?Equal/]`](node) {
const args = node.parent.parent.parent.arguments[0];
if (isNonEmptyStringOrTemplateLiteral(args)) {
return;
}
context.report({

@@ -67,10 +60,7 @@ node,

},
[`MemberExpression[property.name='innerHTML'][parent.parent.property.name='not'][parent.parent.parent.property.name=/toBe$|to(Strict)?Equal$/][parent.parent.object.callee.name='expect']`](node) {
const args = node.parent.parent.parent.parent.arguments[0];
if (isNonEmptyStringOrTemplateLiteral(args)) {
return;
}
context.report({

@@ -82,3 +72,2 @@ node,

},
[`MemberExpression[property.name = 'firstChild'][parent.callee.name = 'expect'][parent.parent.property.name = /toBeNull$/]`](node) {

@@ -91,3 +80,2 @@ context.report({

},
[`MemberExpression[property.name='firstChild'][parent.parent.property.name='not'][parent.parent.parent.property.name=/toBe$|to(Strict)?Equal$/][parent.parent.object.callee.name='expect']`](node) {

@@ -97,3 +85,2 @@ if (node.parent.parent.parent.parent.arguments[0].value !== null) {

}
context.report({

@@ -105,3 +92,2 @@ node,

},
[`MemberExpression[property.name='firstChild'][parent.parent.property.name='not'][parent.parent.parent.property.name=/toBeNull$/][parent.parent.object.callee.name='expect']`](node) {

@@ -114,3 +100,2 @@ context.report({

},
[`MemberExpression[property.name = 'firstChild'][parent.callee.name = 'expect'][parent.parent.property.name = /toBe$|to(Strict)?Equal/]`](node) {

@@ -120,3 +105,2 @@ if (node.parent.parent.parent.arguments[0].value !== null) {

}
context.report({

@@ -128,6 +112,4 @@ node,

}
};
};
exports.create = create;
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {

@@ -9,5 +8,3 @@ value: true

exports.meta = exports.create = void 0;
var _createBannedAttributeRule = _interopRequireDefault(require("../createBannedAttributeRule"));
/**

@@ -17,2 +14,3 @@ * @fileoverview prefer toBeDisabled or toBeEnabled over attribute checks

*/
const meta = {

@@ -19,0 +17,0 @@ docs: {

@@ -7,3 +7,2 @@ "use strict";

exports.meta = exports.create = void 0;
/**

@@ -13,5 +12,9 @@ * @fileoverview prefer toHaveFocus over checking activeElementa

*/
const variantsOfDoc = [// document:
`[object.name=document]`, // window.document || global.document:
`[object.object.name=/(global|window)$/][object.property.name=document]`, // global.window.document:
const variantsOfDoc = [
// document:
`[object.name=document]`,
// window.document || global.document:
`[object.object.name=/(global|window)$/][object.property.name=document]`,
// global.window.document:
`[object.object.object.name='global'][object.object.property.name='window'][object.property.name=document]`];

@@ -28,3 +31,2 @@ const meta = {

exports.meta = meta;
const create = context => ({

@@ -41,3 +43,2 @@ [variantsOfDoc.map(variant => `MemberExpression${variant}[property.name='activeElement'][parent.parent.object.callee.name='expect'][parent.parent.property.name='not'][parent.parent.parent.property.name=/to(Be|(Strict)?Equal)$/]`).join(", ")](node) {

}
return [fixer.removeRange([node.range[0], element.range[0]]), fixer.insertTextAfterRange([element.range[1], element.range[1] + 1], ".not.toHaveFocus()")];

@@ -47,3 +48,2 @@ }

},
[variantsOfDoc.map(variant => `MemberExpression${variant}[property.name='activeElement'][parent.callee.object.object.callee.name='expect'][parent.callee.property.name=/to(Be|(Strict)?Equal)$/]`).join(", ")](node) {

@@ -57,3 +57,2 @@ const matcher = node.parent.callee.property;

},
[variantsOfDoc.map(variant => `MemberExpression${variant}[property.name='activeElement'][parent.callee.name='expect'][parent.parent.property.name=/to(Be|(Strict)?Equal)$/]`).join(", ")](node) {

@@ -69,3 +68,2 @@ const element = node.parent.parent.parent.arguments[0];

}
return [fixer.replaceText(node, element.name), fixer.remove(element), fixer.replaceText(matcher, "toHaveFocus")];

@@ -75,3 +73,2 @@ }

},
[variantsOfDoc.map(variant => `MemberExpression${variant}[property.name='activeElement'][parent.callee.object.callee.name='expect'][parent.callee.property.name=/to(Be|(Strict)?Equal)$/]`).join(", ")](node) {

@@ -85,5 +82,3 @@ const matcher = node.parent.callee.property;

}
});
exports.create = create;

@@ -7,7 +7,4 @@ "use strict";

exports.meta = exports.create = void 0;
var _queries = require("../queries");
var _assignmentAst = require("../assignment-ast");
/**

@@ -19,2 +16,3 @@ * @fileoverview prefer toBeInTheDocument over checking getAttribute/hasAttribute

/*eslint complexity: ["error", {"max": 20}]*/
const meta = {

@@ -34,28 +32,22 @@ type: "suggestion",

exports.meta = meta;
function isAntonymMatcher(matcherNode, matcherArguments) {
return matcherNode.name === "toBeNull" || matcherNode.name === "toBeFalsy" || usesToBeOrToEqualWithNull(matcherNode, matcherArguments) || usesToHaveLengthZero(matcherNode, matcherArguments);
}
function usesToBeOrToEqualWithNull(matcherNode, matcherArguments) {
return (matcherNode.name === "toBe" || matcherNode.name === "toEqual") && matcherArguments[0].value === null;
}
function usesToHaveLengthZero(matcherNode, matcherArguments) {
return matcherNode.name === "toHaveLength" && matcherArguments[0].value === 0;
// matcherArguments.length === 0: toHaveLength() will cause jest matcher error
// matcherArguments[0].value: toHaveLength(0, ...) means zero length
return matcherNode.name === "toHaveLength" && (matcherArguments.length === 0 || matcherArguments[0].value === 0);
}
const create = context => {
const alternativeMatchers = /^(toHaveLength|toBeDefined|toBeNull|toBe|toEqual|toBeTruthy|toBeFalsy)$/;
function getLengthValue(matcherArguments) {
let lengthValue;
if (matcherArguments[0].type === "Identifier") {
const assignment = (0, _assignmentAst.getAssignmentForIdentifier)(context, matcherArguments[0].name);
if (!assignment) {
return;
}
lengthValue = assignment.value;

@@ -65,6 +57,4 @@ } else if (matcherArguments[0].type === "Literal") {

}
return lengthValue;
}
function check({

@@ -79,19 +69,19 @@ queryNode,

return;
} // only report on dom nodes which we can resolve to RTL queries.
}
// only report on dom nodes which we can resolve to RTL queries.
if (!queryNode || !queryNode.name && !queryNode.property) return;
if (!queryNode || !queryNode.name && !queryNode.property) return; // toHaveLength() is only invalid with 0 or 1
// toHaveLength() is only invalid with 0 or 1
if (matcherNode.name === "toHaveLength" && matcherArguments.length) {
const lengthValue = getLengthValue(matcherArguments); // isNotToHaveLengthZero represents .not.toHaveLength(0) which is a valid use of toHaveLength
const lengthValue = getLengthValue(matcherArguments);
// isNotToHaveLengthZero represents .not.toHaveLength(0) which is a valid use of toHaveLength
const isNotToHaveLengthZero = usesToHaveLengthZero(matcherNode, matcherArguments) && negatedMatcher;
const isValidUseOfToHaveLength = isNotToHaveLengthZero || !["Literal", "Identifier"].includes(matcherArguments[0].type) || lengthValue === undefined || lengthValue > 1;
if (isValidUseOfToHaveLength) {
return;
}
} // toBe() or toEqual() are only invalid with null
}
// toBe() or toEqual() are only invalid with null
if (matcherNode.name === "toBe" || matcherNode.name === "toEqual") {

@@ -102,5 +92,3 @@ if (!matcherArguments.length || !usesToBeOrToEqualWithNull(matcherNode, matcherArguments)) {

}
const query = queryNode.name || queryNode.property.name;
if (_queries.queries.includes(query)) {

@@ -111,13 +99,19 @@ context.report({

loc: matcherNode.loc,
fix(fixer) {
const operations = []; // Remove any arguments in the matcher
const operations = [];
// Remove any arguments in the matcher
for (const argument of Array.from(matcherArguments)) {
const sourceCode = context.getSourceCode();
const token = sourceCode.getTokenAfter(argument);
if (token.value === "," && token.type === "Punctuator") {
// Remove commas if toHaveLength had more than one argument or a trailing comma
operations.push(fixer.replaceText(token, ""));
}
operations.push(fixer.remove(argument));
} // AllBy should not be used with toBeInTheDocument
}
operations.push(fixer.replaceText(queryNode.property || queryNode, query.replace("All", ""))); // Flip the .not if necessary
// AllBy should not be used with toBeInTheDocument
operations.push(fixer.replaceText(queryNode.property || queryNode, query.replace("All", "")));
// Flip the .not if necessary
if (isAntonymMatcher(matcherNode, matcherArguments)) {

@@ -130,13 +124,11 @@ if (negatedMatcher) {

}
} // Replace the actual matcher
}
// Replace the actual matcher
operations.push(fixer.replaceText(matcherNode, "toBeInTheDocument"));
return operations;
}
});
}
}
return {

@@ -148,3 +140,2 @@ // expect(<query>).not.<matcher>

}
const arg = node.callee.object.object.arguments[0];

@@ -163,3 +154,2 @@ const queryNode = arg.type === "AwaitExpression" ? arg.argument.callee : arg.callee;

},
// // const foo = <query> expect(foo).not.<matcher>

@@ -179,3 +169,2 @@ [`MemberExpression[object.object.callee.name=expect][object.property.name=not][property.name=${alternativeMatchers}][object.object.arguments.0.type=Identifier]`](node) {

},
// const foo = <query> expect(foo).<matcher>

@@ -193,3 +182,2 @@ [`MemberExpression[object.callee.name=expect][property.name=${alternativeMatchers}][object.arguments.0.type=Identifier]`](node) {

},
// expect(await <query>).<matcher>

@@ -199,7 +187,5 @@ // expect(<query>).<matcher>

const arg = node.callee.object.arguments[0];
if (!arg) {
return;
}
const queryNode = arg.type === "AwaitExpression" ? arg.argument.callee : arg.callee;

@@ -215,6 +201,4 @@ const matcherNode = node.callee.property;

}
};
};
exports.create = create;
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {

@@ -9,5 +8,3 @@ value: true

exports.meta = exports.create = void 0;
var _createBannedAttributeRule = _interopRequireDefault(require("../createBannedAttributeRule"));
/**

@@ -17,2 +14,3 @@ * @fileoverview prefer toBeDisabled or toBeEnabled over attribute checks

*/
const meta = {

@@ -19,0 +17,0 @@ docs: {

@@ -7,3 +7,2 @@ "use strict";

exports.meta = exports.create = void 0;
/**

@@ -13,5 +12,7 @@ * @fileoverview prefer toHaveAttribute over checking getAttribute/hasAttribute

*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const meta = {

@@ -27,3 +28,2 @@ docs: {

exports.meta = meta;
const create = context => ({

@@ -37,3 +37,2 @@ [`CallExpression[callee.property.name='getAttribute'][parent.callee.name='expect'][parent.parent.property.name=/toBeNull/]`](node) {

},
[`CallExpression[callee.property.name='getAttribute'][parent.callee.name='expect'][parent.parent.property.name=/toContain$|toMatch$/]`](node) {

@@ -47,3 +46,2 @@ const sourceCode = context.getSourceCode();

},
[`CallExpression[callee.property.name='getAttribute'][parent.callee.name='expect'][parent.parent.property.name=/toBe$|to(Strict)?Equal/]`](node) {

@@ -62,3 +60,2 @@ const arg = node.parent.parent.parent.arguments;

},
[`CallExpression[callee.property.name='hasAttribute'][parent.callee.name='expect'][parent.parent.property.name=/toBeNull|toBeUndefined|toBeDefined/]`](node) {

@@ -70,3 +67,2 @@ context.report({

},
[`CallExpression[callee.property.name='getAttribute'][parent.callee.name='expect'][parent.parent.property.name=/toBeUndefined|toBeDefined/]`](node) {

@@ -78,3 +74,2 @@ context.report({

},
[`CallExpression[callee.property.name='hasAttribute'][parent.callee.name='expect'][parent.parent.property.name=/toBe$|to(Strict)?Equal/]`](node) {

@@ -94,3 +89,2 @@ if (typeof node.parent.parent.parent.arguments[0].value === "boolean") {

},
[`CallExpression[callee.property.name='hasAttribute'][parent.callee.name='expect'][parent.parent.property.name=/toBeTruthy|toBeFalsy/]`](node) {

@@ -103,5 +97,3 @@ context.report({

}
});
exports.create = create;

@@ -7,5 +7,3 @@ "use strict";

exports.meta = exports.create = void 0;
var _assignmentAst = require("../assignment-ast");
/**

@@ -15,5 +13,7 @@ * @fileoverview prefer toHaveClass over checking element className

*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const messageId = "use-to-have-class";

@@ -33,3 +33,2 @@ const meta = {

exports.meta = meta;
const create = context => ({

@@ -47,3 +46,2 @@ //expect(el.classList.contains("foo")).toBe(true)

messageId,
fix(fixer) {

@@ -54,6 +52,4 @@ return [fixer.removeRange([checkedProp.range[1], expectArg.range[1]]), fixer.replaceText(matcher, `${isTruthy ? "" : "not."}toHaveClass`), matcherArg ? fixer.replaceText(matcherArg, context.getSourceCode().getText(classValue)) : fixer.insertTextBefore(context.getSourceCode().getTokenAfter(matcher, {

}
});
},
//expect(el.classList[0]).toBe("bar")

@@ -68,3 +64,2 @@ [`CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.object.property.name=classList][callee.property.name=/toBe$|to(Strict)?Equal|toContain/][arguments.0.type=/Literal$/]`](node) {

messageId,
fix(fixer) {

@@ -75,6 +70,4 @@ //can't autofix here as it toHaveClass doesn't have a partial matcher / regex for class names.

}
});
},
//expect(el.classList[0]).not.toBe("bar")

@@ -88,3 +81,2 @@ [`CallExpression[callee.object.object.callee.name=expect][callee.object.object.arguments.0.object.property.name=classList][callee.object.property.name=not][callee.property.name=/toBe$|to(Strict)?Equal|toContain/][arguments.0.type=/Literal$/]`](node) {

},
//expect(el.className | el.classList).toBe("bar") / toStrict?Equal / toContain

@@ -99,3 +91,4 @@ [`CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.property.name=/class(Name|List)/][callee.property.name=/toBe$|to(Strict)?Equal|toContain/]`](node) {

} = (0, _assignmentAst.getQueryNodeFrom)(context, classNameProp);
if (!isDTLQuery) return; // don't report here if using `expect.foo()`
if (!isDTLQuery) return;
// don't report here if using `expect.foo()`

@@ -105,7 +98,5 @@ if (classValue.type === "CallExpression" && classValue.callee.type === "MemberExpression" && classValue.callee.object.name === "expect") {

}
context.report({
node: matcher,
messageId,
fix(fixer) {

@@ -115,9 +106,6 @@ if (checkedProp.name === "classList" && matcher.name !== "toContain") {

}
return [fixer.removeRange([classNameProp.range[1], checkedProp.range[1]]), fixer.replaceText(matcher, "toHaveClass"), fixer.replaceText(classValue, `${context.getSourceCode().getText(classValue)}${matcher.name === "toContain" ? "" : ", { exact: true }"}`)];
}
});
},
//expect(el.className | el.classList).toEqual(expect.stringContaining("foo") | objectContaining) / toStrictEqual

@@ -137,3 +125,2 @@ [`CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.property.name=/class(Name|List)/][callee.property.name=/to(Strict)?Equal/][arguments.0.callee.object.name=expect]`](node) {

messageId,
fix(fixer) {

@@ -143,6 +130,4 @@ if (matcherArg.name !== "stringContaining") return;

}
});
},
//expect(screen.getByRole("button").className | classList).not.toBe("foo"); / toStrict?Equal / toContain

@@ -161,3 +146,2 @@ [`CallExpression[callee.object.object.callee.name=expect][callee.object.object.arguments.0.property.name=/class(Name|List)/][callee.object.property.name=not][callee.property.name=/toBe$|to(Strict)?Equal|toContain/]`](node) {

messageId,
fix(fixer) {

@@ -167,9 +151,6 @@ if (className.name === "classList" && matcher.name !== "toContain") {

}
return [fixer.removeRange([classNameProp.range[1], className.range[1]]), fixer.replaceText(matcher, "toHaveClass"), fixer.replaceText(classValue, `${context.getSourceCode().getText(classValue)}${matcher.name === "toContain" ? "" : ", { exact: true }"}`)];
}
});
},
//expect(el).toHaveProperty("className", "foo: bar");

@@ -181,7 +162,5 @@ //expect(el).toHaveAttribute("class", "foo: bar");

const classNameValue = context.getSourceCode().getText(classArg).slice(1, -1);
if (matcher.name === "toHaveAttribute" && classNameValue !== "class" || matcher.name === "toHaveProperty" && classNameValue !== "className") {
return;
}
const {

@@ -194,10 +173,7 @@ isDTLQuery

messageId,
fix(fixer) {
return [fixer.replaceText(matcher, "toHaveClass"), fixer.replaceText(classArg, context.getSourceCode().getText(classValueArg)), fixer.replaceText(classValueArg, `{ exact: true }`)];
}
});
},
//expect(el).not.toHaveAttribute("class", "foo: bar");

@@ -210,7 +186,5 @@ //expect(el).not.toHaveProperty("className", "foo: bar");

const classNameValue = context.getSourceCode().getText(classArg).slice(1, -1);
if (matcher.name === "toHaveAttribute" && classNameValue !== "class" || matcher.name === "toHaveProperty" && classNameValue !== "className") {
return;
}
const {

@@ -223,10 +197,7 @@ isDTLQuery

messageId,
fix(fixer) {
return [fixer.replaceText(matcher, "toHaveClass"), fixer.replaceText(classArg, context.getSourceCode().getText(classValueArg)), fixer.replaceText(classValueArg, `{ exact: true }`)];
}
});
},
//expect(el).toHaveProperty(`className`, expect.stringContaining("foo"));

@@ -239,7 +210,5 @@ //expect(el).toHaveAttribute(`class`, expect.stringContaining("foo"));

const classNameValue = context.getSourceCode().getText(classArg).slice(1, -1);
if (matcher.name === "toHaveAttribute" && classNameValue !== "class" || matcher.name === "toHaveProperty" && classNameValue !== "className") {
return;
}
const {

@@ -252,12 +221,8 @@ isDTLQuery

messageId,
fix(fixer) {
return [fixer.replaceText(matcher, "toHaveClass"), fixer.replaceText(classArg, context.getSourceCode().getText(classValueArg)), fixer.removeRange([classArg.range[1], classValue.range[1]])];
}
});
}
});
exports.create = create;

@@ -7,3 +7,2 @@ "use strict";

exports.meta = exports.create = void 0;
/**

@@ -13,2 +12,3 @@ * @fileoverview prefer toHaveStyle over checking element style

*/
//------------------------------------------------------------------------------

@@ -18,3 +18,2 @@ // Rule Definition

const camelCase = str => str.replace(/-([a-z])/g, c => c[1].toUpperCase());
const meta = {

@@ -30,3 +29,2 @@ docs: {

exports.meta = meta;
const create = context => {

@@ -37,10 +35,7 @@ function getReplacementObjectProperty(styleName) {

}
return `[${context.getSourceCode().getText(styleName)}]`;
}
function getReplacementStyleParam(styleName, styleValue) {
return styleName.type === "Literal" ? `{${camelCase(styleName.value)}: ${context.getSourceCode().getText(styleValue)}}` : `${context.getSourceCode().getText(styleName).slice(0, -1)}: ${styleValue.type === "TemplateLiteral" ? context.getSourceCode().getText(styleValue).substring(1) : `${styleValue.value}\``}`;
}
return {

@@ -55,10 +50,7 @@ //expect(el.style.foo).toBe("bar");

message: "Use toHaveStyle instead of asserting on element style",
fix(fixer) {
return [fixer.removeRange([node.object.range[1], styleName.range[1]]), fixer.replaceText(matcher, "toHaveStyle"), fixer.replaceText(styleValue, `{${styleName.name}:${context.getSourceCode().getText(styleValue)}}`)];
}
});
},
//expect(el.style.foo).not.toBe("bar");

@@ -72,10 +64,7 @@ [`MemberExpression[property.name=style][parent.computed=false][parent.parent.parent.property.name=not][parent.parent.parent.parent.property.name=/toBe$|to(Strict)?Equal/][parent.parent.parent.parent.parent.arguments.0.type=/(Template)?Literal$/][parent.parent.callee.name=expect]`](node) {

message: "Use toHaveStyle instead of asserting on element style",
fix(fixer) {
return [fixer.removeRange([node.object.range[1], styleName.range[1]]), fixer.replaceText(matcher, "toHaveStyle"), fixer.replaceText(styleValue, `{${styleName.name}:${context.getSourceCode().getText(styleValue)}}`)];
}
});
},
// expect(el.style).toContain("foo-bar")

@@ -88,10 +77,7 @@ [`MemberExpression[property.name=style][parent.parent.property.name=toContain][parent.parent.parent.arguments.0.type=/(Template)?Literal$/][parent.callee.name=expect]`](node) {

message: "Use toHaveStyle instead of asserting on element style",
fix(fixer) {
return [fixer.removeRange([node.object.range[1], node.property.range[1]]), fixer.replaceText(matcher, "toHaveStyle"), fixer.replaceText(styleName, styleName.type === "Literal" ? `{${camelCase(styleName.value)}: expect.anything()}` : context.getSourceCode().getText(styleName))];
}
});
},
// expect(el.style).not.toContain("foo-bar")

@@ -104,10 +90,7 @@ [`MemberExpression[property.name=style][parent.parent.property.name=not][parent.parent.parent.property.name=toContain][parent.parent.parent.parent.arguments.0.type=/(Template)?Literal$/]`](node) {

message: "Use toHaveStyle instead of asserting on element style",
fix(fixer) {
return [fixer.removeRange([node.object.range[1], node.property.range[1]]), fixer.replaceText(matcher, "toHaveStyle"), fixer.replaceText(styleName, styleName.type === "Literal" ? `{${camelCase(styleName.value)}: expect.anything()}` : context.getSourceCode().getText(styleName))];
}
});
},
//expect(el).toHaveAttribute("style", "foo: bar");

@@ -118,10 +101,7 @@ [`CallExpression[callee.property.name=toHaveAttribute][arguments.0.value=style][arguments.1][callee.object.callee.name=expect]`](node) {

message: "Use toHaveStyle instead of asserting on element style",
fix(fixer) {
return [fixer.replaceText(node.callee.property, "toHaveStyle"), fixer.removeRange([node.arguments[0].range[0], node.arguments[1].range[0]])];
}
});
},
//expect(el.style["foo-bar"]).toBe("baz")

@@ -135,3 +115,2 @@ [`MemberExpression[property.name=style][parent.computed=true][parent.parent.parent.property.name=/toBe$|to(Strict)?Equal/][parent.parent.parent.parent.arguments.0.type=/((Template)?Literal|Identifier)/][parent.parent.callee.name=expect]`](node) {

let fix = null;
if (typeof styleValue.value !== "number" && !(styleValue.value instanceof RegExp)) {

@@ -142,3 +121,2 @@ fix = fixer => {

}
context.report({

@@ -150,3 +128,2 @@ node: node.property,

},
//expect(el.style["foo-bar"]).not.toBe("baz")

@@ -159,3 +136,2 @@ [`MemberExpression[property.name=style][parent.computed=true][parent.parent.parent.property.name=not][parent.parent.parent.parent.parent.callee.property.name=/toBe$|to(Strict)?Equal/][parent.parent.parent.parent.parent.arguments.0.type=/(Template)?Literal/][parent.parent.callee.name=expect]`](node) {

let fix = null;
if (typeof styleName.value !== "number") {

@@ -166,3 +142,2 @@ fix = fixer => {

}
context.report({

@@ -174,3 +149,2 @@ node: node.property,

},
//expect(foo.style).toHaveProperty("foo", "bar")

@@ -183,3 +157,2 @@ [`MemberExpression[property.name=style][parent.parent.property.name=toHaveProperty][parent.callee.name=expect]`](node) {

message: "Use toHaveStyle instead of asserting on element style",
fix(fixer) {

@@ -189,9 +162,6 @@ if (!styleValue || !["Literal", "TemplateLiteral"].includes(styleValue.type)) {

}
return [fixer.removeRange([node.object.range[1], node.property.range[1]]), fixer.replaceText(matcher, "toHaveStyle"), fixer.replaceTextRange([styleName.range[0], styleValue.range[1]], `{${camelCase(styleName.value)}: ${context.getSourceCode().getText(styleValue)}}`)];
}
});
},
//expect(foo.style).not.toHaveProperty("foo", "bar")

@@ -204,3 +174,2 @@ [`MemberExpression[property.name=style][parent.parent.property.name=not][parent.parent.parent.property.name=toHaveProperty][parent.callee.name=expect]`](node) {

message: "Use toHaveStyle instead of asserting on element style",
fix(fixer) {

@@ -210,12 +179,8 @@ if (!styleValue || !["Literal", "TemplateLiteral"].includes(styleValue.type)) {

}
return [fixer.removeRange([node.object.range[1], node.property.range[1]]), fixer.replaceText(matcher, "toHaveStyle"), fixer.replaceTextRange([styleName.range[0], styleValue.range[1]], `{${camelCase(styleName.value)}: ${context.getSourceCode().getText(styleValue)}}`)];
}
});
}
};
};
exports.create = create;

@@ -7,3 +7,2 @@ "use strict";

exports.meta = exports.create = void 0;
/**

@@ -13,2 +12,3 @@ * @fileoverview prefer toHaveAttribute over checking getAttribute/hasAttribute

*/
const meta = {

@@ -24,3 +24,2 @@ docs: {

exports.meta = meta;
const create = context => ({

@@ -38,3 +37,2 @@ [`MemberExpression[property.name='textContent'][parent.callee.name='expect'][parent.parent.property.name=/toContain$|toMatch$/]`](node) {

},
[`MemberExpression[property.name='textContent'][parent.callee.name='expect'][parent.parent.property.name=/toBe$|to(Strict)?Equal/]`](node) {

@@ -47,3 +45,2 @@ context.report({

},
[`MemberExpression[property.name='textContent'][parent.callee.name='expect'][parent.parent.property.name='not'][parent.parent.parent.property.name=/toBe$|to(Strict)?Equal/]`](node) {

@@ -56,3 +53,2 @@ context.report({

},
[`MemberExpression[property.name='textContent'][parent.callee.name='expect'][parent.parent.property.name='not'][parent.parent.parent.property.name=/toContain$|toMatch$/]`](node) {

@@ -67,5 +63,3 @@ const expectedArg = node.parent.parent.parent.parent.arguments[0];

}
});
exports.create = create;

@@ -7,5 +7,3 @@ "use strict";

exports.meta = exports.create = void 0;
var _assignmentAst = require("../assignment-ast");
/**

@@ -15,5 +13,7 @@ * @fileoverview prefer toHaveAttribute over checking getAttribute/hasAttribute

*/
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const meta = {

@@ -33,3 +33,2 @@ docs: {

const messageId = "use-to-have-value";
const create = context => {

@@ -44,3 +43,2 @@ function isValidQueryNode(nodeWithValueProp) {

}
return {

@@ -54,3 +52,2 @@ // expect(element.value).toBe('foo') / toEqual / toStrictEqual

const queryNode = node.callee.object.arguments[0].object;
if (isValidQueryNode(queryNode)) {

@@ -60,11 +57,8 @@ context.report({

node,
fix(fixer) {
return [fixer.remove(context.getSourceCode().getTokenBefore(valueProp)), fixer.remove(valueProp), fixer.replaceText(matcher, "toHaveValue")];
}
});
}
},
// expect(element.value).not.toBe('foo') / toEqual / toStrictEqual

@@ -77,3 +71,2 @@ // expect(<query>.value).not.toBe('foo') / toEqual / toStrictEqual

const matcher = node.callee.property;
if (isValidQueryNode(queryNode)) {

@@ -83,11 +76,8 @@ context.report({

node,
fix(fixer) {
return [fixer.removeRange([context.getSourceCode().getTokenBefore(valueProp).range[0], valueProp.range[1]]), fixer.replaceText(matcher, "toHaveValue")];
}
});
}
},
//expect(element).toHaveAttribute('value', 'foo') / Property

@@ -100,13 +90,9 @@ [`CallExpression[callee.property.name=/toHave(Attribute|Property)/][arguments.0.value=value][arguments.1][callee.object.callee.name=expect], CallExpression[callee.property.name=/toHave(Attribute|Property)/][arguments.0.value=value][arguments.1][callee.object.object.callee.name=expect][callee.object.property.name=not]`](node) {

node,
fix(fixer) {
return [fixer.replaceText(matcher, "toHaveValue"), fixer.removeRange([prop.range[0], value.range[0]])];
}
});
}
};
};
exports.create = create;
{
"name": "eslint-plugin-jest-dom",
"version": "4.0.2",
"version": "4.0.3",
"description": "ESLint plugin to follow best practices and anticipate common mistakes when writing tests with jest-dom",

@@ -33,5 +33,6 @@ "main": "dist/index.js",

"build": "kcd-scripts build",
"pregenerate-readme-table": "yarn build",
"generate-readme-table": "node build/generate-readme-table.js",
"pregenerate-readme-table": "npm run build",
"generate-readme-table": "eslint-doc-generator --ignore-config all",
"lint": "kcd-scripts lint",
"lint:generate-readme-table": "npm run generate-readme-table -- --check",
"setup": "npm install && npm run validate -s",

@@ -51,4 +52,5 @@ "test": "kcd-scripts test",

"eslint": "^8.7.0",
"eslint-remote-tester": "^2.1.1",
"eslint-remote-tester-repositories": "^0.0.5",
"eslint-doc-generator": "^0.19.0",
"eslint-remote-tester": "^3.0.0",
"eslint-remote-tester-repositories": "^0.0.7",
"kcd-scripts": "^12.0.0",

@@ -55,0 +57,0 @@ "typescript": "^4.5.3"

@@ -95,24 +95,24 @@ <div align="center">

πŸ‘ indicates that a rule is recommended for all users.
<!-- begin auto-generated rules list -->
πŸ”§ indicates that a rule is fixable.
πŸ’Ό Configurations enabled in.\
βœ… Set in the `recommended` configuration.\
πŸ”§ Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).
<!-- __BEGIN AUTOGENERATED TABLE__ -->
| NameΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  | Description | πŸ’Ό | πŸ”§ |
| :----------------------------------------------------------------------- | :-------------------------------------------------------------------- | :- | :- |
| [prefer-checked](docs/rules/prefer-checked.md) | prefer toBeChecked over checking attributes | βœ… | πŸ”§ |
| [prefer-empty](docs/rules/prefer-empty.md) | Prefer toBeEmpty over checking innerHTML | βœ… | πŸ”§ |
| [prefer-enabled-disabled](docs/rules/prefer-enabled-disabled.md) | prefer toBeDisabled or toBeEnabled over checking attributes | βœ… | πŸ”§ |
| [prefer-focus](docs/rules/prefer-focus.md) | prefer toHaveFocus over checking document.activeElement | βœ… | πŸ”§ |
| [prefer-in-document](docs/rules/prefer-in-document.md) | Prefer .toBeInTheDocument() for asserting the existence of a DOM node | βœ… | πŸ”§ |
| [prefer-required](docs/rules/prefer-required.md) | prefer toBeRequired over checking properties | βœ… | πŸ”§ |
| [prefer-to-have-attribute](docs/rules/prefer-to-have-attribute.md) | prefer toHaveAttribute over checking getAttribute/hasAttribute | βœ… | πŸ”§ |
| [prefer-to-have-class](docs/rules/prefer-to-have-class.md) | prefer toHaveClass over checking element className | βœ… | πŸ”§ |
| [prefer-to-have-style](docs/rules/prefer-to-have-style.md) | prefer toHaveStyle over checking element style | βœ… | πŸ”§ |
| [prefer-to-have-text-content](docs/rules/prefer-to-have-text-content.md) | Prefer toHaveTextContent over checking element.textContent | βœ… | πŸ”§ |
| [prefer-to-have-value](docs/rules/prefer-to-have-value.md) | prefer toHaveValue over checking element.value | βœ… | πŸ”§ |
| Name | πŸ‘ | πŸ”§ | Description |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | --- | --- | --------------------------------------------------------------------- |
| [prefer-checked](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-checked.md) | πŸ‘ | πŸ”§ | prefer toBeChecked over checking attributes |
| [prefer-empty](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-empty.md) | πŸ‘ | πŸ”§ | Prefer toBeEmpty over checking innerHTML |
| [prefer-enabled-disabled](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-enabled-disabled.md) | πŸ‘ | πŸ”§ | prefer toBeDisabled or toBeEnabled over checking attributes |
| [prefer-focus](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-focus.md) | πŸ‘ | πŸ”§ | prefer toHaveFocus over checking document.activeElement |
| [prefer-in-document](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-in-document.md) | πŸ‘ | πŸ”§ | Prefer .toBeInTheDocument() for asserting the existence of a DOM node |
| [prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-required.md) | πŸ‘ | πŸ”§ | prefer toBeRequired over checking properties |
| [prefer-to-have-attribute](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-to-have-attribute.md) | πŸ‘ | πŸ”§ | prefer toHaveAttribute over checking getAttribute/hasAttribute |
| [prefer-to-have-class](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-to-have-class.md) | πŸ‘ | πŸ”§ | prefer toHaveClass over checking element className |
| [prefer-to-have-style](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-to-have-style.md) | πŸ‘ | πŸ”§ | prefer toHaveStyle over checking element style |
| [prefer-to-have-text-content](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-to-have-text-content.md) | πŸ‘ | πŸ”§ | Prefer toHaveTextContent over checking element.textContent |
| [prefer-to-have-value](https://github.com/testing-library/eslint-plugin-jest-dom/blob/main/docs/rules/prefer-to-have-value.md) | πŸ‘ | πŸ”§ | prefer toHaveValue over checking element.value |
<!-- end auto-generated rules list -->
<!-- __END AUTOGENERATED TABLE__ -->
## Issues

@@ -200,3 +200,2 @@

[all-contributors]: https://github.com/all-contributors/all-contributors
[all-contributors-badge]: https://img.shields.io/github/all-contributors/testing-library/eslint-plugin-jest-dom?color=orange&style=flat-square
[bugs]: https://github.com/testing-library/eslint-plugin-jest-dom/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Acreated-desc+label%3Abug

@@ -203,0 +202,0 @@ [requests]: https://github.com/testing-library/eslint-plugin-jest-dom/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚑️ by Socket Inc