blob: 4f4d2c775459c2d68ecb1f7d432741623d577584 [file]
import { evaluateObjectProperties, getKeyName, getTestInfo } from "../utils.mjs";
//#region lib/rules/require-test-case-name.ts
const violationFilters = {
always: (testCase) => !testCase.hasName,
objects: (testCase) => testCase.isObject && !testCase.hasName,
"objects-with-config": (testCase) => testCase.isObject && testCase.hasConfig && !testCase.hasName
};
const violationMessages = {
always: "nameRequiredAlways",
objects: "nameRequiredObjects",
"objects-with-config": "nameRequiredObjectsWithConfig"
};
const rule = {
meta: {
type: "suggestion",
docs: {
description: "require test cases to have a `name` property under certain conditions",
category: "Tests",
recommended: false,
url: "https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/require-test-case-name.md"
},
schema: [{
additionalProperties: false,
properties: { require: {
description: "When should the name property be required on a test case object.",
enum: [
"always",
"objects",
"objects-with-config"
]
} },
type: "object"
}],
defaultOptions: [{ require: "objects-with-config" }],
messages: {
nameRequiredAlways: "This test case is missing the `name` property. All test cases should have a name property.",
nameRequiredObjects: "This test case is missing the `name` property. Test cases defined as objects should have a name property.",
nameRequiredObjectsWithConfig: "This test case is missing the `name` property. Test cases defined as objects with additional configuration should have a name property."
}
},
create(context) {
const { require: requireOption = "objects-with-config" } = context.options[0] || {};
const sourceCode = context.sourceCode;
/**
* Validates test cases and reports them if found in violation
* @param cases A list of test case nodes
*/
function validateTestCases(cases) {
const violations = cases.filter((testCase) => !!testCase).map((testCase) => {
if (testCase.type === "Literal" || testCase.type === "TemplateLiteral") return {
node: testCase,
isObject: false,
hasName: false,
hasConfig: false
};
if (testCase.type === "ObjectExpression") {
let hasName = false;
let hasConfig = false;
for (const property of evaluateObjectProperties(testCase, sourceCode.scopeManager)) if (property.type === "Property") {
const keyName = getKeyName(property, sourceCode.getScope(testCase));
if (keyName === "name") hasName = true;
else if (keyName === "options" || keyName === "settings") hasConfig = true;
}
return {
node: testCase,
isObject: true,
hasName,
hasConfig
};
}
return null;
}).filter((testCase) => !!testCase).filter(violationFilters[requireOption]);
for (const violation of violations) context.report({
node: violation.node,
messageId: violationMessages[requireOption]
});
}
return { Program(ast) {
getTestInfo(context, ast).map((testRun) => [...testRun.valid, ...testRun.invalid]).forEach(validateTestCases);
} };
}
};
//#endregion
export { rule as default };