Skip to content

Commit 49120aa

Browse files
committedApr 28, 2019
Ensure the assertion message is a string
Fixes #1125.
1 parent 0804107 commit 49120aa

File tree

2 files changed

+307
-9
lines changed

2 files changed

+307
-9
lines changed
 

‎lib/assert.js

+104-9
Original file line numberDiff line numberDiff line change
@@ -265,18 +265,46 @@ class Assertions {
265265
patterns: [pattern]
266266
});
267267

268+
const checkMessage = (assertion, message, powerAssert = false) => {
269+
if (typeof message === 'undefined' || typeof message === 'string') {
270+
return true;
271+
}
272+
273+
const error = new AssertionError({
274+
assertion,
275+
improperUsage: true,
276+
message: 'The assertion message must be a string',
277+
values: [formatWithLabel('Called with:', message)]
278+
});
279+
280+
if (powerAssert) {
281+
throw error;
282+
}
283+
284+
fail(error);
285+
return false;
286+
};
287+
268288
this.pass = withSkip(() => {
269289
pass();
270290
});
271291

272292
this.fail = withSkip(message => {
293+
if (!checkMessage('fail', message)) {
294+
return;
295+
}
296+
273297
fail(new AssertionError({
274298
assertion: 'fail',
275299
message: message || 'Test failed via `t.fail()`'
276300
}));
277301
});
278302

279303
this.is = withSkip((actual, expected, message) => {
304+
if (!checkMessage('is', message)) {
305+
return;
306+
}
307+
280308
if (Object.is(actual, expected)) {
281309
pass();
282310
} else {
@@ -303,6 +331,10 @@ class Assertions {
303331
});
304332

305333
this.not = withSkip((actual, expected, message) => {
334+
if (!checkMessage('not', message)) {
335+
return;
336+
}
337+
306338
if (Object.is(actual, expected)) {
307339
fail(new AssertionError({
308340
assertion: 'not',
@@ -316,6 +348,10 @@ class Assertions {
316348
});
317349

318350
this.deepEqual = withSkip((actual, expected, message) => {
351+
if (!checkMessage('deepEqual', message)) {
352+
return;
353+
}
354+
319355
const result = concordance.compare(actual, expected, concordanceOptions);
320356
if (result.pass) {
321357
pass();
@@ -332,6 +368,10 @@ class Assertions {
332368
});
333369

334370
this.notDeepEqual = withSkip((actual, expected, message) => {
371+
if (!checkMessage('notDeepEqual', message)) {
372+
return;
373+
}
374+
335375
const result = concordance.compare(actual, expected, concordanceOptions);
336376
if (result.pass) {
337377
const actualDescriptor = result.actual || concordance.describe(actual, concordanceOptions);
@@ -351,6 +391,11 @@ class Assertions {
351391
// operator, so we can determine the total number of arguments passed
352392
// to the function.
353393
let [fn, expectations, message] = args;
394+
395+
if (!checkMessage('throws', message)) {
396+
return;
397+
}
398+
354399
if (typeof fn !== 'function') {
355400
fail(new AssertionError({
356401
assertion: 'throws',
@@ -412,6 +457,11 @@ class Assertions {
412457

413458
this.throwsAsync = withSkip((...args) => {
414459
let [thrower, expectations, message] = args;
460+
461+
if (!checkMessage('throwsAsync', message)) {
462+
return Promise.resolve();
463+
}
464+
415465
if (typeof thrower !== 'function' && !isPromise(thrower)) {
416466
fail(new AssertionError({
417467
assertion: 'throwsAsync',
@@ -492,6 +542,10 @@ class Assertions {
492542
});
493543

494544
this.notThrows = withSkip((fn, message) => {
545+
if (!checkMessage('notThrows', message)) {
546+
return;
547+
}
548+
495549
if (typeof fn !== 'function') {
496550
fail(new AssertionError({
497551
assertion: 'notThrows',
@@ -518,6 +572,10 @@ class Assertions {
518572
});
519573

520574
this.notThrowsAsync = withSkip((nonThrower, message) => {
575+
if (!checkMessage('notThrowsAsync', message)) {
576+
return Promise.resolve();
577+
}
578+
521579
if (typeof nonThrower !== 'function' && !isPromise(nonThrower)) {
522580
fail(new AssertionError({
523581
assertion: 'notThrowsAsync',
@@ -574,20 +632,31 @@ class Assertions {
574632
return handlePromise(retval, true);
575633
});
576634

577-
this.snapshot = withSkip((expected, optionsOrMessage, message) => {
578-
const options = {};
579-
if (typeof optionsOrMessage === 'string') {
580-
message = optionsOrMessage;
581-
} else if (optionsOrMessage) {
582-
options.id = optionsOrMessage.id;
635+
this.snapshot = withSkip((expected, ...rest) => {
636+
let message;
637+
let snapshotOptions;
638+
if (rest.length > 1) {
639+
[snapshotOptions, message] = rest;
640+
} else {
641+
const [optionsOrMessage] = rest;
642+
if (typeof optionsOrMessage === 'object') {
643+
snapshotOptions = optionsOrMessage;
644+
} else {
645+
message = optionsOrMessage;
646+
}
583647
}
584648

585-
options.expected = expected;
586-
options.message = message;
649+
if (!checkMessage('snapshot', message)) {
650+
return;
651+
}
587652

588653
let result;
589654
try {
590-
result = compareWithSnapshot(options);
655+
result = compareWithSnapshot({
656+
expected,
657+
id: snapshotOptions ? snapshotOptions.id : undefined,
658+
message
659+
});
591660
} catch (error) {
592661
if (!(error instanceof snapshotManager.SnapshotError)) {
593662
throw error;
@@ -625,6 +694,10 @@ class Assertions {
625694
});
626695

627696
this.truthy = withSkip((actual, message) => {
697+
if (!checkMessage('truthy', message)) {
698+
return;
699+
}
700+
628701
if (actual) {
629702
pass();
630703
} else {
@@ -638,6 +711,10 @@ class Assertions {
638711
});
639712

640713
this.falsy = withSkip((actual, message) => {
714+
if (!checkMessage('falsy', message)) {
715+
return;
716+
}
717+
641718
if (actual) {
642719
fail(new AssertionError({
643720
assertion: 'falsy',
@@ -651,6 +728,10 @@ class Assertions {
651728
});
652729

653730
this.true = withSkip((actual, message) => {
731+
if (!checkMessage('true', message)) {
732+
return;
733+
}
734+
654735
if (actual === true) {
655736
pass();
656737
} else {
@@ -663,6 +744,10 @@ class Assertions {
663744
});
664745

665746
this.false = withSkip((actual, message) => {
747+
if (!checkMessage('false', message)) {
748+
return;
749+
}
750+
666751
if (actual === false) {
667752
pass();
668753
} else {
@@ -675,6 +760,10 @@ class Assertions {
675760
});
676761

677762
this.regex = withSkip((string, regex, message) => {
763+
if (!checkMessage('regex', message)) {
764+
return;
765+
}
766+
678767
if (typeof string !== 'string') {
679768
fail(new AssertionError({
680769
assertion: 'regex',
@@ -711,6 +800,10 @@ class Assertions {
711800
});
712801

713802
this.notRegex = withSkip((string, regex, message) => {
803+
if (!checkMessage('notRegex', message)) {
804+
return;
805+
}
806+
714807
if (typeof string !== 'string') {
715808
fail(new AssertionError({
716809
assertion: 'notRegex',
@@ -749,6 +842,8 @@ class Assertions {
749842
this.assert = withSkip(withPowerAssert(
750843
'assert(value, [message])',
751844
(actual, message) => {
845+
checkMessage('assert', message, true);
846+
752847
if (!actual) {
753848
throw new AssertionError({
754849
assertion: 'assert',

‎test/assert.js

+203
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,18 @@ test('.fail()', t => {
201201
message: 'Test failed via `t.fail()`'
202202
});
203203

204+
failsWith(t, () => {
205+
assertions.fail(null);
206+
}, {
207+
assertion: 'fail',
208+
improperUsage: true,
209+
message: 'The assertion message must be a string',
210+
values: [{
211+
label: 'Called with:',
212+
formatted: /null/
213+
}]
214+
});
215+
204216
t.end();
205217
});
206218

@@ -383,6 +395,18 @@ test('.is()', t => {
383395
]
384396
});
385397

398+
failsWith(t, () => {
399+
assertions.is(0, 0, null);
400+
}, {
401+
assertion: 'is',
402+
improperUsage: true,
403+
message: 'The assertion message must be a string',
404+
values: [{
405+
label: 'Called with:',
406+
formatted: /null/
407+
}]
408+
});
409+
386410
t.end();
387411
});
388412

@@ -421,6 +445,18 @@ test('.not()', t => {
421445
values: [{label: 'Value is the same as:', formatted: /foo/}]
422446
});
423447

448+
failsWith(t, () => {
449+
assertions.not(0, 1, null);
450+
}, {
451+
assertion: 'not',
452+
improperUsage: true,
453+
message: 'The assertion message must be a string',
454+
values: [{
455+
label: 'Called with:',
456+
formatted: /null/
457+
}]
458+
});
459+
424460
t.end();
425461
});
426462

@@ -682,6 +718,18 @@ test('.deepEqual()', t => {
682718
values: [{label: 'Difference:', formatted: /- 'foo'\n\+ 42/}]
683719
});
684720

721+
failsWith(t, () => {
722+
assertions.deepEqual({}, {}, null);
723+
}, {
724+
assertion: 'deepEqual',
725+
improperUsage: true,
726+
message: 'The assertion message must be a string',
727+
values: [{
728+
label: 'Called with:',
729+
formatted: /null/
730+
}]
731+
});
732+
685733
t.end();
686734
});
687735

@@ -720,6 +768,18 @@ test('.notDeepEqual()', t => {
720768
values: [{label: 'Value is deeply equal:', formatted: /.*\[.*\n.*'a',\n.*'b',/}]
721769
});
722770

771+
failsWith(t, () => {
772+
assertions.notDeepEqual({}, [], null);
773+
}, {
774+
assertion: 'notDeepEqual',
775+
improperUsage: true,
776+
message: 'The assertion message must be a string',
777+
values: [{
778+
label: 'Called with:',
779+
formatted: /null/
780+
}]
781+
});
782+
723783
t.end();
724784
});
725785

@@ -921,6 +981,18 @@ test('.throws()', gather(t => {
921981
throw new Error('foo');
922982
}, undefined);
923983
});
984+
985+
failsWith(t, () => {
986+
assertions.throws(() => {}, null, null);
987+
}, {
988+
assertion: 'throws',
989+
improperUsage: true,
990+
message: 'The assertion message must be a string',
991+
values: [{
992+
label: 'Called with:',
993+
formatted: /null/
994+
}]
995+
});
924996
}));
925997

926998
test('.throws() returns the thrown error', t => {
@@ -1003,6 +1075,16 @@ test('.throwsAsync()', gather(t => {
10031075
{label: 'Function returned:', formatted: /undefined/}
10041076
]
10051077
});
1078+
1079+
eventuallyFailsWith(t, () => assertions.throwsAsync(Promise.resolve(), null, null), {
1080+
assertion: 'throwsAsync',
1081+
improperUsage: true,
1082+
message: 'The assertion message must be a string',
1083+
values: [{
1084+
label: 'Called with:',
1085+
formatted: /null/
1086+
}]
1087+
});
10061088
}));
10071089

10081090
test('.throwsAsync() returns the rejection reason of promise', t => {
@@ -1218,6 +1300,18 @@ test('.notThrows()', gather(t => {
12181300
message: 'my message',
12191301
values: [{label: 'Function threw:', formatted: /foo/}]
12201302
});
1303+
1304+
failsWith(t, () => {
1305+
assertions.notThrows(() => {}, null);
1306+
}, {
1307+
assertion: 'notThrows',
1308+
improperUsage: true,
1309+
message: 'The assertion message must be a string',
1310+
values: [{
1311+
label: 'Called with:',
1312+
formatted: /null/
1313+
}]
1314+
});
12211315
}));
12221316

12231317
test('.notThrowsAsync()', gather(t => {
@@ -1265,6 +1359,16 @@ test('.notThrowsAsync()', gather(t => {
12651359
{label: 'Function did not return a promise. Use `t.notThrows()` instead:', formatted: /undefined/}
12661360
]
12671361
});
1362+
1363+
eventuallyFailsWith(t, () => assertions.notThrowsAsync(Promise.resolve(), null), {
1364+
assertion: 'notThrowsAsync',
1365+
improperUsage: true,
1366+
message: 'The assertion message must be a string',
1367+
values: [{
1368+
label: 'Called with:',
1369+
formatted: /null/
1370+
}]
1371+
});
12681372
}));
12691373

12701374
test('.notThrowsAsync() returns undefined for a fulfilled promise', t => {
@@ -1443,6 +1547,21 @@ test('.snapshot()', t => {
14431547
}
14441548
}
14451549

1550+
{
1551+
const assertions = setup('bad message');
1552+
failsWith(t, () => {
1553+
assertions.snapshot(null, null, null);
1554+
}, {
1555+
assertion: 'snapshot',
1556+
improperUsage: true,
1557+
message: 'The assertion message must be a string',
1558+
values: [{
1559+
label: 'Called with:',
1560+
formatted: /null/
1561+
}]
1562+
});
1563+
}
1564+
14461565
manager.save();
14471566
t.end();
14481567
});
@@ -1477,6 +1596,18 @@ test('.truthy()', t => {
14771596
truthy(true);
14781597
});
14791598

1599+
failsWith(t, () => {
1600+
assertions.truthy(true, null);
1601+
}, {
1602+
assertion: 'truthy',
1603+
improperUsage: true,
1604+
message: 'The assertion message must be a string',
1605+
values: [{
1606+
label: 'Called with:',
1607+
formatted: /null/
1608+
}]
1609+
});
1610+
14801611
t.end();
14811612
});
14821613

@@ -1510,6 +1641,18 @@ test('.falsy()', t => {
15101641
falsy(false);
15111642
});
15121643

1644+
failsWith(t, () => {
1645+
assertions.falsy(false, null);
1646+
}, {
1647+
assertion: 'falsy',
1648+
improperUsage: true,
1649+
message: 'The assertion message must be a string',
1650+
values: [{
1651+
label: 'Called with:',
1652+
formatted: /null/
1653+
}]
1654+
});
1655+
15131656
t.end();
15141657
});
15151658

@@ -1555,6 +1698,18 @@ test('.true()', t => {
15551698
trueFn(true);
15561699
});
15571700

1701+
failsWith(t, () => {
1702+
assertions.true(true, null);
1703+
}, {
1704+
assertion: 'true',
1705+
improperUsage: true,
1706+
message: 'The assertion message must be a string',
1707+
values: [{
1708+
label: 'Called with:',
1709+
formatted: /null/
1710+
}]
1711+
});
1712+
15581713
t.end();
15591714
});
15601715

@@ -1600,6 +1755,18 @@ test('.false()', t => {
16001755
falseFn(false);
16011756
});
16021757

1758+
failsWith(t, () => {
1759+
assertions.false(false, null);
1760+
}, {
1761+
assertion: 'false',
1762+
improperUsage: true,
1763+
message: 'The assertion message must be a string',
1764+
values: [{
1765+
label: 'Called with:',
1766+
formatted: /null/
1767+
}]
1768+
});
1769+
16031770
t.end();
16041771
});
16051772

@@ -1635,6 +1802,18 @@ test('.regex()', t => {
16351802
]
16361803
});
16371804

1805+
failsWith(t, () => {
1806+
assertions.regex('foo', /^abc$/, null);
1807+
}, {
1808+
assertion: 'regex',
1809+
improperUsage: true,
1810+
message: 'The assertion message must be a string',
1811+
values: [{
1812+
label: 'Called with:',
1813+
formatted: /null/
1814+
}]
1815+
});
1816+
16381817
t.end();
16391818
});
16401819

@@ -1691,6 +1870,18 @@ test('.notRegex()', t => {
16911870
]
16921871
});
16931872

1873+
failsWith(t, () => {
1874+
assertions.notRegex('abc', /abc/, null);
1875+
}, {
1876+
assertion: 'notRegex',
1877+
improperUsage: true,
1878+
message: 'The assertion message must be a string',
1879+
values: [{
1880+
label: 'Called with:',
1881+
formatted: /null/
1882+
}]
1883+
});
1884+
16941885
t.end();
16951886
});
16961887

@@ -1744,5 +1935,17 @@ test('.assert()', t => {
17441935
assert(true);
17451936
});
17461937

1938+
failsWith(t, () => {
1939+
assertions.assert(null, null);
1940+
}, {
1941+
assertion: 'assert',
1942+
improperUsage: true,
1943+
message: 'The assertion message must be a string',
1944+
values: [{
1945+
label: 'Called with:',
1946+
formatted: /null/
1947+
}]
1948+
});
1949+
17471950
t.end();
17481951
});

0 commit comments

Comments
 (0)
Please sign in to comment.