Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: fails the test case if autofix made syntax error (fixes #11615) #11798

Merged
merged 2 commits into from Jun 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 26 additions & 8 deletions lib/rule-tester/rule-tester.js
Expand Up @@ -313,7 +313,7 @@ class RuleTester {
*/
function runRuleForItem(item) {
let config = lodash.cloneDeep(testerConfig),
code, filename, beforeAST, afterAST;
code, filename, output, beforeAST, afterAST;

if (typeof item === "string") {
code = item;
Expand Down Expand Up @@ -396,8 +396,29 @@ class RuleTester {

validate(config, "rule-tester", id => (id === ruleName ? rule : null));

// Verify the code.
const messages = linter.verify(code, config, filename);

// Ignore syntax errors for backward compatibility if `errors` is a number.
if (typeof item.errors !== "number") {
const errorMessage = messages.find(m => m.fatal);

assert(!errorMessage, `A fatal parsing error occurred: ${errorMessage && errorMessage.message}`);
}

// Verify if autofix makes a syntax error or not.
if (messages.some(m => m.fix)) {
output = SourceCodeFixer.applyFixes(code, messages).output;
const errorMessageInFix = linter.verify(output, config, filename).find(m => m.fatal);

assert(!errorMessageInFix, `A fatal parsing error occurred in autofix: ${errorMessageInFix && errorMessageInFix.message}`);
} else {
output = code;
}

return {
messages: linter.verify(code, config, filename, true),
messages,
output,
beforeAST,
afterAST: cloneDeeplyExcludesParent(afterAST)
};
Expand Down Expand Up @@ -488,7 +509,6 @@ class RuleTester {
const error = item.errors[i];
const message = messages[i];

assert(!message.fatal, `A fatal parsing error occurred: ${message.message}`);
assert(hasMessageOfThisRule, "Error rule name should be the same as the name of the rule being tested");

if (typeof error === "string" || error instanceof RegExp) {
Expand Down Expand Up @@ -574,14 +594,12 @@ class RuleTester {
if (Object.prototype.hasOwnProperty.call(item, "output")) {
if (item.output === null) {
assert.strictEqual(
messages.filter(message => message.fix).length,
0,
result.output,
item.code,
"Expected no autofixes to be suggested"
);
} else {
const fixResult = SourceCodeFixer.applyFixes(item.code, messages);

assert.strictEqual(fixResult.output, item.output, "Output is incorrect.");
assert.strictEqual(result.output, item.output, "Output is incorrect.");
}
}

Expand Down
50 changes: 40 additions & 10 deletions tests/lib/rule-tester/rule-tester.js
Expand Up @@ -42,22 +42,28 @@ const NODE_ASSERT_STRICT_EQUAL_OPERATOR = (() => {

const ruleTesterTestEmitter = new EventEmitter();

RuleTester.describe = function(text, method) {
ruleTesterTestEmitter.emit("describe", text, method);
return method.call(this);
};

RuleTester.it = function(text, method) {
ruleTesterTestEmitter.emit("it", text, method);
return method.call(this);
};

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

describe("RuleTester", () => {

// Stub `describe()` and `it()` while this test suite.
before(() => {
RuleTester.describe = function(text, method) {
ruleTesterTestEmitter.emit("describe", text, method);
return method.call(this);
};
RuleTester.it = function(text, method) {
ruleTesterTestEmitter.emit("it", text, method);
return method.call(this);
};
});
after(() => {
RuleTester.describe = null;
RuleTester.it = null;
});

let ruleTester;

/**
Expand Down Expand Up @@ -1042,4 +1048,28 @@ describe("RuleTester", () => {
return assertion;
});
});

// https://github.com/eslint/eslint/issues/11615
it("should fail the case if autofix made a syntax error.", () => {
assert.throw(() => {
ruleTester.run(
"foo",
context => ({
Identifier(node) {
context.report({
node,
message: "make a syntax error",
fix(fixer) {
return fixer.replaceText(node, "one two");
}
});
}
}),
{
valid: ["one()"],
invalid: []
}
);
}, /A fatal parsing error occurred in autofix/u);
});
});
2 changes: 1 addition & 1 deletion tests/lib/rules/complexity.js
Expand Up @@ -81,7 +81,7 @@ ruleTester.run("complexity", rule, {
{ code: "var func = function () {}", options: [0], errors: [makeError("Function", 1, 0)] },
{ code: "var obj = { a(x) {} }", options: [0], parserOptions: { ecmaVersion: 6 }, errors: [makeError("Method 'a'", 1, 0)] },
{ code: "class Test { a(x) {} }", options: [0], parserOptions: { ecmaVersion: 6 }, errors: [makeError("Method 'a'", 1, 0)] },
{ code: "var a = (x) => {if (true) {return x;}}", options: [1], errors: 1, settings: { ecmascript: 6 } },
{ code: "var a = (x) => {if (true) {return x;}}", options: [1], parserOptions: { ecmaVersion: 6 }, errors: 1 },
{ code: "function a(x) {if (true) {return x;}}", options: [1], errors: 1 },
{ code: "function a(x) {if (true) {return x;} else {return x+1;}}", options: [1], errors: 1 },
{ code: "function a(x) {if (true) {return x;} else if (false) {return x+1;} else {return 4;}}", options: [2], errors: 1 },
Expand Down
7 changes: 6 additions & 1 deletion tests/lib/rules/quotes.js
Expand Up @@ -160,30 +160,35 @@ ruleTester.run("quotes", rule, {
code: "var foo = 'bar';",
output: "var foo = `bar`;",
options: ["backtick"],
parserOptions: { ecmaVersion: 2015 },
aladdin-add marked this conversation as resolved.
Show resolved Hide resolved
errors: [{ message: "Strings must use backtick.", type: "Literal" }]
},
{
code: "var foo = 'b${x}a$r';",
output: "var foo = `b\\${x}a$r`;",
options: ["backtick"],
parserOptions: { ecmaVersion: 2015 },
errors: [{ message: "Strings must use backtick.", type: "Literal" }]
},
{
code: "var foo = \"bar\";",
output: "var foo = `bar`;",
options: ["backtick"],
parserOptions: { ecmaVersion: 2015 },
errors: [{ message: "Strings must use backtick.", type: "Literal" }]
},
{
code: "var foo = \"bar\";",
output: "var foo = `bar`;",
options: ["backtick", { avoidEscape: true }],
parserOptions: { ecmaVersion: 2015 },
errors: [{ message: "Strings must use backtick.", type: "Literal" }]
},
{
code: "var foo = 'bar';",
output: "var foo = `bar`;",
options: ["backtick", { avoidEscape: true }],
parserOptions: { ecmaVersion: 2015 },
errors: [{ message: "Strings must use backtick.", type: "Literal" }]
},

Expand Down Expand Up @@ -255,7 +260,7 @@ ruleTester.run("quotes", rule, {
code: "<div blah={'blah'} />",
output: "<div blah={`blah`} />",
options: ["backtick"],
parserOptions: { ecmaFeatures: { jsx: true } },
parserOptions: { ecmaFeatures: { jsx: true }, ecmaVersion: 2015 },
errors: [
{ message: "Strings must use backtick.", type: "Literal" }
]
Expand Down