Skip to content

Commit ae54195

Browse files
authored
Ensure the assertion message is a string (#314)
1 parent 2b04f84 commit ae54195

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

docs/rules/assertion-arguments.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const test = require('ava');
1616
test(t => {
1717
t.is(value); // Not enough arguments
1818
t.is(value, expected, message, extra); // Too many arguments
19+
t.is(value, expected, false); // Assertion message is not a string
1920
});
2021

2122
/* eslint ava/assertion-arguments: ["error", {"message": "always"}] */

rules/assertion-arguments.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22
const {visitIf} = require('enhance-visitors');
3-
const {getStaticValue, isOpeningParenToken, isCommaToken} = require('eslint-utils');
3+
const {getStaticValue, isOpeningParenToken, isCommaToken, findVariable} = require('eslint-utils');
44
const util = require('../util');
55
const createAvaRule = require('../create-ava-rule');
66

@@ -203,6 +203,13 @@ function noComments(sourceCode, ...nodes) {
203203
});
204204
}
205205

206+
function isString(node) {
207+
const {type} = node;
208+
return type === 'TemplateLiteral' ||
209+
type === 'TaggedTemplateExpression' ||
210+
(type === 'Literal' && typeof node.value === 'string');
211+
}
212+
206213
const create = context => {
207214
const ava = createAvaRule();
208215
const options = context.options[0] || {};
@@ -271,6 +278,24 @@ const create = context => {
271278

272279
checkArgumentOrder({node, assertion: firstNonSkipMember, context});
273280
}
281+
282+
if (gottenArgs === nArgs.max && nArgs.min !== nArgs.max) {
283+
let lastArg = node.arguments[node.arguments.length - 1];
284+
285+
if (lastArg.type === 'Identifier') {
286+
const variable = findVariable(context.getScope(), lastArg);
287+
let value;
288+
for (const ref of variable.references) {
289+
value = ref.writeExpr || value;
290+
}
291+
292+
lastArg = value;
293+
}
294+
295+
if (!isString(lastArg)) {
296+
report(node, 'Assertion message should be a string.');
297+
}
298+
}
274299
})
275300
});
276301
};

test/assertion-arguments.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const outOfOrderError = (line, column, endLine, endColumn) => ({
1919
message: 'Expected values should come after actual values.',
2020
line, column, endLine, endColumn
2121
});
22+
const messageIsNotStringError = 'Assertion message should be a string.';
2223

2324
const header = 'const test = require(\'ava\');';
2425

@@ -331,7 +332,11 @@ ruleTester.run('assertion-arguments', rule, {
331332
testCase(false, 't.regex(\'static\', new RegExp(\'[dynamic]+\'));'),
332333
testCase(false, 't.regex(dynamic, /[static]/);'),
333334
testCase(false, 't.notRegex(\'static\', new RegExp(\'[dynamic]+\'));'),
334-
testCase(false, 't.notRegex(dynamic, /[static]/);')
335+
testCase(false, 't.notRegex(dynamic, /[static]/);'),
336+
337+
// Lookup message type
338+
testCase(false, 'const message = \'ok\'; t.assert(true, message);'),
339+
testCase(false, 'const message = \'ok\'; t.is(42, 42, message);')
335340
],
336341
invalid: [
337342
// Not enough arguments
@@ -538,6 +543,12 @@ ruleTester.run('assertion-arguments', rule, {
538543
outOfOrderError(1, 13, 1, 23 + expression.length),
539544
{output: `t.deepEqual(${expression}, 'static');`}
540545
)
541-
)
546+
),
547+
548+
// Message is not string
549+
testCase(false, 't.assert(true, true);', messageIsNotStringError),
550+
testCase(false, 't.deepEqual({}, {}, 42);', messageIsNotStringError),
551+
testCase(false, 't.fail({});', messageIsNotStringError),
552+
testCase(false, 'let message = "ok"; message = false; t.assert(true, message);', messageIsNotStringError)
542553
]
543554
});

0 commit comments

Comments
 (0)