diff --git a/test/dispatchers/mouseDispatcherTests.ts b/test/dispatchers/mouseDispatcherTests.ts index 83c1ba7c25..5a7ae6a1ff 100644 --- a/test/dispatchers/mouseDispatcherTests.ts +++ b/test/dispatchers/mouseDispatcherTests.ts @@ -3,137 +3,36 @@ describe("Dispatchers", () => { describe("Mouse Dispatcher", () => { - it("getDispatcher() creates only one Dispatcher.Mouse per ", () => { - let svg = TestMethods.generateSVG(); - - let md1 = Plottable.Dispatchers.Mouse.getDispatcher( svg.node()); - assert.isNotNull(md1, "created a new Dispatcher on an SVG"); - let md2 = Plottable.Dispatchers.Mouse.getDispatcher( svg.node()); - assert.strictEqual(md1, md2, "returned the existing Dispatcher if called again with same "); - - svg.remove(); - }); - - it("lastMousePosition() defaults to a non-null value", () => { - let svg = TestMethods.generateSVG(); - - let md = Plottable.Dispatchers.Mouse.getDispatcher( svg.node()); - let p = md.lastMousePosition(); - assert.isNotNull(p, "returns a value after initialization"); - assert.isNotNull(p.x, "x value is set"); - assert.isNotNull(p.y, "y value is set"); - - svg.remove(); - }); - - it("can remove callbacks by passing null", () => { - let targetWidth = 400, targetHeight = 400; - let target = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - target.append("rect").attr("width", targetWidth).attr("height", targetHeight); - - let targetX = 17; - let targetY = 76; - - let md = Plottable.Dispatchers.Mouse.getDispatcher( target.node()); - - let cb1Called = false; - let cb1 = (p: Plottable.Point, e: MouseEvent) => cb1Called = true; - let cb2Called = false; - let cb2 = (p: Plottable.Point, e: MouseEvent) => cb2Called = true; - - md.onMouseMove(cb1); - md.onMouseMove(cb2); - TestMethods.triggerFakeMouseEvent("mousemove", target, targetX, targetY); - assert.isTrue(cb1Called, "callback 1 was called on mousemove"); - assert.isTrue(cb2Called, "callback 2 was called on mousemove"); - - cb1Called = false; - cb2Called = false; - md.offMouseMove(cb1); - TestMethods.triggerFakeMouseEvent("mousemove", target, targetX, targetY); - assert.isFalse(cb1Called, "callback was not called after blanking"); - assert.isTrue(cb2Called, "callback 2 was still called"); - - target.remove(); + describe("Basic usage", () => { + let svg: d3.Selection; + let svgNode: SVGElement; + + beforeEach(() => { + svg = TestMethods.generateSVG(); + svgNode = svg.node(); + }); + + it("creates only one Dispatcher.Mouse per using getDispatcher() ", () => { + let dispatcher1 = Plottable.Dispatchers.Mouse.getDispatcher(svgNode); + assert.isNotNull(dispatcher1, "created a new Dispatcher on an SVG"); + let dispatcher2 = Plottable.Dispatchers.Mouse.getDispatcher(svgNode); + assert.strictEqual(dispatcher1, dispatcher2, "returned the existing Dispatcher if called again with same "); + + svg.remove(); + }); + + it("returns non-null value for default lastMousePosition()", () => { + let mouseDispatcher = Plottable.Dispatchers.Mouse.getDispatcher(svgNode); + let point = mouseDispatcher.lastMousePosition(); + assert.isNotNull(point, "returns a value after initialization"); + assert.isNotNull(point.x, "x value is set"); + assert.isNotNull(point.y, "y value is set"); + + svg.remove(); + }); }); - it("doesn't call callbacks if not in the DOM", () => { - let targetWidth = 400, targetHeight = 400; - let target = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - target.append("rect").attr("width", targetWidth).attr("height", targetHeight); - - let targetX = 17; - let targetY = 76; - - let md = Plottable.Dispatchers.Mouse.getDispatcher( target.node()); - - let callbackWasCalled = false; - let callback = (p: Plottable.Point, e: MouseEvent) => callbackWasCalled = true; - - md.onMouseMove(callback); - TestMethods.triggerFakeMouseEvent("mousemove", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on mousemove"); - - target.remove(); - callbackWasCalled = false; - TestMethods.triggerFakeMouseEvent("mousemove", target, targetX, targetY); - assert.isFalse(callbackWasCalled, "callback was not called after was removed from DOM"); - - md.offMouseMove(callback); - }); - - it("doesn't call callbacks for clicks if obscured by overlay", () => { - let targetWidth = 400, targetHeight = 400; - let target = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - target.append("rect").attr("width", targetWidth).attr("height", targetHeight); - - let targetX = 17; - let targetY = 76; - - let md = Plottable.Dispatchers.Mouse.getDispatcher( target.node()); - - let callbackWasCalled = false; - let callback = (p: Plottable.Point, e: MouseEvent) => callbackWasCalled = true; - - md.onMouseDown(callback); - TestMethods.triggerFakeMouseEvent("mousedown", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on mousedown"); - - let element = target[0][0]; - let position = { x: 0, y: 0 }; - while (element != null) { - position.x += (element.offsetLeft || element.clientLeft || 0); - position.y += (element.offsetTop || element.clientTop || 0); - element = (element.offsetParent || element.parentNode); - } - - let overlay = TestMethods.getSVGParent().append("div") - .style({ - height: "400px", - width: "400px", - position: "absolute", - top: position.y + "px", - left: position.x + "px" - }); - - callbackWasCalled = false; - TestMethods.triggerFakeMouseEvent("mousedown", overlay, targetX, targetY); - assert.isFalse(callbackWasCalled, "callback was not called on mousedown on overlay"); - - md.offMouseDown(callback); - target.remove(); - overlay.remove(); - }); - - it("calls callbacks on mouseover, mousemove, and mouseout", () => { - let targetWidth = 400, targetHeight = 400; - let target = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - target.append("rect").attr("width", targetWidth).attr("height", targetHeight); - + describe("Callbacks", () => { let targetX = 17; let targetY = 76; let expectedPoint = { @@ -141,154 +40,235 @@ describe("Dispatchers", () => { y: targetY }; - let md = Plottable.Dispatchers.Mouse.getDispatcher( target.node()); - - let callbackWasCalled = false; - let callback = (p: Plottable.Point, e: MouseEvent) => { - callbackWasCalled = true; - TestMethods.assertPointsClose(p, expectedPoint, 0.5, "mouse position is correct"); - assert.isNotNull(e, "mouse event was passed to the callback"); - }; - - md.onMouseMove(callback); - - TestMethods.triggerFakeMouseEvent("mouseover", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on mouseover"); - callbackWasCalled = false; - TestMethods.triggerFakeMouseEvent("mousemove", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on mousemove"); - callbackWasCalled = false; - TestMethods.triggerFakeMouseEvent("mouseout", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on mouseout"); - - md.offMouseMove(callback); - target.remove(); + let svg: d3.Selection; + let mouseDispatcher: Plottable.Dispatchers.Mouse; + + beforeEach(() => { + let SVG_WIDTH = 400; + let SVG_HEIGHT = 400; + svg = TestMethods.generateSVG(SVG_WIDTH, SVG_HEIGHT); + // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space + svg.append("rect").attr("width", SVG_WIDTH).attr("height", SVG_HEIGHT); + + mouseDispatcher = Plottable.Dispatchers.Mouse.getDispatcher( svg.node()); + }); + + it("calls the mouseDown callback", () => { + let callbackWasCalled = false; + let callback = (point: Plottable.Point, event: MouseEvent) => { + callbackWasCalled = true; + TestMethods.assertPointsClose(point, expectedPoint, 0.5, "mouse position is correct"); + assert.isNotNull(event, "mouse event was passed to the callback"); + assert.instanceOf(event, MouseEvent, "the event passed is an instance of MouseEvent"); + }; + + assert.strictEqual(mouseDispatcher.onMouseDown(callback), mouseDispatcher, + "setting the mouseDown callback returns the dispatcher"); + + TestMethods.triggerFakeMouseEvent("mousedown", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on mouseDown"); + + assert.strictEqual(mouseDispatcher.offMouseDown(callback), mouseDispatcher, + "unsetting the mouseDown callback returns the dispatcher"); + + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("mousedown", svg, targetX, targetY); + assert.isFalse(callbackWasCalled, "callback was disconnected from the dispatcher"); + + svg.remove(); + }); + + it("calls the mouseUp callback", () => { + let callbackWasCalled = false; + let callback = (point: Plottable.Point, event: MouseEvent) => { + callbackWasCalled = true; + TestMethods.assertPointsClose(point, expectedPoint, 0.5, "mouse position is correct"); + assert.isNotNull(event, "mouse event was passed to the callback"); + assert.instanceOf(event, MouseEvent, "the event passed is an instance of MouseEvent"); + }; + + assert.strictEqual(mouseDispatcher.onMouseUp(callback), mouseDispatcher, + "setting the mouseUp callback returns the dispatcher"); + + TestMethods.triggerFakeMouseEvent("mouseup", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on mouseUp"); + + assert.strictEqual(mouseDispatcher.offMouseUp(callback), mouseDispatcher, + "unsetting the mouseUp callback returns the dispatcher"); + + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("mouseup", svg, targetX, targetY); + assert.isFalse(callbackWasCalled, "callback was disconnected from the dispatcher"); + + svg.remove(); + }); + + it("calls the wheel callback", () => { + // HACKHACK PhantomJS doesn't implement fake creation of WheelEvents + // https://github.com/ariya/phantomjs/issues/11289 + if (window.PHANTOMJS) { + svg.remove(); + return; + } + + let targetDeltaY = 10; + + let callbackWasCalled = false; + let callback = (point: Plottable.Point, event: WheelEvent) => { + callbackWasCalled = true; + assert.strictEqual(event.deltaY, targetDeltaY, "deltaY value was passed to callback"); + TestMethods.assertPointsClose(point, expectedPoint, 0.5, "mouse position is correct"); + assert.isNotNull(event, "mouse event was passed to the callback"); + assert.instanceOf(event, MouseEvent, "the event passed is an instance of MouseEvent"); + }; + + assert.strictEqual(mouseDispatcher.onWheel(callback), mouseDispatcher, + "setting the wheel callback returns the dispatcher"); + + TestMethods.triggerFakeWheelEvent("wheel", svg, targetX, targetY, targetDeltaY); + assert.isTrue(callbackWasCalled, "callback was called on wheel"); + + assert.strictEqual(mouseDispatcher.offWheel(callback), mouseDispatcher, + "unsetting the wheel callback returns the dispatcher"); + + callbackWasCalled = false; + TestMethods.triggerFakeWheelEvent("wheel", svg, targetX, targetY, targetDeltaY); + assert.isFalse(callbackWasCalled, "callback was disconnected from the dispatcher"); + + svg.remove(); + }); + + it("calls the dblClick callback", () => { + let callbackWasCalled = false; + let callback = (point: Plottable.Point, event: MouseEvent) => { + callbackWasCalled = true; + TestMethods.assertPointsClose(point, expectedPoint, 0.5, "mouse position is correct"); + assert.isNotNull(event, "mouse event was passed to the callback"); + assert.instanceOf(event, MouseEvent, "the event passed is an instance of MouseEvent"); + }; + + assert.strictEqual(mouseDispatcher.onDblClick(callback), mouseDispatcher, + "setting the dblClick callback returns the dispatcher"); + + TestMethods.triggerFakeMouseEvent("dblclick", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on dblClick"); + + assert.strictEqual(mouseDispatcher.offDblClick(callback), mouseDispatcher, + "unsetting the dblClick callback returns the dispatcher"); + + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("dblclick", svg, targetX, targetY); + assert.isFalse(callbackWasCalled, "callback was disconnected from the dispatcher"); + + svg.remove(); + }); + + it("calls mouseMove callback on mouseover, mousemove, and mouseout", () => { + let callbackWasCalled = false; + let callback = (point: Plottable.Point, event: MouseEvent) => { + callbackWasCalled = true; + TestMethods.assertPointsClose(point, expectedPoint, 0.5, "mouse position is correct"); + assert.isNotNull(event, "mouse event was passed to the callback"); + assert.instanceOf(event, MouseEvent, "the event passed is an instance of MouseEvent"); + }; + + mouseDispatcher.onMouseMove(callback); + + TestMethods.triggerFakeMouseEvent("mouseover", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on mouseover"); + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("mousemove", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on mousemove"); + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("mouseout", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on mouseout"); + + mouseDispatcher.offMouseMove(callback); + + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("mouseover", svg, targetX, targetY); + assert.isFalse(callbackWasCalled, "disconnected dispatcher callback not called on mouseover"); + TestMethods.triggerFakeMouseEvent("mousemove", svg, targetX, targetY); + assert.isFalse(callbackWasCalled, "disconnected dispatcher callback not called on mousemove"); + TestMethods.triggerFakeMouseEvent("mouseout", svg, targetX, targetY); + assert.isFalse(callbackWasCalled, "disconnected dispatcher callback not called on mouseout"); + + svg.remove(); + }); + + it("can register two callbacks for the same mouse dispatcher", () => { + let cb1Called = false; + let cb1 = () => cb1Called = true; + let cb2Called = false; + let cb2 = () => cb2Called = true; + + mouseDispatcher.onMouseMove(cb1); + mouseDispatcher.onMouseMove(cb2); + TestMethods.triggerFakeMouseEvent("mousemove", svg, targetX, targetY); + assert.isTrue(cb1Called, "callback 1 was called on mousemove"); + assert.isTrue(cb2Called, "callback 2 was called on mousemove"); + + cb1Called = false; + cb2Called = false; + mouseDispatcher.offMouseMove(cb1); + TestMethods.triggerFakeMouseEvent("mousemove", svg, targetX, targetY); + assert.isFalse(cb1Called, "callback was not called after blanking"); + assert.isTrue(cb2Called, "callback 2 was still called"); + + mouseDispatcher.offMouseMove(cb2); + svg.remove(); + }); + + it("doesn't call callbacks if not in the DOM", () => { + let callbackWasCalled = false; + let callback = () => callbackWasCalled = true; + + mouseDispatcher.onMouseMove(callback); + TestMethods.triggerFakeMouseEvent("mousemove", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on mousemove"); + + svg.remove(); + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("mousemove", svg, targetX, targetY); + assert.isFalse(callbackWasCalled, "callback was not called after was removed from DOM"); + + mouseDispatcher.offMouseMove(callback); + }); + + it("doesn't call callbacks for clicks if obscured by overlay", () => { + let callbackWasCalled = false; + let callback = () => callbackWasCalled = true; + + mouseDispatcher.onMouseDown(callback); + TestMethods.triggerFakeMouseEvent("mousedown", svg, targetX, targetY); + assert.isTrue(callbackWasCalled, "callback was called on mousedown"); + + let element = svg[0][0]; + // Getting the absolute coordinates of the SVG in order to place the overlay at the right location + let topLeftCorner = { x: 0, y: 0 }; + while (element != null) { + topLeftCorner.x += (element.offsetLeft || element.clientLeft || 0); + topLeftCorner.y += (element.offsetTop || element.clientTop || 0); + element = (element.offsetParent || element.parentNode); + } + + let overlay = TestMethods.getSVGParent().append("div").style({ + height: "400px", + width: "400px", + topLeftCorner: "absolute", + top: topLeftCorner.y + "px", + left: topLeftCorner.x + "px" + }); + + callbackWasCalled = false; + TestMethods.triggerFakeMouseEvent("mousedown", overlay, targetX, targetY); + assert.isFalse(callbackWasCalled, "callback was not called on mousedown on overlay"); + + mouseDispatcher.offMouseDown(callback); + svg.remove(); + overlay.remove(); + }); }); - it("onMouseDown()", () => { - let targetWidth = 400, targetHeight = 400; - let target = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - target.append("rect").attr("width", targetWidth).attr("height", targetHeight); - - let targetX = 17; - let targetY = 76; - let expectedPoint = { - x: targetX, - y: targetY - }; - - let md = Plottable.Dispatchers.Mouse.getDispatcher( target.node()); - - let callbackWasCalled = false; - let callback = (p: Plottable.Point, e: MouseEvent) => { - callbackWasCalled = true; - TestMethods.assertPointsClose(p, expectedPoint, 0.5, "mouse position is correct"); - assert.isNotNull(e, "mouse event was passed to the callback"); - }; - - md.onMouseDown(callback); - - TestMethods.triggerFakeMouseEvent("mousedown", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on mousedown"); - - md.offMouseDown(callback); - target.remove(); - }); - - it("onMouseUp()", () => { - let targetWidth = 400, targetHeight = 400; - let target = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - target.append("rect").attr("width", targetWidth).attr("height", targetHeight); - - let targetX = 17; - let targetY = 76; - let expectedPoint = { - x: targetX, - y: targetY - }; - - let md = Plottable.Dispatchers.Mouse.getDispatcher( target.node()); - - let callbackWasCalled = false; - let callback = (p: Plottable.Point, e: MouseEvent) => { - callbackWasCalled = true; - TestMethods.assertPointsClose(p, expectedPoint, 0.5, "mouse position is correct"); - assert.isNotNull(e, "mouse event was passed to the callback"); - }; - - md.onMouseUp(callback); - - TestMethods.triggerFakeMouseEvent("mouseup", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on mouseup"); - - md.offMouseUp(callback); - target.remove(); - }); - - it("onWheel()", () => { - // HACKHACK PhantomJS doesn't implement fake creation of WheelEvents - // https://github.com/ariya/phantomjs/issues/11289 - if (window.PHANTOMJS) { - return; - } - let targetWidth = 400, targetHeight = 400; - let svg = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - svg.append("rect").attr("width", targetWidth).attr("height", targetHeight); - - let targetX = 17; - let targetY = 76; - let expectedPoint = { - x: targetX, - y: targetY - }; - let targetDeltaY = 10; - - let md = Plottable.Dispatchers.Mouse.getDispatcher( svg.node()); - - let callbackWasCalled = false; - let callback = (p: Plottable.Point, e: WheelEvent) => { - callbackWasCalled = true; - assert.strictEqual(e.deltaY, targetDeltaY, "deltaY value was passed to callback"); - TestMethods.assertPointsClose(p, expectedPoint, 0.5, "mouse position is correct"); - assert.isNotNull(e, "mouse event was passed to the callback"); - }; - - md.onWheel(callback); - - TestMethods.triggerFakeWheelEvent("wheel", svg, targetX, targetY, targetDeltaY); - assert.isTrue(callbackWasCalled, "callback was called on wheel"); - - md.offWheel(callback); - svg.remove(); - }); - - it("onDblClick()", () => { - let targetWidth = 400, targetHeight = 400; - let target = TestMethods.generateSVG(targetWidth, targetHeight); - // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space - target.append("rect").attr("width", targetWidth).attr("height", targetHeight); - - let targetX = 17; - let targetY = 76; - - let md = Plottable.Dispatchers.Mouse.getDispatcher( target.node()); - - let callbackWasCalled = false; - let callback = (p: Plottable.Point, e: MouseEvent) => { - callbackWasCalled = true; - assert.isNotNull(e, "mouse event was passed to the callback"); - }; - - md.onDblClick(callback); - - TestMethods.triggerFakeMouseEvent("dblclick", target, targetX, targetY); - assert.isTrue(callbackWasCalled, "callback was called on dblClick"); - - md.offDblClick(callback); - target.remove(); - }); }); });