diff --git a/frontend/src/Metamaps/Util.js b/frontend/src/Metamaps/Util.js index 2bc49159..4a53fc7c 100644 --- a/frontend/src/Metamaps/Util.js +++ b/frontend/src/Metamaps/Util.js @@ -39,36 +39,30 @@ const Util = { }, decodeEntities: function(desc) { - let temp = document.createElement('p') - temp.innerHTML = desc // browser handles the topics - let str = temp.textContent || temp.innerText - temp = null // delete the element + let paragraph = document.createElement('p') + paragraph.innerHTML = desc // browser handles the topics + let str = paragraph.textContent || paragraph.innerText + paragraph = null // delete the element return str - }, // decodeEntities + }, getDistance: function(p1, p2) { return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2)) }, - // Try using Visualize.mGraph coordsToPixels: function(mGraph, coords) { - if (mGraph) { - const canvas = mGraph.canvas - const s = canvas.getSize() - const p = canvas.getPos() - const ox = canvas.translateOffsetX - const oy = canvas.translateOffsetY - const sx = canvas.scaleOffsetX - const sy = canvas.scaleOffsetY - return { - x: (coords.x / (1 / sx)) + p.x + s.width / 2 + ox, - y: (coords.y / (1 / sy)) + p.y + s.height / 2 + oy - } - } else { - return { - x: 0, - y: 0 - } + if (!mGraph) return { x: 0, y: 0 } + + const canvas = mGraph.canvas + const s = canvas.getSize() + const p = canvas.getPos() + const ox = canvas.translateOffsetX + const oy = canvas.translateOffsetY + const sx = canvas.scaleOffsetX + const sy = canvas.scaleOffsetY + return { + x: (coords.x / (1 / sx)) + p.x + s.width / 2 + ox, + y: (coords.y / (1 / sy)) + p.y + s.height / 2 + oy } }, diff --git a/frontend/test/Metamaps/Util.spec.js b/frontend/test/Metamaps/Util.spec.js index 3cfe05d8..67abe1fd 100644 --- a/frontend/test/Metamaps/Util.spec.js +++ b/frontend/test/Metamaps/Util.spec.js @@ -1,9 +1,12 @@ -/* global describe, it */ +/* global describe, it, afterEach */ import { expect } from 'chai' +import sinon from 'sinon' import Util from '../../src/Metamaps/Util' +const sandbox = sinon.sandbox.create() + describe('Metamaps.Util.js', function() { describe('splitLine', function() { it('splits on words', function() { @@ -21,10 +24,42 @@ describe('Metamaps.Util.js', function() { }) }) describe('nowDateFormatted', function() { - it.skip('TODO need `Date`') + function assertNowDateFormatted(expected, { month, day, year }) { + const date = { + getDate: () => day, + getMonth: () => month - 1, // 0 to 11 + getFullYear: () => year + } + expect(Util.nowDateFormatted(date)).to.equal(expected) + } + it('formats dates with one digit properly', function() { + assertNowDateFormatted('01/01/2000', { month: 1, day: 1, year: 2000 }) + }) + it('formats dates with two digits properly', function() { + assertNowDateFormatted('10/10/2000', { month: 10, day: 10, year: 2000 }) + }) }) describe('decodeEntities', function() { - it.skip('TODO need `document`') + function assertDecodeEntities(expected, { textContent, innerText, desc }) { + const paragraph = { textContent, innerText } + sandbox.stub(document, "createElement").withArgs('p').returns(paragraph) + + const actual = Util.decodeEntities(desc) + + expect(actual).to.equal(expected) + expect(paragraph.innerHTML).to.equal(desc) + } + afterEach(function() { + sandbox.restore() + }) + it('returns textContent if available', function() { + assertDecodeEntities('textContent', + { textContent: 'textContent', innerText: 'innerText', desc: 'desc' }) + }) + it('otherwise returns innerText', function() { + assertDecodeEntities('innerText', + { innerText: 'innerText', desc: 'desc' }) + }) }) describe('getDistance', function() { it('(0,0) -> (0,0) = 0', function() { @@ -41,18 +76,72 @@ describe('Metamaps.Util.js', function() { }) }) describe('coordsToPixels', function() { + function assertCoordsToPixels(expectedX, expectedY, + x, y, sx, sy, px, py, width, height, ox, oy) { + const mGraph = { + canvas: { + getSize: () => ({ width, height }), + getPos: () => ({ x: px, y: py }), + translateOffsetX: ox, translateOffsetY: oy, + scaleOffsetX: sx, scaleOffsetY: sy + } + } + const coords = { x, y } + const actual = Util.coordsToPixels(mGraph, coords) + expect(actual.x).to.equal(expectedX) + expect(actual.y).to.equal(expectedY) + } + + it('returns 0,0 for null canvas', function() { expect(Util.coordsToPixels(null, {}).x).to.equal(0) expect(Util.coordsToPixels(null, {}).y).to.equal(0) }) - it.skip('TODO need initialized mGraph to test further') + it('does the correct calculation', function() { + assertCoordsToPixels(0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0) + assertCoordsToPixels(1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0) + assertCoordsToPixels(2, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 0) + assertCoordsToPixels(2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0) + assertCoordsToPixels(3, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0) + assertCoordsToPixels(3, 3, 1, 1, 2, 2, 1, 1, 0, 0, 0, 0) + assertCoordsToPixels(4, 3, 1, 1, 2, 2, 1, 1, 2, 0, 0, 0) + assertCoordsToPixels(4, 4, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0) + assertCoordsToPixels(9, 4, 1, 1, 2, 2, 1, 1, 2, 2, 5, 0) + assertCoordsToPixels(9, 9, 1, 1, 2, 2, 1, 1, 2, 2, 5, 5) + }) }) describe('pixelsToCoords', function() { + function assertPixelsToCoords(expectedX, expectedY, + x, y, px, py, width, height, ox, oy, sx, sy) { + const mGraph = { + canvas: { + getSize: () => ({ width, height }), + getPos: () => ({ x: px, y: py }), + translateOffsetX: ox, translateOffsetY: oy, + scaleOffsetX: sx, scaleOffsetY: sy + } + } + const coords = { x, y } + const actual = Util.pixelsToCoords(mGraph, coords) + expect(actual.x).to.equal(expectedX) + expect(actual.y).to.equal(expectedY) + } it('returns 0,0 for null canvas', function() { expect(Util.pixelsToCoords(null, {}).x).to.equal(0) expect(Util.pixelsToCoords(null, {}).y).to.equal(0) }) - it.skip('TODO need initialized mGraph to test further') + it('does the correct calculation', function() { + assertPixelsToCoords(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) + assertPixelsToCoords(5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 1, 1) + assertPixelsToCoords(4, 5, 5, 5, 1, 0, 0, 0, 0, 0, 1, 1) + assertPixelsToCoords(4, 4, 5, 5, 1, 1, 0, 0, 0, 0, 1, 1) + assertPixelsToCoords(3, 4, 5, 5, 1, 1, 2, 0, 0, 0, 1, 1) + assertPixelsToCoords(3, 3, 5, 5, 1, 1, 2, 2, 0, 0, 1, 1) + assertPixelsToCoords(2, 3, 5, 5, 1, 1, 2, 2, 1, 0, 1, 1) + assertPixelsToCoords(2, 2, 5, 5, 1, 1, 2, 2, 1, 1, 1, 1) + assertPixelsToCoords(4, 2, 5, 5, 1, 1, 2, 2, 1, 1, 0.5, 1) + assertPixelsToCoords(4, 4, 5, 5, 1, 1, 2, 2, 1, 1, 0.5, 0.5) + }) }) describe('getPastelColor', function() { it('1 => fefefe', function() { @@ -96,7 +185,27 @@ describe('Metamaps.Util.js', function() { }) }) describe('openLink', function() { - it.skip('TODO need `window`') + function stubWindow({ popupsAllowed }) { + const open = sandbox.stub(window, "open").returns(popupsAllowed) + const alert = sandbox.stub(window, "alert") + return { open, alert } + } + afterEach(function() { + sandbox.restore() + }) + it('blank url returns true', function() { + expect(Util.openLink('')).to.equal(true) + }) + it('popus allowed returns true', function() { + stubWindow({ popupsAllowed: true }) + expect(Util.openLink('https://www.google.ca')).to.equal(true) + }) + it('popups blocked shows alert', function() { + const { alert } = stubWindow({ popupsAllowed: false }) + expect(Util.openLink('https://www.google.ca')).to.equal(false) + expect(alert.calledWith('Please allow popups in order to open the link')) + .to.equal(true) + }) }) describe('mdToHTML', function() { it('filters xss', function() { @@ -124,9 +233,24 @@ describe('Metamaps.Util.js', function() { }) }) describe('logCanvasAttributes', function() { - it.skip('TODO need a canvas') + it('returns correct canvas attributes', function() { + const canvas = { + scaleOffsetX: 1, scaleOffsetY: 2, + canvases: [{ size: { width: 3, height: 4 } }] + } + sinon.stub(Util, "pixelsToCoords").returnsArg(1) + + const actual = Util.logCanvasAttributes(canvas) + + expect(actual.scaleX).to.equal(1) + expect(actual.scaleY).to.equal(2) + + // stub will return the x/y coords passed to pixelsToCoords + expect(actual.centreCoords.x).to.equal(3 / 2) + expect(actual.centreCoords.y).to.equal(4 / 2) + }) }) describe('resizeCanvas', function() { - it.skip('TODO need a canvas') + it.skip('TODO') }) })