eslint-plugin-jest-dom
Advanced tools
Comparing version 4.0.2 to 4.0.3
@@ -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; |
"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 |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1267
79351
7
203