{"action":"created","comment":{"url":"https://api.github.com/repos/palantir/plottable/pulls/comments/39412280","id":39412280,"diff_hunk":"@@ -2,249 +2,282 @@\n \n describe(\"Dispatchers\", () => {\n   describe(\"Touch Dispatcher\", () => {\n-    it(\"getDispatcher() creates only one Dispatcher.Touch per <svg>\", () => {\n-      let svg = TestMethods.generateSVG();\n \n-      let td1 = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> svg.node());\n-      assert.isNotNull(td1, \"created a new Dispatcher on an SVG\");\n-      let td2 = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> svg.node());\n-      assert.strictEqual(td1, td2, \"returned the existing Dispatcher if called again with same <svg>\");\n+    describe(\"Basic usage\", () => {\n+      it(\"creates only one Dispatcher.Touch per <svg> using getDispatcher()\", () => {\n+        let svg = TestMethods.generateSVG();\n \n-      svg.remove();\n-    });\n+        let td1 = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> svg.node());\n+        assert.isNotNull(td1, \"created a new Dispatcher on an SVG\");\n+        let td2 = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> svg.node());\n+        assert.strictEqual(td1, td2, \"returned the existing Dispatcher if called again with same <svg>\");\n \n-    it(\"onTouchStart()\", () => {\n-      let targetWidth = 400, targetHeight = 400;\n-      let target = TestMethods.generateSVG(targetWidth, targetHeight);\n-      // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space\n-      target.append(\"rect\").attr(\"width\", targetWidth).attr(\"height\", targetHeight);\n-\n-      let targetXs = [17, 18, 12, 23, 44];\n-      let targetYs = [77, 78, 52, 43, 14];\n-      let expectedPoints = targetXs.map((targetX, i) => {\n-        return {\n-          x: targetX,\n-          y: targetYs[i]\n-        };\n+        svg.remove();\n       });\n-      let ids = targetXs.map((targetX, i) => i);\n+    });\n+\n+    describe(\"Callbacks\", () => {\n+      let svg: d3.Selection<void>;\n+      let touchDispatcher: Plottable.Dispatchers.Touch;\n+\n+      beforeEach(() => {\n+        let SVG_WIDTH = 400;\n+        let SVG_HEIGHT = 400;\n \n-      let td = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> target.node());\n+        svg = TestMethods.generateSVG(SVG_WIDTH, SVG_HEIGHT);\n+        // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space\n+        svg.append(\"rect\").attr(\"width\", SVG_WIDTH).attr(\"height\", SVG_HEIGHT);\n+        touchDispatcher = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> svg.node());\n+      });\n \n-      let callbackWasCalled = false;\n-      let callback = function(ids: number[], points: { [id: number]: Plottable.Point; }, e: TouchEvent) {\n-        callbackWasCalled = true;\n-        ids.forEach((id) => {\n-          TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+      it(\"calls the touchStart callback\", () => {\n+        let targetXs = [17, 18, 12, 23, 44];\n+        let targetYs = [77, 78, 52, 43, 14];\n+        let expectedPoints = targetXs.map((targetX, i) => {\n+          return {\n+            x: targetX,\n+            y: targetYs[i]\n+          };\n         });\n-        assert.isNotNull(e, \"TouchEvent was passed to the Dispatcher\");\n-      };\n+        let ids = targetXs.map((targetX, i) => i);\n+\n+        let callbackWasCalled = false;\n+        let callback = (ids: number[], points: { [id: number]: Plottable.Point; }, event: TouchEvent) => {\n+          callbackWasCalled = true;\n+          ids.forEach((id) => {\n+            TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+          });\n+          assert.isNotNull(event, \"TouchEvent was passed to the Dispatcher\");\n+        };\n \n-      td.onTouchStart(callback);\n+        assert.strictEqual(touchDispatcher.onTouchStart(callback), touchDispatcher,\n+          \"setting the touchStart callback returns the dispatcher\");\n \n-      TestMethods.triggerFakeTouchEvent(\"touchstart\", target, expectedPoints, ids);\n-      assert.isTrue(callbackWasCalled, \"callback was called on touchstart\");\n+        TestMethods.triggerFakeTouchEvent(\"touchstart\", svg, expectedPoints, ids);\n+        assert.isTrue(callbackWasCalled, \"callback was called on touchstart\");\n \n-      td.offTouchStart(callback);\n-      target.remove();\n-    });\n+        assert.strictEqual(touchDispatcher.offTouchStart(callback), touchDispatcher,\n+          \"unsetting the touchStart callback returns the dispatcher\");\n \n-    it(\"onTouchMove()\", () => {\n-      let targetWidth = 400, targetHeight = 400;\n-      let target = TestMethods.generateSVG(targetWidth, targetHeight);\n-      // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space\n-      target.append(\"rect\").attr(\"width\", targetWidth).attr(\"height\", targetHeight);\n-\n-      let targetXs = [17, 18, 12, 23, 44];\n-      let targetYs = [77, 78, 52, 43, 14];\n-      let expectedPoints = targetXs.map((targetX, i) => {\n-        return {\n-          x: targetX,\n-          y: targetYs[i]\n-        };\n-      });\n-      let ids = targetXs.map((targetX, i) => i);\n+        callbackWasCalled = false;\n+        TestMethods.triggerFakeTouchEvent(\"touchstart\", svg, expectedPoints, ids);\n+        assert.isFalse(callbackWasCalled, \"callback was disconnected from the dispatcher\");\n \n-      let td = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> target.node());\n+        svg.remove();\n+      });\n \n-      let callbackWasCalled = false;\n-      let callback = function(ids: number[], points: { [id: number]: Plottable.Point; }, e: TouchEvent) {\n-        callbackWasCalled = true;\n-        ids.forEach((id) => {\n-          TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+      it(\"calls the touchMove callback\", () => {\n+        let targetXs = [17, 18, 12, 23, 44];\n+        let targetYs = [77, 78, 52, 43, 14];\n+        let expectedPoints = targetXs.map((targetX, i) => {\n+          return {\n+            x: targetX,\n+            y: targetYs[i]\n+          };\n         });\n-        assert.isNotNull(e, \"TouchEvent was passed to the Dispatcher\");\n-      };\n+        let ids = targetXs.map((targetX, i) => i);\n+\n+        let callbackWasCalled = false;\n+        let callback = (ids: number[], points: { [id: number]: Plottable.Point; }, event: TouchEvent) => {\n+          callbackWasCalled = true;\n+          ids.forEach((id) => {\n+            TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+          });\n+          assert.isNotNull(event, \"TouchEvent was passed to the Dispatcher\");\n+        };\n \n-      td.onTouchMove(callback);\n+        assert.strictEqual(touchDispatcher.onTouchMove(callback), touchDispatcher,\n+          \"setting the touchMove callback returns the dispatcher\");\n \n-      TestMethods.triggerFakeTouchEvent(\"touchmove\", target, expectedPoints, ids);\n-      assert.isTrue(callbackWasCalled, \"callback was called on touchmove\");\n+        TestMethods.triggerFakeTouchEvent(\"touchmove\", svg, expectedPoints, ids);\n+        assert.isTrue(callbackWasCalled, \"callback was called on touchmove\");\n \n-      td.offTouchMove(callback);\n-      target.remove();\n-    });\n+        assert.strictEqual(touchDispatcher.offTouchMove(callback), touchDispatcher,\n+          \"unsetting the touchMove callback returns the dispatcher\");\n \n-    it(\"onTouchEnd()\", () => {\n-      let targetWidth = 400, targetHeight = 400;\n-      let target = TestMethods.generateSVG(targetWidth, targetHeight);\n-      // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space\n-      target.append(\"rect\").attr(\"width\", targetWidth).attr(\"height\", targetHeight);\n-\n-      let targetXs = [17, 18, 12, 23, 44];\n-      let targetYs = [77, 78, 52, 43, 14];\n-      let expectedPoints = targetXs.map((targetX, i) => {\n-        return {\n-          x: targetX,\n-          y: targetYs[i]\n-        };\n-      });\n-      let ids = targetXs.map((targetX, i) => i);\n+        callbackWasCalled = false;\n+        TestMethods.triggerFakeTouchEvent(\"touchmove\", svg, expectedPoints, ids);\n+        assert.isFalse(callbackWasCalled, \"callback was disconnected from the dispatcher\");\n \n-      let td = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> target.node());\n+        svg.remove();\n+      });\n \n-      let callbackWasCalled = false;\n-      let callback = function(ids: number[], points: { [id: number]: Plottable.Point; }, e: TouchEvent) {\n-        callbackWasCalled = true;\n-        ids.forEach((id) => {\n-          TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+      it(\"calls the touchEnd callback\", () => {\n+        let targetXs = [17, 18, 12, 23, 44];\n+        let targetYs = [77, 78, 52, 43, 14];\n+        let expectedPoints = targetXs.map((targetX, i) => {\n+          return {\n+            x: targetX,\n+            y: targetYs[i]\n+          };\n         });\n-        assert.isNotNull(e, \"TouchEvent was passed to the Dispatcher\");\n-      };\n+        let ids = targetXs.map((targetX, i) => i);\n+\n+        let callbackWasCalled = false;\n+        let callback = (ids: number[], points: { [id: number]: Plottable.Point; }, event: TouchEvent) => {\n+          callbackWasCalled = true;\n+          ids.forEach((id) => {\n+            TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+          });\n+          assert.isNotNull(event, \"TouchEvent was passed to the Dispatcher\");\n+        };\n \n-      td.onTouchEnd(callback);\n+        assert.strictEqual(touchDispatcher.onTouchEnd(callback), touchDispatcher,\n+          \"setting the touchEnd callback returns the dispatcher\");\n \n-      TestMethods.triggerFakeTouchEvent(\"touchend\", target, expectedPoints, ids);\n-      assert.isTrue(callbackWasCalled, \"callback was called on touchend\");\n+        TestMethods.triggerFakeTouchEvent(\"touchend\", svg, expectedPoints, ids);\n+        assert.isTrue(callbackWasCalled, \"callback was called on touchend\");\n \n-      td.offTouchEnd(callback);\n-      target.remove();\n-    });\n+        assert.strictEqual(touchDispatcher.offTouchEnd(callback), touchDispatcher,\n+          \"unsetting the touchEnd callback returns the dispatcher\");\n \n-    it(\"onTouchCancel()\", () => {\n-      let targetWidth = 400, targetHeight = 400;\n-      let target = TestMethods.generateSVG(targetWidth, targetHeight);\n-      // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space\n-      target.append(\"rect\").attr(\"width\", targetWidth).attr(\"height\", targetHeight);\n-\n-      let targetXs = [17, 18, 12, 23, 44];\n-      let targetYs = [77, 78, 52, 43, 14];\n-      let expectedPoints = targetXs.map((targetX, i) => {\n-        return {\n-          x: targetX,\n-          y: targetYs[i]\n-        };\n+        callbackWasCalled = false;\n+        TestMethods.triggerFakeTouchEvent(\"touchend\", svg, expectedPoints, ids);\n+        assert.isFalse(callbackWasCalled, \"callback was disconnected from the dispatcher\");\n+\n+        svg.remove();\n       });\n-      let ids = targetXs.map((targetX, i) => i);\n \n-      let td = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> target.node());\n+      it(\"calls the touchCancel callback\", () => {\n+        let targetXs = [17, 18, 12, 23, 44];\n+        let targetYs = [77, 78, 52, 43, 14];\n+        let expectedPoints = targetXs.map((targetX, i) => {\n+          return {\n+            x: targetX,\n+            y: targetYs[i]\n+          };\n+        });\n+        let ids = targetXs.map((targetX, i) => i);\n+\n+        let callbackWasCalled = false;\n+        let callback = (ids: number[], points: { [id: number]: Plottable.Point; }, event: TouchEvent) => {\n+          callbackWasCalled = true;\n+          ids.forEach((id) => {\n+            TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+          });\n+          assert.isNotNull(event, \"TouchEvent was passed to the Dispatcher\");\n+        };\n+\n+        assert.strictEqual(touchDispatcher.onTouchCancel(callback), touchDispatcher,\n+          \"setting the touchCancel callback returns the dispatcher\");\n+\n+        TestMethods.triggerFakeTouchEvent(\"touchcancel\", svg, expectedPoints, ids);\n+        assert.isTrue(callbackWasCalled, \"callback was called on touchend\");\n \n-      let callbackWasCalled = false;\n-      let callback = function(ids: number[], points: { [id: number]: Plottable.Point; }, e: TouchEvent) {\n-        callbackWasCalled = true;\n-        ids.forEach((id) => {\n-          TestMethods.assertPointsClose(points[id], expectedPoints[id], 0.5, \"touch position is correct\");\n+        assert.strictEqual(touchDispatcher.offTouchCancel(callback), touchDispatcher,\n+          \"unsetting the touchCancel callback returns the dispatcher\");\n+\n+        callbackWasCalled = false;\n+        TestMethods.triggerFakeTouchEvent(\"touchcancel\", svg, expectedPoints, ids);\n+        assert.isFalse(callbackWasCalled, \"callback was disconnected from the dispatcher\");\n+\n+        svg.remove();\n+      });\n+\n+      it(\"can register two callbacks for the same touch dispatcher\", () => {\n+        let targetXs = [17, 18, 12, 23, 44];\n+        let targetYs = [77, 78, 52, 43, 14];\n+        let expectedPoints = targetXs.map((targetX, i) => {\n+          return {\n+            x: targetX,\n+            y: targetYs[i]\n+          };\n         });\n-        assert.isNotNull(e, \"TouchEvent was passed to the Dispatcher\");\n-      };\n+        let ids = targetXs.map((targetX, i) => i);\n \n-      td.onTouchCancel(callback);\n+        let callback1WasCalled = false;\n+        let callback1 = () => callback1WasCalled = true;\n+        let callback2WasCalled = false;\n+        let callback2 = () => callback2WasCalled = true;\n \n-      TestMethods.triggerFakeTouchEvent(\"touchcancel\", target, expectedPoints, ids);\n-      assert.isTrue(callbackWasCalled, \"callback was called on touchend\");\n+        touchDispatcher.onTouchStart(callback1);\n+        touchDispatcher.onTouchStart(callback2);\n \n-      td.offTouchCancel(callback);\n-      target.remove();\n-    });\n+        TestMethods.triggerFakeTouchEvent(\"touchstart\", svg, expectedPoints, ids);\n \n-    it(\"doesn't call callbacks if not in the DOM\", () => {\n-      let targetWidth = 400, targetHeight = 400;\n-      let target = TestMethods.generateSVG(targetWidth, targetHeight);\n-      // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space\n-      target.append(\"rect\").attr(\"width\", targetWidth).attr(\"height\", targetHeight);\n-\n-      let targetXs = [17, 18, 12, 23, 44];\n-      let targetYs = [77, 78, 52, 43, 14];\n-      let expectedPoints = targetXs.map((targetX, i) => {\n-        return {\n-          x: targetX,\n-          y: targetYs[i]\n-        };\n+        assert.isTrue(callback1WasCalled, \"callback 1 was called on touchstart\");\n+        assert.isTrue(callback2WasCalled, \"callback 2 was called on touchstart\");\n+\n+        touchDispatcher.offTouchStart(callback1);\n+\n+        callback1WasCalled = false;\n+        callback2WasCalled = false;\n+        TestMethods.triggerFakeTouchEvent(\"touchstart\", svg, expectedPoints, ids);\n+        assert.isFalse(callback1WasCalled, \"callback 1 was disconnected from the dispatcher\");\n+        assert.isTrue(callback2WasCalled, \"callback 2 is still connected to the dispatcher\");\n+\n+        svg.remove();\n       });\n-      let ids = targetXs.map((targetX, i) => i);\n \n-      let td = Plottable.Dispatchers.Touch.getDispatcher(<SVGElement> target.node());\n+      it(\"doesn't call callbacks if not in the DOM\", () => {\n+        let targetXs = [17, 18, 12, 23, 44];\n+        let targetYs = [77, 78, 52, 43, 14];\n+        let expectedPoints = targetXs.map((targetX, i) => {\n+          return {\n+            x: targetX,\n+            y: targetYs[i]\n+          };\n+        });\n+        let ids = targetXs.map((targetX, i) => i);\n \n-      let callbackWasCalled = false;\n-      let callback = function(ids: number[], points: { [id: number]: Plottable.Point; }, e: TouchEvent) {\n-        callbackWasCalled = true;\n-        assert.isNotNull(e, \"TouchEvent was passed to the Dispatcher\");\n-      };\n+        let callbackWasCalled = false;\n+        let callback = () => callbackWasCalled = true;\n \n-      td.onTouchMove(callback);\n-      TestMethods.triggerFakeTouchEvent(\"touchmove\", target, expectedPoints, ids);\n-      assert.isTrue(callbackWasCalled, \"callback was called on touchmove\");\n+        touchDispatcher.onTouchMove(callback);\n+        TestMethods.triggerFakeTouchEvent(\"touchmove\", svg, expectedPoints, ids);\n+        assert.isTrue(callbackWasCalled, \"callback was called on touchmove\");\n \n-      target.remove();\n-      callbackWasCalled = false;\n-      TestMethods.triggerFakeTouchEvent(\"touchmove\", target, expectedPoints, ids);\n-      assert.isFalse(callbackWasCalled, \"callback was not called after <svg> was removed from DOM\");\n+        svg.remove();\n+        callbackWasCalled = false;\n+        TestMethods.triggerFakeTouchEvent(\"touchmove\", svg, expectedPoints, ids);\n+        assert.isFalse(callbackWasCalled, \"callback was not called after <svg> was removed from DOM\");\n \n-      td.offTouchMove(callback);\n-    });\n+        touchDispatcher.offTouchMove(callback);\n+      });\n \n-    it(\"doesn't call callbacks if obscured by overlay\", () => {\n-      let targetWidth = 400, targetHeight = 400;\n-      let target = TestMethods.generateSVG(targetWidth, targetHeight);\n-      // HACKHACK: PhantomJS can't measure SVGs unless they have something in them occupying space\n-      target.append(\"rect\").attr(\"width\", targetWidth).attr(\"height\", targetHeight);\n-\n-      let targetXs = [17, 18, 12, 23, 44];\n-      let targetYs = [77, 78, 52, 43, 14];\n-      let expectedPoints = targetXs.map((targetX, i) => {\n-        return {\n-          x: targetX,\n-          y: targetYs[i]\n-        };\n+      it(\"doesn't call callbacks if obscured by overlay\", () => {\n+        let targetXs = [17, 18, 12, 23, 44];\n+        let targetYs = [77, 78, 52, 43, 14];\n+        let expectedPoints = targetXs.map((targetX, i) => {\n+          return {\n+            x: targetX,\n+            y: targetYs[i]\n+          };\n+        });\n+        let ids = targetXs.map((targetX, i) => i);\n+\n+        let callbackWasCalled = false;\n+        let callback = () => callbackWasCalled = true;\n+\n+        touchDispatcher.onTouchStart(callback);\n+        TestMethods.triggerFakeTouchEvent(\"touchstart\", svg, expectedPoints, ids);\n+        assert.isTrue(callbackWasCalled, \"callback was called on touchstart\");\n+\n+        let element = <HTMLElement> svg[0][0];\n+        let position = { x: 0, y: 0 };\n+        while (element != null) {\n+          position.x += (element.offsetLeft || element.clientLeft || 0);\n+          position.y += (element.offsetTop || element.clientTop || 0);\n+          element = <HTMLElement> (element.offsetParent || element.parentNode);\n+        }\n+\n+        let overlay = TestMethods.getSVGParent().append(\"div\")\n+              .style({\n+                height: \"400px\",\n+                width: \"400px\",\n+                position: \"absolute\",\n+                top: position.y + \"px\",\n+                left: position.x + \"px\"\n+              });\n+\n+        callbackWasCalled = false;\n+        TestMethods.triggerFakeTouchEvent(\"touchmove\", svg, expectedPoints, ids);\n+        assert.isFalse(callbackWasCalled, \"callback was not called on touchstart on overlay\");","path":"test/dispatchers/touchDispatcherTests.ts","position":438,"original_position":438,"commit_id":"e9be35258b8e60b2eafaf621fba2bac76325c221","original_commit_id":"e9be35258b8e60b2eafaf621fba2bac76325c221","user":{"login":"jtlan","id":1440449,"avatar_url":"https://avatars.githubusercontent.com/u/1440449?v=3","gravatar_id":"","url":"https://api.github.com/users/jtlan","html_url":"https://github.com/jtlan","followers_url":"https://api.github.com/users/jtlan/followers","following_url":"https://api.github.com/users/jtlan/following{/other_user}","gists_url":"https://api.github.com/users/jtlan/gists{/gist_id}","starred_url":"https://api.github.com/users/jtlan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jtlan/subscriptions","organizations_url":"https://api.github.com/users/jtlan/orgs","repos_url":"https://api.github.com/users/jtlan/repos","events_url":"https://api.github.com/users/jtlan/events{/privacy}","received_events_url":"https://api.github.com/users/jtlan/received_events","type":"User","site_admin":false},"body":"This method and the preceding line don't match up -- are we checking `touchmove` or `touchstart`?","created_at":"2015-09-14T16:06:11Z","updated_at":"2015-09-14T16:06:11Z","html_url":"https://github.com/palantir/plottable/pull/2764#discussion_r39412280","pull_request_url":"https://api.github.com/repos/palantir/plottable/pulls/2764","_links":{"self":{"href":"https://api.github.com/repos/palantir/plottable/pulls/comments/39412280"},"html":{"href":"https://github.com/palantir/plottable/pull/2764#discussion_r39412280"},"pull_request":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2764"}}},"pull_request":{"url":"https://api.github.com/repos/palantir/plottable/pulls/2764","id":44842942,"html_url":"https://github.com/palantir/plottable/pull/2764","diff_url":"https://github.com/palantir/plottable/pull/2764.diff","patch_url":"https://github.com/palantir/plottable/pull/2764.patch","issue_url":"https://api.github.com/repos/palantir/plottable/issues/2764","number":2764,"state":"open","locked":false,"title":"Refactor touch dispatcher tests - Pass 1","user":{"login":"aicioara","id":3248682,"avatar_url":"https://avatars.githubusercontent.com/u/3248682?v=3","gravatar_id":"","url":"https://api.github.com/users/aicioara","html_url":"https://github.com/aicioara","followers_url":"https://api.github.com/users/aicioara/followers","following_url":"https://api.github.com/users/aicioara/following{/other_user}","gists_url":"https://api.github.com/users/aicioara/gists{/gist_id}","starred_url":"https://api.github.com/users/aicioara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aicioara/subscriptions","organizations_url":"https://api.github.com/users/aicioara/orgs","repos_url":"https://api.github.com/users/aicioara/repos","events_url":"https://api.github.com/users/aicioara/events{/privacy}","received_events_url":"https://api.github.com/users/aicioara/received_events","type":"User","site_admin":false},"body":"Part of #2628\r\n\r\nI will be doing 2 passes because I will get more context (and better sense of best practices) by refactoring other files. However, please flag anything that seems unusual.\r\n\r\nAs part of this: \r\n- **Test semantics: hierarchy, naming, testing, but no coverage check**\r\n- Applied best practices from the wiki page\r\n- Factored out common code into `beforeEach()` clauses\r\n- No nested `beforeEach()`es\r\n- Cleaned the console\r\n- Remade hierarchy as shown bellow\r\n\r\n![screen shot 2015-09-11 at 5 53 50 pm](https://cloud.githubusercontent.com/assets/3248682/9829126/27416f6c-58ae-11e5-8e6d-888ece8971e9.png)\r\n","created_at":"2015-09-12T00:54:38Z","updated_at":"2015-09-14T16:06:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"30e456314665e629296726997eb637f1234867b7","assignee":{"login":"jtlan","id":1440449,"avatar_url":"https://avatars.githubusercontent.com/u/1440449?v=3","gravatar_id":"","url":"https://api.github.com/users/jtlan","html_url":"https://github.com/jtlan","followers_url":"https://api.github.com/users/jtlan/followers","following_url":"https://api.github.com/users/jtlan/following{/other_user}","gists_url":"https://api.github.com/users/jtlan/gists{/gist_id}","starred_url":"https://api.github.com/users/jtlan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jtlan/subscriptions","organizations_url":"https://api.github.com/users/jtlan/orgs","repos_url":"https://api.github.com/users/jtlan/repos","events_url":"https://api.github.com/users/jtlan/events{/privacy}","received_events_url":"https://api.github.com/users/jtlan/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/palantir/plottable/pulls/2764/commits","review_comments_url":"https://api.github.com/repos/palantir/plottable/pulls/2764/comments","review_comment_url":"https://api.github.com/repos/palantir/plottable/pulls/comments{/number}","comments_url":"https://api.github.com/repos/palantir/plottable/issues/2764/comments","statuses_url":"https://api.github.com/repos/palantir/plottable/statuses/e9be35258b8e60b2eafaf621fba2bac76325c221","head":{"label":"palantir:refactorTouchDispatcher","ref":"refactorTouchDispatcher","sha":"e9be35258b8e60b2eafaf621fba2bac76325c221","user":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"repo":{"id":16149854,"name":"plottable","full_name":"palantir/plottable","owner":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/palantir/plottable","description":"A library of modular chart components, built on D3","fork":false,"url":"https://api.github.com/repos/palantir/plottable","forks_url":"https://api.github.com/repos/palantir/plottable/forks","keys_url":"https://api.github.com/repos/palantir/plottable/keys{/key_id}","collaborators_url":"https://api.github.com/repos/palantir/plottable/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/palantir/plottable/teams","hooks_url":"https://api.github.com/repos/palantir/plottable/hooks","issue_events_url":"https://api.github.com/repos/palantir/plottable/issues/events{/number}","events_url":"https://api.github.com/repos/palantir/plottable/events","assignees_url":"https://api.github.com/repos/palantir/plottable/assignees{/user}","branches_url":"https://api.github.com/repos/palantir/plottable/branches{/branch}","tags_url":"https://api.github.com/repos/palantir/plottable/tags","blobs_url":"https://api.github.com/repos/palantir/plottable/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/palantir/plottable/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/palantir/plottable/git/refs{/sha}","trees_url":"https://api.github.com/repos/palantir/plottable/git/trees{/sha}","statuses_url":"https://api.github.com/repos/palantir/plottable/statuses/{sha}","languages_url":"https://api.github.com/repos/palantir/plottable/languages","stargazers_url":"https://api.github.com/repos/palantir/plottable/stargazers","contributors_url":"https://api.github.com/repos/palantir/plottable/contributors","subscribers_url":"https://api.github.com/repos/palantir/plottable/subscribers","subscription_url":"https://api.github.com/repos/palantir/plottable/subscription","commits_url":"https://api.github.com/repos/palantir/plottable/commits{/sha}","git_commits_url":"https://api.github.com/repos/palantir/plottable/git/commits{/sha}","comments_url":"https://api.github.com/repos/palantir/plottable/comments{/number}","issue_comment_url":"https://api.github.com/repos/palantir/plottable/issues/comments{/number}","contents_url":"https://api.github.com/repos/palantir/plottable/contents/{+path}","compare_url":"https://api.github.com/repos/palantir/plottable/compare/{base}...{head}","merges_url":"https://api.github.com/repos/palantir/plottable/merges","archive_url":"https://api.github.com/repos/palantir/plottable/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/palantir/plottable/downloads","issues_url":"https://api.github.com/repos/palantir/plottable/issues{/number}","pulls_url":"https://api.github.com/repos/palantir/plottable/pulls{/number}","milestones_url":"https://api.github.com/repos/palantir/plottable/milestones{/number}","notifications_url":"https://api.github.com/repos/palantir/plottable/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/palantir/plottable/labels{/name}","releases_url":"https://api.github.com/repos/palantir/plottable/releases{/id}","created_at":"2014-01-22T19:29:19Z","updated_at":"2015-09-12T14:26:41Z","pushed_at":"2015-09-14T16:01:57Z","git_url":"git://github.com/palantir/plottable.git","ssh_url":"git@github.com:palantir/plottable.git","clone_url":"https://github.com/palantir/plottable.git","svn_url":"https://github.com/palantir/plottable","homepage":"plottablejs.org","size":134331,"stargazers_count":717,"watchers_count":717,"language":"TypeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":74,"mirror_url":null,"open_issues_count":198,"forks":74,"open_issues":198,"watchers":717,"default_branch":"develop"}},"base":{"label":"palantir:develop","ref":"develop","sha":"bc7f4b26ae64604ccf0fed65c87e121e573c1936","user":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"repo":{"id":16149854,"name":"plottable","full_name":"palantir/plottable","owner":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/palantir/plottable","description":"A library of modular chart components, built on D3","fork":false,"url":"https://api.github.com/repos/palantir/plottable","forks_url":"https://api.github.com/repos/palantir/plottable/forks","keys_url":"https://api.github.com/repos/palantir/plottable/keys{/key_id}","collaborators_url":"https://api.github.com/repos/palantir/plottable/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/palantir/plottable/teams","hooks_url":"https://api.github.com/repos/palantir/plottable/hooks","issue_events_url":"https://api.github.com/repos/palantir/plottable/issues/events{/number}","events_url":"https://api.github.com/repos/palantir/plottable/events","assignees_url":"https://api.github.com/repos/palantir/plottable/assignees{/user}","branches_url":"https://api.github.com/repos/palantir/plottable/branches{/branch}","tags_url":"https://api.github.com/repos/palantir/plottable/tags","blobs_url":"https://api.github.com/repos/palantir/plottable/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/palantir/plottable/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/palantir/plottable/git/refs{/sha}","trees_url":"https://api.github.com/repos/palantir/plottable/git/trees{/sha}","statuses_url":"https://api.github.com/repos/palantir/plottable/statuses/{sha}","languages_url":"https://api.github.com/repos/palantir/plottable/languages","stargazers_url":"https://api.github.com/repos/palantir/plottable/stargazers","contributors_url":"https://api.github.com/repos/palantir/plottable/contributors","subscribers_url":"https://api.github.com/repos/palantir/plottable/subscribers","subscription_url":"https://api.github.com/repos/palantir/plottable/subscription","commits_url":"https://api.github.com/repos/palantir/plottable/commits{/sha}","git_commits_url":"https://api.github.com/repos/palantir/plottable/git/commits{/sha}","comments_url":"https://api.github.com/repos/palantir/plottable/comments{/number}","issue_comment_url":"https://api.github.com/repos/palantir/plottable/issues/comments{/number}","contents_url":"https://api.github.com/repos/palantir/plottable/contents/{+path}","compare_url":"https://api.github.com/repos/palantir/plottable/compare/{base}...{head}","merges_url":"https://api.github.com/repos/palantir/plottable/merges","archive_url":"https://api.github.com/repos/palantir/plottable/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/palantir/plottable/downloads","issues_url":"https://api.github.com/repos/palantir/plottable/issues{/number}","pulls_url":"https://api.github.com/repos/palantir/plottable/pulls{/number}","milestones_url":"https://api.github.com/repos/palantir/plottable/milestones{/number}","notifications_url":"https://api.github.com/repos/palantir/plottable/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/palantir/plottable/labels{/name}","releases_url":"https://api.github.com/repos/palantir/plottable/releases{/id}","created_at":"2014-01-22T19:29:19Z","updated_at":"2015-09-12T14:26:41Z","pushed_at":"2015-09-14T16:01:57Z","git_url":"git://github.com/palantir/plottable.git","ssh_url":"git@github.com:palantir/plottable.git","clone_url":"https://github.com/palantir/plottable.git","svn_url":"https://github.com/palantir/plottable","homepage":"plottablejs.org","size":134331,"stargazers_count":717,"watchers_count":717,"language":"TypeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":74,"mirror_url":null,"open_issues_count":198,"forks":74,"open_issues":198,"watchers":717,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2764"},"html":{"href":"https://github.com/palantir/plottable/pull/2764"},"issue":{"href":"https://api.github.com/repos/palantir/plottable/issues/2764"},"comments":{"href":"https://api.github.com/repos/palantir/plottable/issues/2764/comments"},"review_comments":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2764/comments"},"review_comment":{"href":"https://api.github.com/repos/palantir/plottable/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2764/commits"},"statuses":{"href":"https://api.github.com/repos/palantir/plottable/statuses/e9be35258b8e60b2eafaf621fba2bac76325c221"}}}}