You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

781 line
20KB

  1. describe('Core helper tests', function() {
  2. var helpers;
  3. beforeAll(function() {
  4. helpers = window.Chart.helpers;
  5. });
  6. it('should iterate over an array and pass the extra data to that function', function() {
  7. var testData = [0, 9, "abc"];
  8. var scope = {}; // fake out the scope and ensure that 'this' is the correct thing
  9. helpers.each(testData, function(item, index) {
  10. expect(item).not.toBe(undefined);
  11. expect(index).not.toBe(undefined);
  12. expect(testData[index]).toBe(item);
  13. expect(this).toBe(scope);
  14. }, scope);
  15. // Reverse iteration
  16. var iterated = [];
  17. helpers.each(testData, function(item, index) {
  18. expect(item).not.toBe(undefined);
  19. expect(index).not.toBe(undefined);
  20. expect(testData[index]).toBe(item);
  21. expect(this).toBe(scope);
  22. iterated.push(item);
  23. }, scope, true);
  24. expect(iterated.slice().reverse()).toEqual(testData);
  25. });
  26. it('should iterate over properties in an object', function() {
  27. var testData = {
  28. myProp1: 'abc',
  29. myProp2: 276,
  30. myProp3: ['a', 'b']
  31. };
  32. helpers.each(testData, function(value, key) {
  33. if (key === 'myProp1') {
  34. expect(value).toBe('abc');
  35. } else if (key === 'myProp2') {
  36. expect(value).toBe(276);
  37. } else if (key === 'myProp3') {
  38. expect(value).toEqual(['a', 'b']);
  39. } else {
  40. expect(false).toBe(true);
  41. }
  42. });
  43. });
  44. it('should not error when iterating over a null object', function() {
  45. expect(function() {
  46. helpers.each(undefined);
  47. }).not.toThrow();
  48. });
  49. it('should clone an object', function() {
  50. var testData = {
  51. myProp1: 'abc',
  52. myProp2: ['a', 'b'],
  53. myProp3: {
  54. myProp4: 5,
  55. myProp5: [1, 2]
  56. }
  57. };
  58. var clone = helpers.clone(testData);
  59. expect(clone).toEqual(testData);
  60. expect(clone).not.toBe(testData);
  61. expect(clone.myProp2).not.toBe(testData.myProp2);
  62. expect(clone.myProp3).not.toBe(testData.myProp3);
  63. expect(clone.myProp3.myProp5).not.toBe(testData.myProp3.myProp5);
  64. });
  65. it('should extend an object', function() {
  66. var original = {
  67. myProp1: 'abc',
  68. myProp2: 56
  69. };
  70. var extension = {
  71. myProp3: [2, 5, 6],
  72. myProp2: 0
  73. };
  74. helpers.extend(original, extension);
  75. expect(original).toEqual({
  76. myProp1: 'abc',
  77. myProp2: 0,
  78. myProp3: [2, 5, 6],
  79. });
  80. });
  81. it('should merge a normal config without scales', function() {
  82. var baseConfig = {
  83. valueProp: 5,
  84. arrayProp: [1, 2, 3, 4, 5, 6],
  85. objectProp: {
  86. prop1: 'abc',
  87. prop2: 56
  88. }
  89. };
  90. var toMerge = {
  91. valueProp2: null,
  92. arrayProp: ['a', 'c'],
  93. objectProp: {
  94. prop1: 'c',
  95. prop3: 'prop3'
  96. }
  97. };
  98. var merged = helpers.configMerge(baseConfig, toMerge);
  99. expect(merged).toEqual({
  100. valueProp: 5,
  101. valueProp2: null,
  102. arrayProp: ['a', 'c', 3, 4, 5, 6],
  103. objectProp: {
  104. prop1: 'c',
  105. prop2: 56,
  106. prop3: 'prop3'
  107. }
  108. });
  109. });
  110. it('should merge arrays containing objects', function() {
  111. var baseConfig = {
  112. arrayProp: [{
  113. prop1: 'abc',
  114. prop2: 56
  115. }],
  116. };
  117. var toMerge = {
  118. arrayProp: [{
  119. prop1: 'myProp1',
  120. prop3: 'prop3'
  121. }, 2, {
  122. prop1: 'myProp1'
  123. }],
  124. };
  125. var merged = helpers.configMerge(baseConfig, toMerge);
  126. expect(merged).toEqual({
  127. arrayProp: [{
  128. prop1: 'myProp1',
  129. prop2: 56,
  130. prop3: 'prop3'
  131. },
  132. 2, {
  133. prop1: 'myProp1'
  134. }
  135. ],
  136. });
  137. });
  138. it('should merge scale configs', function() {
  139. var baseConfig = {
  140. scales: {
  141. prop1: {
  142. abc: 123,
  143. def: '456'
  144. },
  145. prop2: 777,
  146. yAxes: [{
  147. type: 'linear',
  148. }, {
  149. type: 'log'
  150. }]
  151. }
  152. };
  153. var toMerge = {
  154. scales: {
  155. prop1: {
  156. def: 'bbb',
  157. ghi: 78
  158. },
  159. prop2: null,
  160. yAxes: [{
  161. type: 'linear',
  162. axisProp: 456
  163. }, {
  164. // pulls in linear default config since axis type changes
  165. type: 'linear',
  166. position: 'right'
  167. }, {
  168. // Pulls in linear default config since axis not in base
  169. type: 'linear'
  170. }]
  171. }
  172. };
  173. var merged = helpers.configMerge(baseConfig, toMerge);
  174. expect(merged).toEqual({
  175. scales: {
  176. prop1: {
  177. abc: 123,
  178. def: 'bbb',
  179. ghi: 78
  180. },
  181. prop2: null,
  182. yAxes: [{
  183. type: 'linear',
  184. axisProp: 456
  185. }, {
  186. display: true,
  187. gridLines: {
  188. color: "rgba(0, 0, 0, 0.1)",
  189. drawBorder: true,
  190. drawOnChartArea: true,
  191. drawTicks: true, // draw ticks extending towards the label
  192. tickMarkLength: 10,
  193. lineWidth: 1,
  194. offsetGridLines: false,
  195. display: true,
  196. zeroLineColor: "rgba(0,0,0,0.25)",
  197. zeroLineWidth: 1,
  198. },
  199. position: "right",
  200. scaleLabel: {
  201. labelString: '',
  202. display: false,
  203. },
  204. ticks: {
  205. beginAtZero: false,
  206. minRotation: 0,
  207. maxRotation: 50,
  208. mirror: false,
  209. padding: 10,
  210. reverse: false,
  211. display: true,
  212. callback: merged.scales.yAxes[1].ticks.callback, // make it nicer, then check explicitly below
  213. autoSkip: true,
  214. autoSkipPadding: 0,
  215. labelOffset: 0,
  216. },
  217. type: 'linear'
  218. }, {
  219. display: true,
  220. gridLines: {
  221. color: "rgba(0, 0, 0, 0.1)",
  222. drawBorder: true,
  223. drawOnChartArea: true,
  224. drawTicks: true, // draw ticks extending towards the label,
  225. tickMarkLength: 10,
  226. lineWidth: 1,
  227. offsetGridLines: false,
  228. display: true,
  229. zeroLineColor: "rgba(0,0,0,0.25)",
  230. zeroLineWidth: 1,
  231. },
  232. position: "left",
  233. scaleLabel: {
  234. labelString: '',
  235. display: false,
  236. },
  237. ticks: {
  238. beginAtZero: false,
  239. minRotation: 0,
  240. maxRotation: 50,
  241. mirror: false,
  242. padding: 10,
  243. reverse: false,
  244. display: true,
  245. callback: merged.scales.yAxes[2].ticks.callback, // make it nicer, then check explicitly below
  246. autoSkip: true,
  247. autoSkipPadding: 0,
  248. labelOffset: 0,
  249. },
  250. type: 'linear'
  251. }]
  252. }
  253. });
  254. // Are these actually functions
  255. expect(merged.scales.yAxes[1].ticks.callback).toEqual(jasmine.any(Function));
  256. expect(merged.scales.yAxes[2].ticks.callback).toEqual(jasmine.any(Function));
  257. });
  258. it('should get value or default', function() {
  259. expect(helpers.getValueAtIndexOrDefault(98, 0, 56)).toBe(98);
  260. expect(helpers.getValueAtIndexOrDefault(0, 0, 56)).toBe(0);
  261. expect(helpers.getValueAtIndexOrDefault(undefined, undefined, 56)).toBe(56);
  262. expect(helpers.getValueAtIndexOrDefault([1, 2, 3], 1, 100)).toBe(2);
  263. expect(helpers.getValueAtIndexOrDefault([1, 2, 3], 3, 100)).toBe(100);
  264. });
  265. it('should filter an array', function() {
  266. var data = [-10, 0, 6, 0, 7];
  267. var callback = function(item) {
  268. return item > 2
  269. };
  270. expect(helpers.where(data, callback)).toEqual([6, 7]);
  271. expect(helpers.findNextWhere(data, callback)).toEqual(6);
  272. expect(helpers.findNextWhere(data, callback, 2)).toBe(7);
  273. expect(helpers.findNextWhere(data, callback, 4)).toBe(undefined);
  274. expect(helpers.findPreviousWhere(data, callback)).toBe(7);
  275. expect(helpers.findPreviousWhere(data, callback, 3)).toBe(6);
  276. expect(helpers.findPreviousWhere(data, callback, 0)).toBe(undefined);
  277. });
  278. it('should get the correct sign', function() {
  279. expect(helpers.sign(0)).toBe(0);
  280. expect(helpers.sign(10)).toBe(1);
  281. expect(helpers.sign(-5)).toBe(-1);
  282. });
  283. it('should do a log10 operation', function() {
  284. expect(helpers.log10(0)).toBe(-Infinity);
  285. expect(helpers.log10(1)).toBe(0);
  286. expect(helpers.log10(1000)).toBeCloseTo(3, 1e-9);
  287. });
  288. it('should correctly determine if two numbers are essentially equal', function() {
  289. expect(helpers.almostEquals(0, Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
  290. expect(helpers.almostEquals(1, 1.1, 0.0001)).toBe(false);
  291. expect(helpers.almostEquals(1e30, 1e30 + Number.EPSILON, 0)).toBe(false);
  292. expect(helpers.almostEquals(1e30, 1e30 + Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
  293. });
  294. it('should generate integer ids', function() {
  295. var uid = helpers.uid();
  296. expect(uid).toEqual(jasmine.any(Number));
  297. expect(helpers.uid()).toBe(uid + 1);
  298. expect(helpers.uid()).toBe(uid + 2);
  299. expect(helpers.uid()).toBe(uid + 3);
  300. });
  301. it('should detect a number', function() {
  302. expect(helpers.isNumber(123)).toBe(true);
  303. expect(helpers.isNumber('123')).toBe(true);
  304. expect(helpers.isNumber(null)).toBe(false);
  305. expect(helpers.isNumber(NaN)).toBe(false);
  306. expect(helpers.isNumber(undefined)).toBe(false);
  307. expect(helpers.isNumber('cbc')).toBe(false);
  308. });
  309. it('should convert between radians and degrees', function() {
  310. expect(helpers.toRadians(180)).toBe(Math.PI);
  311. expect(helpers.toRadians(90)).toBe(0.5 * Math.PI);
  312. expect(helpers.toDegrees(Math.PI)).toBe(180);
  313. expect(helpers.toDegrees(Math.PI * 3 / 2)).toBe(270);
  314. });
  315. it('should get an angle from a point', function() {
  316. var center = {
  317. x: 0,
  318. y: 0
  319. };
  320. expect(helpers.getAngleFromPoint(center, {
  321. x: 0,
  322. y: 10
  323. })).toEqual({
  324. angle: Math.PI / 2,
  325. distance: 10,
  326. });
  327. expect(helpers.getAngleFromPoint(center, {
  328. x: Math.sqrt(2),
  329. y: Math.sqrt(2)
  330. })).toEqual({
  331. angle: Math.PI / 4,
  332. distance: 2
  333. });
  334. expect(helpers.getAngleFromPoint(center, {
  335. x: -1.0 * Math.sqrt(2),
  336. y: -1.0 * Math.sqrt(2)
  337. })).toEqual({
  338. angle: Math.PI * 1.25,
  339. distance: 2
  340. });
  341. });
  342. it('should spline curves', function() {
  343. expect(helpers.splineCurve({
  344. x: 0,
  345. y: 0
  346. }, {
  347. x: 1,
  348. y: 1
  349. }, {
  350. x: 2,
  351. y: 0
  352. }, 0)).toEqual({
  353. previous: {
  354. x: 1,
  355. y: 1,
  356. },
  357. next: {
  358. x: 1,
  359. y: 1,
  360. }
  361. });
  362. expect(helpers.splineCurve({
  363. x: 0,
  364. y: 0
  365. }, {
  366. x: 1,
  367. y: 1
  368. }, {
  369. x: 2,
  370. y: 0
  371. }, 1)).toEqual({
  372. previous: {
  373. x: 0,
  374. y: 1,
  375. },
  376. next: {
  377. x: 2,
  378. y: 1,
  379. }
  380. });
  381. });
  382. it('should get the next or previous item in an array', function() {
  383. var testData = [0, 1, 2];
  384. expect(helpers.nextItem(testData, 0, false)).toEqual(1);
  385. expect(helpers.nextItem(testData, 2, false)).toEqual(2);
  386. expect(helpers.nextItem(testData, 2, true)).toEqual(0);
  387. expect(helpers.nextItem(testData, 1, true)).toEqual(2);
  388. expect(helpers.nextItem(testData, -1, false)).toEqual(0);
  389. expect(helpers.previousItem(testData, 0, false)).toEqual(0);
  390. expect(helpers.previousItem(testData, 0, true)).toEqual(2);
  391. expect(helpers.previousItem(testData, 2, false)).toEqual(1);
  392. expect(helpers.previousItem(testData, 1, true)).toEqual(0);
  393. });
  394. it('should clear a canvas', function() {
  395. var context = window.createMockContext();
  396. helpers.clear({
  397. width: 100,
  398. height: 150,
  399. ctx: context
  400. });
  401. expect(context.getCalls()).toEqual([{
  402. name: 'clearRect',
  403. args: [0, 0, 100, 150]
  404. }]);
  405. });
  406. it('should return the width of the longest text in an Array and 2D Array', function() {
  407. var context = window.createMockContext();
  408. var font = "normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif";
  409. var arrayOfThings_1D = ['FooBar','Bar'];
  410. var arrayOfThings_2D = [['FooBar_1','Bar_2'],'Foo_1'];
  411. // Regardless 'FooBar' is the longest label it should return (charcters * 10)
  412. expect(helpers.longestText(context, font, arrayOfThings_1D, {})).toEqual(60);
  413. expect(helpers.longestText(context, font, arrayOfThings_2D, {})).toEqual(80);
  414. // We check to make sure we made the right calls to the canvas.
  415. expect(context.getCalls()).toEqual([{
  416. name: 'measureText',
  417. args: ['FooBar']
  418. }, {
  419. name: 'measureText',
  420. args: ['Bar']
  421. }, {
  422. name: 'measureText',
  423. args: ['FooBar_1']
  424. }, {
  425. name: 'measureText',
  426. args: ['Bar_2']
  427. }, {
  428. name: 'measureText',
  429. args: ['Foo_1']
  430. }]);
  431. });
  432. it('compare text with current longest and update', function() {
  433. var context = window.createMockContext();
  434. var data = {};
  435. var gc = [];
  436. var longest = 70;
  437. expect(helpers.measureText(context, data, gc, longest, 'foobar')).toEqual(70);
  438. expect(helpers.measureText(context, data, gc, longest, 'foobar_')).toEqual(70);
  439. expect(helpers.measureText(context, data, gc, longest, 'foobar_1')).toEqual(80);
  440. // We check to make sure we made the right calls to the canvas.
  441. expect(context.getCalls()).toEqual([{
  442. name: 'measureText',
  443. args: ['foobar']
  444. }, {
  445. name: 'measureText',
  446. args: ['foobar_']
  447. }, {
  448. name: 'measureText',
  449. args: ['foobar_1']
  450. }]);
  451. });
  452. it('count look at all the labels and return maximum number of lines', function() {
  453. var context = window.createMockContext();
  454. var arrayOfThings_1 = ['Foo','Bar'];
  455. var arrayOfThings_2 = [['Foo','Bar'],'Foo'];
  456. var arrayOfThings_3 = [['Foo','Bar','Boo'],['Foo','Bar'],'Foo'];
  457. expect(helpers.numberOfLabelLines(arrayOfThings_1)).toEqual(1);
  458. expect(helpers.numberOfLabelLines(arrayOfThings_2)).toEqual(2);
  459. expect(helpers.numberOfLabelLines(arrayOfThings_3)).toEqual(3);
  460. });
  461. it('should draw a rounded rectangle', function() {
  462. var context = window.createMockContext();
  463. helpers.drawRoundedRectangle(context, 10, 20, 30, 40, 5);
  464. expect(context.getCalls()).toEqual([{
  465. name: 'beginPath',
  466. args: []
  467. }, {
  468. name: 'moveTo',
  469. args: [15, 20]
  470. }, {
  471. name: 'lineTo',
  472. args: [35, 20]
  473. }, {
  474. name: 'quadraticCurveTo',
  475. args: [40, 20, 40, 25]
  476. }, {
  477. name: 'lineTo',
  478. args: [40, 55]
  479. }, {
  480. name: 'quadraticCurveTo',
  481. args: [40, 60, 35, 60]
  482. }, {
  483. name: 'lineTo',
  484. args: [15, 60]
  485. }, {
  486. name: 'quadraticCurveTo',
  487. args: [10, 60, 10, 55]
  488. }, {
  489. name: 'lineTo',
  490. args: [10, 25]
  491. }, {
  492. name: 'quadraticCurveTo',
  493. args: [10, 20, 15, 20]
  494. }, {
  495. name: 'closePath',
  496. args: []
  497. }])
  498. });
  499. it ('should get the maximum width and height for a node', function() {
  500. // Create div with fixed size as a test bed
  501. var div = document.createElement('div');
  502. div.style.width = "200px";
  503. div.style.height = "300px";
  504. document.body.appendChild(div);
  505. // Create the div we want to get the max size for
  506. var innerDiv = document.createElement('div');
  507. div.appendChild(innerDiv);
  508. expect(helpers.getMaximumWidth(innerDiv)).toBe(200);
  509. expect(helpers.getMaximumHeight(innerDiv)).toBe(300);
  510. document.body.removeChild(div);
  511. });
  512. it ('should get the maximum width of a node that has a max-width style', function() {
  513. // Create div with fixed size as a test bed
  514. var div = document.createElement('div');
  515. div.style.width = "200px";
  516. div.style.height = "300px";
  517. document.body.appendChild(div);
  518. // Create the div we want to get the max size for and set a max-width style
  519. var innerDiv = document.createElement('div');
  520. innerDiv.style.maxWidth = "150px";
  521. div.appendChild(innerDiv);
  522. expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
  523. document.body.removeChild(div);
  524. });
  525. it ('should get the maximum height of a node that has a max-height style', function() {
  526. // Create div with fixed size as a test bed
  527. var div = document.createElement('div');
  528. div.style.width = "200px";
  529. div.style.height = "300px";
  530. document.body.appendChild(div);
  531. // Create the div we want to get the max size for and set a max-height style
  532. var innerDiv = document.createElement('div');
  533. innerDiv.style.maxHeight = "150px";
  534. div.appendChild(innerDiv);
  535. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  536. document.body.removeChild(div);
  537. });
  538. it ('should get the maximum width of a node when the parent has a max-width style', function() {
  539. // Create div with fixed size as a test bed
  540. var div = document.createElement('div');
  541. div.style.width = "200px";
  542. div.style.height = "300px";
  543. document.body.appendChild(div);
  544. // Create an inner wrapper around our div we want to size and give that a max-width style
  545. var parentDiv = document.createElement('div');
  546. parentDiv.style.maxWidth = "150px";
  547. div.appendChild(parentDiv);
  548. // Create the div we want to get the max size for
  549. var innerDiv = document.createElement('div');
  550. parentDiv.appendChild(innerDiv);
  551. expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
  552. document.body.removeChild(div);
  553. });
  554. it ('should get the maximum height of a node when the parent has a max-height style', function() {
  555. // Create div with fixed size as a test bed
  556. var div = document.createElement('div');
  557. div.style.width = "200px";
  558. div.style.height = "300px";
  559. document.body.appendChild(div);
  560. // Create an inner wrapper around our div we want to size and give that a max-height style
  561. var parentDiv = document.createElement('div');
  562. parentDiv.style.maxHeight = "150px";
  563. div.appendChild(parentDiv);
  564. // Create the div we want to get the max size for
  565. var innerDiv = document.createElement('div');
  566. innerDiv.style.height = "300px"; // make it large
  567. parentDiv.appendChild(innerDiv);
  568. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  569. document.body.removeChild(div);
  570. });
  571. it ('should get the maximum width of a node that has a percentage max-width style', function() {
  572. // Create div with fixed size as a test bed
  573. var div = document.createElement('div');
  574. div.style.width = "200px";
  575. div.style.height = "300px";
  576. document.body.appendChild(div);
  577. // Create the div we want to get the max size for and set a max-width style
  578. var innerDiv = document.createElement('div');
  579. innerDiv.style.maxWidth = "50%";
  580. div.appendChild(innerDiv);
  581. expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
  582. document.body.removeChild(div);
  583. });
  584. it ('should get the maximum height of a node that has a percentage max-height style', function() {
  585. // Create div with fixed size as a test bed
  586. var div = document.createElement('div');
  587. div.style.width = "200px";
  588. div.style.height = "300px";
  589. document.body.appendChild(div);
  590. // Create the div we want to get the max size for and set a max-height style
  591. var innerDiv = document.createElement('div');
  592. innerDiv.style.maxHeight = "50%";
  593. div.appendChild(innerDiv);
  594. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  595. document.body.removeChild(div);
  596. });
  597. it ('should get the maximum width of a node when the parent has a percentage max-width style', function() {
  598. // Create div with fixed size as a test bed
  599. var div = document.createElement('div');
  600. div.style.width = "200px";
  601. div.style.height = "300px";
  602. document.body.appendChild(div);
  603. // Create an inner wrapper around our div we want to size and give that a max-width style
  604. var parentDiv = document.createElement('div');
  605. parentDiv.style.maxWidth = "50%";
  606. div.appendChild(parentDiv);
  607. // Create the div we want to get the max size for
  608. var innerDiv = document.createElement('div');
  609. parentDiv.appendChild(innerDiv);
  610. expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
  611. document.body.removeChild(div);
  612. });
  613. it ('should get the maximum height of a node when the parent has a percentage max-height style', function() {
  614. // Create div with fixed size as a test bed
  615. var div = document.createElement('div');
  616. div.style.width = "200px";
  617. div.style.height = "300px";
  618. document.body.appendChild(div);
  619. // Create an inner wrapper around our div we want to size and give that a max-height style
  620. var parentDiv = document.createElement('div');
  621. parentDiv.style.maxHeight = "50%";
  622. div.appendChild(parentDiv);
  623. var innerDiv = document.createElement('div');
  624. innerDiv.style.height = "300px"; // make it large
  625. parentDiv.appendChild(innerDiv);
  626. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  627. document.body.removeChild(div);
  628. });
  629. describe('Color helper', function() {
  630. function isColorInstance(obj) {
  631. return typeof obj === 'object' && obj.hasOwnProperty('values') && obj.values.hasOwnProperty('rgb');
  632. }
  633. it('should return a color when called with a color', function() {
  634. expect(isColorInstance(helpers.color('rgb(1, 2, 3)'))).toBe(true);
  635. });
  636. it('should return a color when called with a CanvasGradient instance', function() {
  637. var context = document.createElement('canvas').getContext('2d');
  638. var gradient = context.createLinearGradient(0, 1, 2, 3);
  639. expect(isColorInstance(helpers.color(gradient))).toBe(true);
  640. });
  641. });
  642. describe('Background hover color helper', function() {
  643. it('should return a CanvasPattern when called with a CanvasPattern', function(done) {
  644. var dots = new Image();
  645. dots.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAAD1BMVEUAAAD///////////////+PQt5oAAAABXRSTlMAHlFhZsfk/BEAAAAqSURBVHgBY2BgZGJmYmSAAUYWEIDzmcBcJhiXGcxlRpPFrhdmMiqgvX0AcGIBEUAo6UAAAAAASUVORK5CYII=';
  646. dots.onload = function() {
  647. var chartContext = document.createElement('canvas').getContext('2d');
  648. var patternCanvas = document.createElement('canvas');
  649. var patternContext = patternCanvas.getContext('2d');
  650. var pattern = patternContext.createPattern(dots, 'repeat');
  651. patternContext.fillStyle = pattern;
  652. var backgroundColor = helpers.getHoverColor(chartContext.createPattern(patternCanvas, 'repeat'));
  653. expect(backgroundColor instanceof CanvasPattern).toBe(true);
  654. done();
  655. }
  656. });
  657. it('should return a modified version of color when called with a color', function() {
  658. var originalColorRGB = 'rgb(70, 191, 189)';
  659. expect(helpers.getHoverColor('#46BFBD')).not.toEqual(originalColorRGB);
  660. });
  661. });
  662. });