assert.js 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502
  1. 'use strict';
  2. require('../lib/chalk').set();
  3. require('../lib/worker/options').set({color: false});
  4. const path = require('path');
  5. const stripAnsi = require('strip-ansi');
  6. const React = require('react');
  7. const renderer = require('react-test-renderer');
  8. const test = require('tap').test;
  9. const Observable = require('zen-observable');
  10. const assert = require('../lib/assert');
  11. const snapshotManager = require('../lib/snapshot-manager');
  12. const Test = require('../lib/test');
  13. const HelloMessage = require('./fixture/hello-message');
  14. let lastFailure = null;
  15. let lastPassed = false;
  16. const assertions = assert.wrapAssertions({
  17. pass(testObj) {
  18. if (testObj !== assertions && !(testObj instanceof Test)) {
  19. throw new Error('Expected testObj');
  20. }
  21. lastPassed = true;
  22. },
  23. pending(testObj, promise) {
  24. if (testObj !== assertions && !(testObj instanceof Test)) {
  25. throw new Error('Expected testObj');
  26. }
  27. promise.then(() => {
  28. lastPassed = true;
  29. }, err => {
  30. lastFailure = err;
  31. });
  32. },
  33. fail(testObj, error) {
  34. if (testObj !== assertions && !(testObj instanceof Test)) {
  35. throw new Error('Expected testObj');
  36. }
  37. lastFailure = error;
  38. }
  39. });
  40. function assertFailure(t, subset) {
  41. if (!lastFailure) {
  42. t.fail('Expected assertion to fail');
  43. return;
  44. }
  45. t.is(lastFailure.assertion, subset.assertion);
  46. t.is(lastFailure.message, subset.message);
  47. t.is(lastFailure.name, 'AssertionError');
  48. t.is(lastFailure.operator, subset.operator);
  49. if (subset.raw) {
  50. t.is(lastFailure.raw.expected, subset.raw.expected);
  51. t.is(lastFailure.raw.actual, subset.raw.actual);
  52. }
  53. if (subset.statements) {
  54. t.is(lastFailure.statements.length, subset.statements.length);
  55. lastFailure.statements.forEach((s, i) => {
  56. t.is(s[0], subset.statements[i][0]);
  57. t.match(s[1], subset.statements[i][1]);
  58. });
  59. } else {
  60. t.same(lastFailure.statements, []);
  61. }
  62. if (subset.values) {
  63. t.is(lastFailure.values.length, subset.values.length);
  64. lastFailure.values.forEach((s, i) => {
  65. t.is(s.label, subset.values[i].label);
  66. t.match(stripAnsi(s.formatted), subset.values[i].formatted);
  67. });
  68. } else {
  69. t.same(lastFailure.values, []);
  70. }
  71. }
  72. let gathering = false;
  73. let gatheringPromise = Promise.resolve();
  74. function gather(run) {
  75. return t => {
  76. if (gathering) {
  77. throw new Error('Cannot nest gather()');
  78. }
  79. gathering = true;
  80. try {
  81. run(t);
  82. return gatheringPromise;
  83. } finally {
  84. gathering = false;
  85. gatheringPromise = Promise.resolve();
  86. }
  87. };
  88. }
  89. function add(fn) {
  90. if (!gathering) {
  91. throw new Error('Cannot add promise, must be called from gather() callback');
  92. }
  93. gatheringPromise = gatheringPromise.then(fn);
  94. return gatheringPromise;
  95. }
  96. function failsWith(t, fn, subset) {
  97. lastFailure = null;
  98. fn();
  99. assertFailure(t, subset);
  100. }
  101. function eventuallyFailsWith(t, fn, subset) {
  102. return add(() => {
  103. lastFailure = null;
  104. return fn().then(() => {
  105. assertFailure(t, subset);
  106. });
  107. });
  108. }
  109. function fails(t, fn) {
  110. lastFailure = null;
  111. fn();
  112. if (lastFailure) {
  113. t.pass();
  114. } else {
  115. t.fail('Expected assertion to fail');
  116. }
  117. }
  118. /* Might be useful
  119. function eventuallyFails(t, fn) {
  120. return add(() => {
  121. lastFailure = null;
  122. return fn().then(() => {
  123. if (lastFailure) {
  124. t.pass();
  125. } else {
  126. t.fail('Expected assertion to fail');
  127. }
  128. });
  129. });
  130. }
  131. */
  132. function passes(t, fn) {
  133. lastPassed = false;
  134. lastFailure = null;
  135. fn();
  136. if (lastPassed) {
  137. t.pass();
  138. } else {
  139. t.ifError(lastFailure, 'Expected assertion to pass');
  140. }
  141. }
  142. function eventuallyPasses(t, fn) {
  143. return add(() => {
  144. lastPassed = false;
  145. lastFailure = null;
  146. return fn().then(() => {
  147. if (lastPassed) {
  148. t.pass();
  149. } else {
  150. t.ifError(lastFailure, 'Expected assertion to pass');
  151. }
  152. });
  153. });
  154. }
  155. test('.pass()', t => {
  156. passes(t, () => {
  157. assertions.pass();
  158. });
  159. t.end();
  160. });
  161. test('.fail()', t => {
  162. failsWith(t, () => {
  163. assertions.fail();
  164. }, {
  165. assertion: 'fail',
  166. message: 'Test failed via `t.fail()`'
  167. });
  168. failsWith(t, () => {
  169. assertions.fail('my message');
  170. }, {
  171. assertion: 'fail',
  172. message: 'my message'
  173. });
  174. t.end();
  175. });
  176. test('.is()', t => {
  177. passes(t, () => {
  178. assertions.is('foo', 'foo');
  179. });
  180. passes(t, () => {
  181. assertions.is('', '');
  182. });
  183. passes(t, () => {
  184. assertions.is(true, true);
  185. });
  186. passes(t, () => {
  187. assertions.is(false, false);
  188. });
  189. passes(t, () => {
  190. assertions.is(null, null);
  191. });
  192. passes(t, () => {
  193. assertions.is(undefined, undefined);
  194. });
  195. passes(t, () => {
  196. assertions.is(1, 1);
  197. });
  198. passes(t, () => {
  199. assertions.is(0, 0);
  200. });
  201. passes(t, () => {
  202. assertions.is(-0, -0);
  203. });
  204. passes(t, () => {
  205. assertions.is(NaN, NaN);
  206. });
  207. passes(t, () => {
  208. assertions.is(0 / 0, NaN);
  209. });
  210. passes(t, () => {
  211. const someRef = {foo: 'bar'};
  212. assertions.is(someRef, someRef);
  213. });
  214. fails(t, () => {
  215. assertions.is(0, -0);
  216. });
  217. fails(t, () => {
  218. assertions.is(0, false);
  219. });
  220. fails(t, () => {
  221. assertions.is('', false);
  222. });
  223. fails(t, () => {
  224. assertions.is('0', 0);
  225. });
  226. fails(t, () => {
  227. assertions.is('17', 17);
  228. });
  229. fails(t, () => {
  230. assertions.is([1, 2], '1,2');
  231. });
  232. fails(t, () => {
  233. // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
  234. assertions.is(new String('foo'), 'foo');
  235. });
  236. fails(t, () => {
  237. assertions.is(null, undefined);
  238. });
  239. fails(t, () => {
  240. assertions.is(null, false);
  241. });
  242. fails(t, () => {
  243. assertions.is(undefined, false);
  244. });
  245. fails(t, () => {
  246. // eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
  247. assertions.is(new String('foo'), new String('foo'));
  248. });
  249. fails(t, () => {
  250. assertions.is(0, null);
  251. });
  252. fails(t, () => {
  253. assertions.is(0, NaN);
  254. });
  255. fails(t, () => {
  256. assertions.is('foo', NaN);
  257. });
  258. failsWith(t, () => {
  259. assertions.is({foo: 'bar'}, {foo: 'bar'});
  260. }, {
  261. assertion: 'is',
  262. message: '',
  263. actual: {foo: 'bar'},
  264. expected: {foo: 'bar'},
  265. values: [{
  266. label: `Values are deeply equal to each other, but they are not the same:`,
  267. formatted: /foo/
  268. }]
  269. });
  270. failsWith(t, () => {
  271. assertions.is('foo', 'bar');
  272. }, {
  273. assertion: 'is',
  274. message: '',
  275. raw: {actual: 'foo', expected: 'bar'},
  276. values: [
  277. {label: 'Difference:', formatted: /- 'foo'\n\+ 'bar'/}
  278. ]
  279. });
  280. failsWith(t, () => {
  281. assertions.is('foo', 42);
  282. }, {
  283. actual: 'foo',
  284. assertion: 'is',
  285. expected: 42,
  286. message: '',
  287. values: [
  288. {label: 'Difference:', formatted: /- 'foo'\n\+ 42/}
  289. ]
  290. });
  291. failsWith(t, () => {
  292. assertions.is('foo', 42, 'my message');
  293. }, {
  294. assertion: 'is',
  295. message: 'my message',
  296. values: [
  297. {label: 'Difference:', formatted: /- 'foo'\n\+ 42/}
  298. ]
  299. });
  300. failsWith(t, () => {
  301. assertions.is(0, -0, 'my message');
  302. }, {
  303. assertion: 'is',
  304. message: 'my message',
  305. values: [
  306. {label: 'Difference:', formatted: /- 0\n\+ -0/}
  307. ]
  308. });
  309. failsWith(t, () => {
  310. assertions.is(-0, 0, 'my message');
  311. }, {
  312. assertion: 'is',
  313. message: 'my message',
  314. values: [
  315. {label: 'Difference:', formatted: /- -0\n\+ 0/}
  316. ]
  317. });
  318. t.end();
  319. });
  320. test('.not()', t => {
  321. passes(t, () => {
  322. assertions.not('foo', 'bar');
  323. });
  324. fails(t, () => {
  325. assertions.not(NaN, NaN);
  326. });
  327. fails(t, () => {
  328. assertions.not(0 / 0, NaN);
  329. });
  330. failsWith(t, () => {
  331. assertions.not('foo', 'foo');
  332. }, {
  333. assertion: 'not',
  334. message: '',
  335. raw: {actual: 'foo', expected: 'foo'},
  336. values: [{label: 'Value is the same as:', formatted: /foo/}]
  337. });
  338. failsWith(t, () => {
  339. assertions.not('foo', 'foo', 'my message');
  340. }, {
  341. assertion: 'not',
  342. message: 'my message',
  343. values: [{label: 'Value is the same as:', formatted: /foo/}]
  344. });
  345. t.end();
  346. });
  347. test('.deepEqual()', t => {
  348. // Tests starting here are to detect regressions in the underlying libraries
  349. // used to test deep object equality
  350. fails(t, () => {
  351. assertions.deepEqual({a: false}, {a: 0});
  352. });
  353. passes(t, () => {
  354. assertions.deepEqual({
  355. a: 'a',
  356. b: 'b'
  357. }, {
  358. b: 'b',
  359. a: 'a'
  360. });
  361. });
  362. passes(t, () => {
  363. assertions.deepEqual({
  364. a: 'a',
  365. b: 'b',
  366. c: {
  367. d: 'd'
  368. }
  369. }, {
  370. c: {
  371. d: 'd'
  372. },
  373. b: 'b',
  374. a: 'a'
  375. });
  376. });
  377. fails(t, () => {
  378. assertions.deepEqual([1, 2, 3], [1, 2, 3, 4]);
  379. });
  380. passes(t, () => {
  381. assertions.deepEqual([1, 2, 3], [1, 2, 3]);
  382. });
  383. fails(t, () => {
  384. const fnA = a => a;
  385. const fnB = a => a;
  386. assertions.deepEqual(fnA, fnB);
  387. });
  388. passes(t, () => {
  389. const x1 = {z: 4};
  390. const y1 = {x: x1};
  391. x1.y = y1;
  392. const x2 = {z: 4};
  393. const y2 = {x: x2};
  394. x2.y = y2;
  395. assertions.deepEqual(x1, x2);
  396. });
  397. passes(t, () => {
  398. function Foo(a) {
  399. this.a = a;
  400. }
  401. const x = new Foo(1);
  402. const y = new Foo(1);
  403. assertions.deepEqual(x, y);
  404. });
  405. fails(t, () => {
  406. function Foo(a) {
  407. this.a = a;
  408. }
  409. function Bar(a) {
  410. this.a = a;
  411. }
  412. const x = new Foo(1);
  413. const y = new Bar(1);
  414. assertions.deepEqual(x, y);
  415. });
  416. fails(t, () => {
  417. assertions.deepEqual({
  418. a: 'a',
  419. b: 'b',
  420. c: {
  421. d: false
  422. }
  423. }, {
  424. c: {
  425. d: 0
  426. },
  427. b: 'b',
  428. a: 'a'
  429. });
  430. });
  431. fails(t, () => {
  432. assertions.deepEqual({}, []);
  433. });
  434. fails(t, () => {
  435. assertions.deepEqual({0: 'a', 1: 'b'}, ['a', 'b']);
  436. });
  437. fails(t, () => {
  438. assertions.deepEqual({a: 1}, {a: 1, b: undefined});
  439. });
  440. fails(t, () => {
  441. assertions.deepEqual(new Date('1972-08-01'), null);
  442. });
  443. fails(t, () => {
  444. assertions.deepEqual(new Date('1972-08-01'), undefined);
  445. });
  446. passes(t, () => {
  447. assertions.deepEqual(new Date('1972-08-01'), new Date('1972-08-01'));
  448. });
  449. passes(t, () => {
  450. assertions.deepEqual({x: new Date('1972-08-01')}, {x: new Date('1972-08-01')});
  451. });
  452. fails(t, () => {
  453. assertions.deepEqual(() => {}, () => {});
  454. });
  455. passes(t, () => {
  456. assertions.deepEqual(undefined, undefined);
  457. assertions.deepEqual({x: undefined}, {x: undefined});
  458. assertions.deepEqual({x: [undefined]}, {x: [undefined]});
  459. });
  460. passes(t, () => {
  461. assertions.deepEqual(null, null);
  462. assertions.deepEqual({x: null}, {x: null});
  463. assertions.deepEqual({x: [null]}, {x: [null]});
  464. });
  465. passes(t, () => {
  466. assertions.deepEqual(0, 0);
  467. assertions.deepEqual(1, 1);
  468. assertions.deepEqual(3.14, 3.14);
  469. });
  470. fails(t, () => {
  471. assertions.deepEqual(0, 1);
  472. });
  473. fails(t, () => {
  474. assertions.deepEqual(1, -1);
  475. });
  476. fails(t, () => {
  477. assertions.deepEqual(3.14, 2.72);
  478. });
  479. fails(t, () => {
  480. assertions.deepEqual({0: 'a', 1: 'b'}, ['a', 'b']);
  481. });
  482. passes(t, () => {
  483. assertions.deepEqual(
  484. [
  485. {foo: {z: 100, y: 200, x: 300}},
  486. 'bar',
  487. 11,
  488. {baz: {d: 4, a: 1, b: 2, c: 3}}
  489. ],
  490. [
  491. {foo: {x: 300, y: 200, z: 100}},
  492. 'bar',
  493. 11,
  494. {baz: {c: 3, b: 2, a: 1, d: 4}}
  495. ]
  496. );
  497. });
  498. passes(t, () => {
  499. assertions.deepEqual(
  500. {x: {a: 1, b: 2}, y: {c: 3, d: 4}},
  501. {y: {d: 4, c: 3}, x: {b: 2, a: 1}}
  502. );
  503. });
  504. passes(t, () => {
  505. assertions.deepEqual(
  506. renderer.create(React.createElement(HelloMessage, {name: 'Sindre'})).toJSON(),
  507. React.createElement('div', null, 'Hello ', React.createElement('mark', null, 'Sindre'))
  508. );
  509. });
  510. // Regression test end here
  511. passes(t, () => {
  512. assertions.deepEqual({a: 'a'}, {a: 'a'});
  513. });
  514. passes(t, () => {
  515. assertions.deepEqual(['a', 'b'], ['a', 'b']);
  516. });
  517. fails(t, () => {
  518. assertions.deepEqual({a: 'a'}, {a: 'b'});
  519. });
  520. fails(t, () => {
  521. assertions.deepEqual(['a', 'b'], ['a', 'a']);
  522. });
  523. fails(t, () => {
  524. assertions.deepEqual([['a', 'b'], 'c'], [['a', 'b'], 'd']);
  525. });
  526. fails(t, () => {
  527. const circular = ['a', 'b'];
  528. circular.push(circular);
  529. assertions.deepEqual([circular, 'c'], [circular, 'd']);
  530. });
  531. failsWith(t, () => {
  532. assertions.deepEqual('foo', 'bar');
  533. }, {
  534. assertion: 'deepEqual',
  535. message: '',
  536. raw: {actual: 'foo', expected: 'bar'},
  537. values: [{label: 'Difference:', formatted: /- 'foo'\n\+ 'bar'/}]
  538. });
  539. failsWith(t, () => {
  540. assertions.deepEqual('foo', 42);
  541. }, {
  542. assertion: 'deepEqual',
  543. message: '',
  544. raw: {actual: 'foo', expected: 42},
  545. values: [{label: 'Difference:', formatted: /- 'foo'\n\+ 42/}]
  546. });
  547. failsWith(t, () => {
  548. assertions.deepEqual('foo', 42, 'my message');
  549. }, {
  550. assertion: 'deepEqual',
  551. message: 'my message',
  552. values: [{label: 'Difference:', formatted: /- 'foo'\n\+ 42/}]
  553. });
  554. t.end();
  555. });
  556. test('.notDeepEqual()', t => {
  557. passes(t, () => {
  558. assertions.notDeepEqual({a: 'a'}, {a: 'b'});
  559. });
  560. passes(t, () => {
  561. assertions.notDeepEqual(['a', 'b'], ['c', 'd']);
  562. });
  563. const actual = {a: 'a'};
  564. const expected = {a: 'a'};
  565. failsWith(t, () => {
  566. assertions.notDeepEqual(actual, expected);
  567. }, {
  568. actual,
  569. assertion: 'notDeepEqual',
  570. expected,
  571. message: '',
  572. raw: {actual, expected},
  573. values: [{label: 'Value is deeply equal:', formatted: /.*\{.*\n.*a: 'a'/}]
  574. });
  575. failsWith(t, () => {
  576. assertions.notDeepEqual(['a', 'b'], ['a', 'b'], 'my message');
  577. }, {
  578. assertion: 'notDeepEqual',
  579. message: 'my message',
  580. values: [{label: 'Value is deeply equal:', formatted: /.*\[.*\n.*'a',\n.*'b',/}]
  581. });
  582. t.end();
  583. });
  584. test('.throws()', gather(t => {
  585. // Fails because function doesn't throw.
  586. failsWith(t, () => {
  587. assertions.throws(() => {});
  588. }, {
  589. assertion: 'throws',
  590. message: '',
  591. values: [{label: 'Function returned:', formatted: /undefined/}]
  592. });
  593. // Fails because function doesn't throw. Asserts that 'my message' is used
  594. // as the assertion message (*not* compared against the error).
  595. failsWith(t, () => {
  596. assertions.throws(() => {}, null, 'my message');
  597. }, {
  598. assertion: 'throws',
  599. message: 'my message',
  600. values: [{label: 'Function returned:', formatted: /undefined/}]
  601. });
  602. // Fails because thrown exception is not an error
  603. failsWith(t, () => {
  604. assertions.throws(() => {
  605. const err = 'foo';
  606. throw err;
  607. });
  608. }, {
  609. assertion: 'throws',
  610. message: '',
  611. values: [
  612. {label: 'Function threw exception that is not an error:', formatted: /'foo'/}
  613. ]
  614. });
  615. // Fails because thrown error's message is not equal to 'bar'
  616. failsWith(t, () => {
  617. const err = new Error('foo');
  618. assertions.throws(() => {
  619. throw err;
  620. }, 'bar');
  621. }, {
  622. assertion: 'throws',
  623. message: '',
  624. values: [
  625. {label: 'Function threw unexpected exception:', formatted: /foo/},
  626. {label: 'Expected message to equal:', formatted: /bar/}
  627. ]
  628. });
  629. // Fails because thrown error is not the right instance
  630. failsWith(t, () => {
  631. const err = new Error('foo');
  632. assertions.throws(() => {
  633. throw err;
  634. }, class Foo {});
  635. }, {
  636. assertion: 'throws',
  637. message: '',
  638. values: [
  639. {label: 'Function threw unexpected exception:', formatted: /foo/},
  640. {label: 'Expected instance of:', formatted: /Foo/}
  641. ]
  642. });
  643. // Passes because thrown error's message is equal to 'bar'
  644. passes(t, () => {
  645. const err = new Error('foo');
  646. assertions.throws(() => {
  647. throw err;
  648. }, 'foo');
  649. });
  650. // Passes because an error is thrown.
  651. passes(t, () => {
  652. assertions.throws(() => {
  653. throw new Error('foo');
  654. });
  655. });
  656. // Passes because the correct error is thrown.
  657. passes(t, () => {
  658. const err = new Error('foo');
  659. assertions.throws(() => {
  660. throw err;
  661. }, {is: err});
  662. });
  663. // Fails because the thrown value is not an error
  664. fails(t, () => {
  665. const obj = {};
  666. assertions.throws(() => {
  667. throw obj;
  668. }, {is: obj});
  669. });
  670. // Fails because the thrown value is not the right one
  671. fails(t, () => {
  672. const err = new Error('foo');
  673. assertions.throws(() => {
  674. throw err;
  675. }, {is: {}});
  676. });
  677. // Passes because the correct error is thrown.
  678. passes(t, () => {
  679. assertions.throws(() => {
  680. throw new TypeError(); // eslint-disable-line unicorn/error-message
  681. }, {name: 'TypeError'});
  682. });
  683. // Fails because the thrown value is not an error
  684. fails(t, () => {
  685. assertions.throws(() => {
  686. const err = {name: 'Bob'};
  687. throw err;
  688. }, {name: 'Bob'});
  689. });
  690. // Fails because the thrown value is not the right one
  691. fails(t, () => {
  692. assertions.throws(() => {
  693. throw new Error('foo');
  694. }, {name: 'TypeError'});
  695. });
  696. // Passes because the correct error is thrown.
  697. passes(t, () => {
  698. assertions.throws(() => {
  699. const err = new TypeError(); // eslint-disable-line unicorn/error-message
  700. err.code = 'ERR_TEST';
  701. throw err;
  702. }, {code: 'ERR_TEST'});
  703. });
  704. // Fails because the thrown value is not the right one
  705. fails(t, () => {
  706. assertions.throws(() => {
  707. const err = new TypeError(); // eslint-disable-line unicorn/error-message
  708. err.code = 'ERR_NOPE';
  709. throw err;
  710. }, {code: 'ERR_TEST'});
  711. });
  712. // Fails because the promise is resolved, not rejected.
  713. eventuallyFailsWith(t, () => assertions.throws(Promise.resolve('foo')), {
  714. assertion: 'throws',
  715. message: '',
  716. values: [{label: 'Promise resolved with:', formatted: /'foo'/}]
  717. });
  718. // Fails because the promise is resolved with an Error
  719. eventuallyFailsWith(t, () => assertions.throws(Promise.resolve(new Error())), {
  720. assertion: 'throws',
  721. message: '',
  722. values: [{label: 'Promise resolved with:', formatted: /Error/}]
  723. });
  724. // Fails because the function returned a promise that resolved, not rejected.
  725. eventuallyFailsWith(t, () => assertions.throws(() => Promise.resolve('foo')), {
  726. assertion: 'throws',
  727. message: '',
  728. values: [{label: 'Returned promise resolved with:', formatted: /'foo'/}]
  729. });
  730. // Passes because the promise was rejected with an error.
  731. eventuallyPasses(t, () => assertions.throws(Promise.reject(new Error())));
  732. // Passes because the function returned a promise rejected with an error.
  733. eventuallyPasses(t, () => assertions.throws(() => Promise.reject(new Error())));
  734. // Passes because the error's message matches the regex
  735. eventuallyPasses(t, () => assertions.throws(Promise.reject(new Error('abc')), /abc/));
  736. // Fails because the error's message does not match the regex
  737. eventuallyFailsWith(t, () => assertions.throws(Promise.reject(new Error('abc')), /def/), {
  738. assertion: 'throws',
  739. message: '',
  740. values: [
  741. {label: 'Promise rejected with unexpected exception:', formatted: /Error/},
  742. {label: 'Expected message to match:', formatted: /\/def\//}
  743. ]
  744. });
  745. const complete = arg => Observable.of(arg);
  746. const error = err => new Observable(observer => observer.error(err));
  747. // Fails because the observable completed, not errored.
  748. eventuallyFailsWith(t, () => assertions.throws(complete('foo')), {
  749. assertion: 'throws',
  750. message: '',
  751. values: [{label: 'Observable completed with:', formatted: /'foo'/}]
  752. });
  753. // Fails because the observable completed with an Error
  754. eventuallyFailsWith(t, () => assertions.throws(complete(new Error())), {
  755. assertion: 'throws',
  756. message: '',
  757. values: [{label: 'Observable completed with:', formatted: /Error/}]
  758. });
  759. // Fails because the function returned a observable that completed, not rejected.
  760. eventuallyFailsWith(t, () => assertions.throws(() => complete('foo')), {
  761. assertion: 'throws',
  762. message: '',
  763. values: [{label: 'Returned observable completed with:', formatted: /'foo'/}]
  764. });
  765. // Passes because the observable errored with an error.
  766. eventuallyPasses(t, () => assertions.throws(error(new Error())));
  767. // Passes because the function returned an observable errored with an error.
  768. eventuallyPasses(t, () => assertions.throws(() => error(new Error())));
  769. // Passes because the error's message matches the regex
  770. eventuallyPasses(t, () => assertions.throws(error(new Error('abc')), /abc/));
  771. // Fails because the error's message does not match the regex
  772. eventuallyFailsWith(t, () => assertions.throws(error(new Error('abc')), /def/), {
  773. assertion: 'throws',
  774. message: '',
  775. values: [
  776. {label: 'Observable errored with unexpected exception:', formatted: /Error/},
  777. {label: 'Expected message to match:', formatted: /\/def\//}
  778. ]
  779. });
  780. }));
  781. test('.throws() returns the thrown error', t => {
  782. const expected = new Error();
  783. const actual = assertions.throws(() => {
  784. throw expected;
  785. });
  786. t.is(actual, expected);
  787. t.end();
  788. });
  789. test('.throws() returns the rejection reason of promise', t => {
  790. const expected = new Error();
  791. return assertions.throws(Promise.reject(expected)).then(actual => {
  792. t.is(actual, expected);
  793. t.end();
  794. });
  795. });
  796. test('.throws() returns the rejection reason of a promise returned by the function', t => {
  797. const expected = new Error();
  798. return assertions.throws(() => {
  799. return Promise.reject(expected);
  800. }).then(actual => {
  801. t.is(actual, expected);
  802. t.end();
  803. });
  804. });
  805. test('.throws() returns the error of an observable returned by the function', t => {
  806. const expected = new Error();
  807. return assertions.throws(() => {
  808. return new Observable(observer => observer.error(expected));
  809. }).then(actual => {
  810. t.is(actual, expected);
  811. t.end();
  812. });
  813. });
  814. test('.throws() fails if passed a bad value', t => {
  815. failsWith(t, () => {
  816. assertions.throws('not a function');
  817. }, {
  818. assertion: 'throws',
  819. message: '`t.throws()` must be called with a function, observable or promise',
  820. values: [{label: 'Called with:', formatted: /not a function/}]
  821. });
  822. t.end();
  823. });
  824. test('.throws() fails if passed a bad expectation', t => {
  825. failsWith(t, () => {
  826. assertions.throws(() => {}, true);
  827. }, {
  828. assertion: 'throws',
  829. message: 'The second argument to `t.throws()` must be a function, string, regular expression, expectation object or `null`',
  830. values: [{label: 'Called with:', formatted: /true/}]
  831. });
  832. failsWith(t, () => {
  833. assertions.throws(() => {}, {});
  834. }, {
  835. assertion: 'throws',
  836. message: 'The second argument to `t.throws()` must be a function, string, regular expression, expectation object or `null`',
  837. values: [{label: 'Called with:', formatted: /\{\}/}]
  838. });
  839. failsWith(t, () => {
  840. assertions.throws(() => {}, []);
  841. }, {
  842. assertion: 'throws',
  843. message: 'The second argument to `t.throws()` must be a function, string, regular expression, expectation object or `null`',
  844. values: [{label: 'Called with:', formatted: /\[\]/}]
  845. });
  846. failsWith(t, () => {
  847. assertions.throws(() => {}, {code: 42});
  848. }, {
  849. assertion: 'throws',
  850. message: 'The `code` property of the second argument to `t.throws()` must be a string',
  851. values: [{label: 'Called with:', formatted: /code: 42/}]
  852. });
  853. failsWith(t, () => {
  854. assertions.throws(() => {}, {instanceOf: null});
  855. }, {
  856. assertion: 'throws',
  857. message: 'The `instanceOf` property of the second argument to `t.throws()` must be a function',
  858. values: [{label: 'Called with:', formatted: /instanceOf: null/}]
  859. });
  860. failsWith(t, () => {
  861. assertions.throws(() => {}, {message: null});
  862. }, {
  863. assertion: 'throws',
  864. message: 'The `message` property of the second argument to `t.throws()` must be a string or regular expression',
  865. values: [{label: 'Called with:', formatted: /message: null/}]
  866. });
  867. failsWith(t, () => {
  868. assertions.throws(() => {}, {name: null});
  869. }, {
  870. assertion: 'throws',
  871. message: 'The `name` property of the second argument to `t.throws()` must be a string',
  872. values: [{label: 'Called with:', formatted: /name: null/}]
  873. });
  874. failsWith(t, () => {
  875. assertions.throws(() => {}, {is: {}, message: '', name: '', of() {}, foo: null});
  876. }, {
  877. assertion: 'throws',
  878. message: 'The second argument to `t.throws()` contains unexpected properties',
  879. values: [{label: 'Called with:', formatted: /foo: null/}]
  880. });
  881. t.end();
  882. });
  883. test('.notThrows()', gather(t => {
  884. // Passes because the function doesn't throw
  885. passes(t, () => {
  886. assertions.notThrows(() => {});
  887. });
  888. // Fails because the function throws.
  889. failsWith(t, () => {
  890. assertions.notThrows(() => {
  891. throw new Error('foo');
  892. });
  893. }, {
  894. assertion: 'notThrows',
  895. message: '',
  896. values: [{label: 'Function threw:', formatted: /foo/}]
  897. });
  898. // Fails because the function throws. Asserts that message is used for the
  899. // assertion, not to validate the thrown error.
  900. failsWith(t, () => {
  901. assertions.notThrows(() => {
  902. throw new Error('foo');
  903. }, 'my message');
  904. }, {
  905. assertion: 'notThrows',
  906. message: 'my message',
  907. values: [{label: 'Function threw:', formatted: /foo/}]
  908. });
  909. // Passes because the promise is resolved
  910. eventuallyPasses(t, () => assertions.notThrows(Promise.resolve()));
  911. // Fails because the promise is rejected
  912. eventuallyFailsWith(t, () => assertions.notThrows(Promise.reject(new Error())), {
  913. assertion: 'notThrows',
  914. message: '',
  915. values: [{label: 'Promise rejected with:', formatted: /Error/}]
  916. });
  917. // Passes because the function returned a resolved promise
  918. eventuallyPasses(t, () => assertions.notThrows(() => Promise.resolve()));
  919. // Fails because the function returned a rejected promise
  920. eventuallyFailsWith(t, () => assertions.notThrows(() => Promise.reject(new Error())), {
  921. assertion: 'notThrows',
  922. message: '',
  923. values: [{label: 'Returned promise rejected with:', formatted: /Error/}]
  924. });
  925. const complete = arg => Observable.of(arg);
  926. const error = err => new Observable(observer => observer.error(err));
  927. // Passes because the observable completed
  928. eventuallyPasses(t, () => assertions.notThrows(complete()));
  929. // Fails because the observable errored
  930. eventuallyFailsWith(t, () => assertions.notThrows(error(new Error())), {
  931. assertion: 'notThrows',
  932. message: '',
  933. values: [{label: 'Observable errored with:', formatted: /Error/}]
  934. });
  935. // Passes because the function returned a completed observable
  936. eventuallyPasses(t, () => assertions.notThrows(() => complete()));
  937. // Fails because the function returned an errored observable
  938. eventuallyFailsWith(t, () => assertions.notThrows(() => error(new Error())), {
  939. assertion: 'notThrows',
  940. message: '',
  941. values: [{label: 'Returned observable errored with:', formatted: /Error/}]
  942. });
  943. }));
  944. test('.notThrows() returns undefined for a fulfilled promise', t => {
  945. return assertions.notThrows(Promise.resolve(Symbol(''))).then(actual => {
  946. t.is(actual, undefined);
  947. });
  948. });
  949. test('.notThrows() returns undefined for a fulfilled promise returned by the function', t => {
  950. return assertions.notThrows(() => {
  951. return Promise.resolve(Symbol(''));
  952. }).then(actual => {
  953. t.is(actual, undefined);
  954. });
  955. });
  956. test('.notThrows() returns undefined for an observable returned by the function', t => {
  957. return assertions.notThrows(() => {
  958. return Observable.of(Symbol(''));
  959. }).then(actual => {
  960. t.is(actual, undefined);
  961. });
  962. });
  963. test('.notThrows() fails if passed a bad value', t => {
  964. failsWith(t, () => {
  965. assertions.notThrows('not a function');
  966. }, {
  967. assertion: 'notThrows',
  968. message: '`t.notThrows()` must be called with a function, observable or promise',
  969. values: [{label: 'Called with:', formatted: /not a function/}]
  970. });
  971. t.end();
  972. });
  973. test('.snapshot()', t => {
  974. // Set to `true` to update the snapshot, then run:
  975. // "$(npm bin)"/tap --no-cov -R spec test/assert.js
  976. //
  977. // Ignore errors and make sure not to run tests with the `-b` (bail) option.
  978. const updating = false;
  979. const projectDir = path.join(__dirname, 'fixture');
  980. const manager = snapshotManager.load({
  981. file: __filename,
  982. name: 'assert.js',
  983. projectDir,
  984. relFile: 'test/assert.js',
  985. fixedLocation: null,
  986. testDir: projectDir,
  987. updating
  988. });
  989. const setup = title => {
  990. return new Test({
  991. title,
  992. compareTestSnapshot: options => manager.compare(options)
  993. });
  994. };
  995. passes(t, () => {
  996. const testInstance = setup('passes');
  997. assertions.snapshot.call(testInstance, {foo: 'bar'});
  998. assertions.snapshot.call(testInstance, {foo: 'bar'}, {id: 'fixed id'}, 'message not included in snapshot report');
  999. assertions.snapshot.call(testInstance, React.createElement(HelloMessage, {name: 'Sindre'}));
  1000. assertions.snapshot.call(testInstance, renderer.create(React.createElement(HelloMessage, {name: 'Sindre'})).toJSON());
  1001. });
  1002. {
  1003. const testInstance = setup('fails');
  1004. if (updating) {
  1005. assertions.snapshot.call(testInstance, {foo: 'bar'});
  1006. } else {
  1007. failsWith(t, () => {
  1008. assertions.snapshot.call(testInstance, {foo: 'not bar'});
  1009. }, {
  1010. assertion: 'snapshot',
  1011. message: 'Did not match snapshot',
  1012. values: [{label: 'Difference:', formatted: ' {\n- foo: \'not bar\',\n+ foo: \'bar\',\n }'}]
  1013. });
  1014. }
  1015. }
  1016. failsWith(t, () => {
  1017. const testInstance = setup('fails (fixed id)');
  1018. assertions.snapshot.call(testInstance, {foo: 'not bar'}, {id: 'fixed id'}, 'different message, also not included in snapshot report');
  1019. }, {
  1020. assertion: 'snapshot',
  1021. message: 'different message, also not included in snapshot report',
  1022. values: [{label: 'Difference:', formatted: ' {\n- foo: \'not bar\',\n+ foo: \'bar\',\n }'}]
  1023. });
  1024. {
  1025. const testInstance = setup('fails');
  1026. if (updating) {
  1027. assertions.snapshot.call(testInstance, {foo: 'bar'}, 'my message');
  1028. } else {
  1029. failsWith(t, () => {
  1030. assertions.snapshot.call(testInstance, {foo: 'not bar'}, 'my message');
  1031. }, {
  1032. assertion: 'snapshot',
  1033. message: 'my message',
  1034. values: [{label: 'Difference:', formatted: ' {\n- foo: \'not bar\',\n+ foo: \'bar\',\n }'}]
  1035. });
  1036. }
  1037. }
  1038. {
  1039. const testInstance = setup('rendered comparison');
  1040. if (updating) {
  1041. assertions.snapshot.call(testInstance, renderer.create(React.createElement(HelloMessage, {name: 'Sindre'})).toJSON());
  1042. } else {
  1043. passes(t, () => {
  1044. assertions.snapshot.call(testInstance, React.createElement('div', null, 'Hello ', React.createElement('mark', null, 'Sindre')));
  1045. });
  1046. }
  1047. }
  1048. {
  1049. const testInstance = setup('rendered comparison');
  1050. if (updating) {
  1051. assertions.snapshot.call(testInstance, renderer.create(React.createElement(HelloMessage, {name: 'Sindre'})).toJSON());
  1052. } else {
  1053. failsWith(t, () => {
  1054. assertions.snapshot.call(testInstance, renderer.create(React.createElement(HelloMessage, {name: 'Vadim'})).toJSON());
  1055. }, {
  1056. assertion: 'snapshot',
  1057. message: 'Did not match snapshot',
  1058. values: [{label: 'Difference:', formatted: ' <div>\n Hello \n <mark>\n- Vadim\n+ Sindre\n </mark>\n </div>'}]
  1059. });
  1060. }
  1061. }
  1062. {
  1063. const testInstance = setup('element comparison');
  1064. if (updating) {
  1065. assertions.snapshot.call(testInstance, React.createElement(HelloMessage, {name: 'Sindre'}));
  1066. } else {
  1067. failsWith(t, () => {
  1068. assertions.snapshot.call(testInstance, React.createElement(HelloMessage, {name: 'Vadim'}));
  1069. }, {
  1070. assertion: 'snapshot',
  1071. message: 'Did not match snapshot',
  1072. values: [{label: 'Difference:', formatted: ' <HelloMessage⍟\n- name="Vadim"\n+ name="Sindre"\n />'}]
  1073. });
  1074. }
  1075. }
  1076. manager.save();
  1077. t.end();
  1078. });
  1079. test('.truthy()', t => {
  1080. failsWith(t, () => {
  1081. assertions.truthy(0);
  1082. }, {
  1083. assertion: 'truthy',
  1084. message: '',
  1085. operator: '!!',
  1086. values: [{label: 'Value is not truthy:', formatted: /0/}]
  1087. });
  1088. failsWith(t, () => {
  1089. assertions.truthy(false, 'my message');
  1090. }, {
  1091. assertion: 'truthy',
  1092. message: 'my message',
  1093. operator: '!!',
  1094. values: [{label: 'Value is not truthy:', formatted: /false/}]
  1095. });
  1096. passes(t, () => {
  1097. assertions.truthy(1);
  1098. assertions.truthy(true);
  1099. });
  1100. t.end();
  1101. });
  1102. test('.falsy()', t => {
  1103. failsWith(t, () => {
  1104. assertions.falsy(1);
  1105. }, {
  1106. assertion: 'falsy',
  1107. message: '',
  1108. operator: '!',
  1109. values: [{label: 'Value is not falsy:', formatted: /1/}]
  1110. });
  1111. failsWith(t, () => {
  1112. assertions.falsy(true, 'my message');
  1113. }, {
  1114. assertion: 'falsy',
  1115. message: 'my message',
  1116. operator: '!',
  1117. values: [{label: 'Value is not falsy:', formatted: /true/}]
  1118. });
  1119. passes(t, () => {
  1120. assertions.falsy(0);
  1121. assertions.falsy(false);
  1122. });
  1123. t.end();
  1124. });
  1125. test('.true()', t => {
  1126. failsWith(t, () => {
  1127. assertions.true(1);
  1128. }, {
  1129. assertion: 'true',
  1130. message: '',
  1131. values: [{label: 'Value is not `true`:', formatted: /1/}]
  1132. });
  1133. failsWith(t, () => {
  1134. assertions.true(0);
  1135. }, {
  1136. assertion: 'true',
  1137. message: '',
  1138. values: [{label: 'Value is not `true`:', formatted: /0/}]
  1139. });
  1140. failsWith(t, () => {
  1141. assertions.true(false);
  1142. }, {
  1143. assertion: 'true',
  1144. message: '',
  1145. values: [{label: 'Value is not `true`:', formatted: /false/}]
  1146. });
  1147. failsWith(t, () => {
  1148. assertions.true('foo', 'my message');
  1149. }, {
  1150. assertion: 'true',
  1151. message: 'my message',
  1152. values: [{label: 'Value is not `true`:', formatted: /foo/}]
  1153. });
  1154. passes(t, () => {
  1155. assertions.true(true);
  1156. });
  1157. t.end();
  1158. });
  1159. test('.false()', t => {
  1160. failsWith(t, () => {
  1161. assertions.false(0);
  1162. }, {
  1163. assertion: 'false',
  1164. message: '',
  1165. values: [{label: 'Value is not `false`:', formatted: /0/}]
  1166. });
  1167. failsWith(t, () => {
  1168. assertions.false(1);
  1169. }, {
  1170. assertion: 'false',
  1171. message: '',
  1172. values: [{label: 'Value is not `false`:', formatted: /1/}]
  1173. });
  1174. failsWith(t, () => {
  1175. assertions.false(true);
  1176. }, {
  1177. assertion: 'false',
  1178. message: '',
  1179. values: [{label: 'Value is not `false`:', formatted: /true/}]
  1180. });
  1181. failsWith(t, () => {
  1182. assertions.false('foo', 'my message');
  1183. }, {
  1184. assertion: 'false',
  1185. message: 'my message',
  1186. values: [{label: 'Value is not `false`:', formatted: /foo/}]
  1187. });
  1188. passes(t, () => {
  1189. assertions.false(false);
  1190. });
  1191. t.end();
  1192. });
  1193. test('.regex()', t => {
  1194. passes(t, () => {
  1195. assertions.regex('abc', /^abc$/);
  1196. });
  1197. failsWith(t, () => {
  1198. assertions.regex('foo', /^abc$/);
  1199. }, {
  1200. assertion: 'regex',
  1201. message: '',
  1202. values: [
  1203. {label: 'Value must match expression:', formatted: /foo/},
  1204. {label: 'Regular expression:', formatted: /\/\^abc\$\//}
  1205. ]
  1206. });
  1207. failsWith(t, () => {
  1208. assertions.regex('foo', /^abc$/, 'my message');
  1209. }, {
  1210. assertion: 'regex',
  1211. message: 'my message',
  1212. values: [
  1213. {label: 'Value must match expression:', formatted: /foo/},
  1214. {label: 'Regular expression:', formatted: /\/\^abc\$\//}
  1215. ]
  1216. });
  1217. t.end();
  1218. });
  1219. test('.regex() fails if passed a bad value', t => {
  1220. failsWith(t, () => {
  1221. assertions.regex(42, /foo/);
  1222. }, {
  1223. assertion: 'regex',
  1224. message: '`t.regex()` must be called with a string',
  1225. values: [{label: 'Called with:', formatted: /42/}]
  1226. });
  1227. failsWith(t, () => {
  1228. assertions.regex('42', {});
  1229. }, {
  1230. assertion: 'regex',
  1231. message: '`t.regex()` must be called with a regular expression',
  1232. values: [{label: 'Called with:', formatted: /\{\}/}]
  1233. });
  1234. t.end();
  1235. });
  1236. test('.notRegex()', t => {
  1237. passes(t, () => {
  1238. assertions.notRegex('abc', /def/);
  1239. });
  1240. failsWith(t, () => {
  1241. assertions.notRegex('abc', /abc/);
  1242. }, {
  1243. assertion: 'notRegex',
  1244. message: '',
  1245. values: [
  1246. {label: 'Value must not match expression:', formatted: /abc/},
  1247. {label: 'Regular expression:', formatted: /\/abc\//}
  1248. ]
  1249. });
  1250. failsWith(t, () => {
  1251. assertions.notRegex('abc', /abc/, 'my message');
  1252. }, {
  1253. assertion: 'notRegex',
  1254. message: 'my message',
  1255. values: [
  1256. {label: 'Value must not match expression:', formatted: /abc/},
  1257. {label: 'Regular expression:', formatted: /\/abc\//}
  1258. ]
  1259. });
  1260. t.end();
  1261. });
  1262. test('.notRegex() fails if passed a bad value', t => {
  1263. failsWith(t, () => {
  1264. assertions.notRegex(42, /foo/);
  1265. }, {
  1266. assertion: 'notRegex',
  1267. message: '`t.notRegex()` must be called with a string',
  1268. values: [{label: 'Called with:', formatted: /42/}]
  1269. });
  1270. failsWith(t, () => {
  1271. assertions.notRegex('42', {});
  1272. }, {
  1273. assertion: 'notRegex',
  1274. message: '`t.notRegex()` must be called with a regular expression',
  1275. values: [{label: 'Called with:', formatted: /\{\}/}]
  1276. });
  1277. t.end();
  1278. });