From 5a42c4909ac990d87399c939903aebc4d8b26309 Mon Sep 17 00:00:00 2001
From: Jez Ng
Date: Mon, 3 Sep 2012 19:24:47 -0400
Subject: Make hints tests pass again.
Convert them to Coffeescript at the same time.
We really need to set up some automated way of running these tests, to
ensure they don't keep breaking.
---
 Cakefile                                  |   3 +-
 background_scripts/main.coffee            |   2 +-
 content_scripts/link_hints.coffee         |   6 +-
 test_harnesses/automated.html             | 312 ------------------------------
 test_harnesses/automated/automated.coffee | 197 +++++++++++++++++++
 test_harnesses/automated/automated.html   |  49 +++++
 6 files changed, 252 insertions(+), 317 deletions(-)
 delete mode 100644 test_harnesses/automated.html
 create mode 100644 test_harnesses/automated/automated.coffee
 create mode 100644 test_harnesses/automated/automated.html
diff --git a/Cakefile b/Cakefile
index 55653b7b..697c03dc 100644
--- a/Cakefile
+++ b/Cakefile
@@ -8,7 +8,8 @@ spawn_with_opts = (proc_name, opts) ->
     opt_array.push "--#{key}=#{value}"
   spawn proc_name, opt_array
 
-src_directories = ["tests", "background_scripts", "content_scripts", "lib", "options"]
+src_directories = ["tests", "background_scripts", "content_scripts", "lib", "options",
+                   "test_harnesses/automated"]
 
 task "build", "compile all coffeescript files to javascript", ->
   coffee = spawn "coffee", ["-c"].concat(src_directories)
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee
index 5b1ed4f7..c392f967 100644
--- a/background_scripts/main.coffee
+++ b/background_scripts/main.coffee
@@ -558,7 +558,7 @@ sendRequestHandlers =
   refreshCompleter: refreshCompleter
 
 # Convenience function for development use.
-window.runTests = -> open(chrome.extension.getURL('test_harnesses/automated.html'))
+window.runTests = -> open(chrome.extension.getURL('test_harnesses/automated/automated.html'))
 
 #
 # Begin initialization.
diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee
index 5cdbc6a7..1d5d668a 100644
--- a/content_scripts/link_hints.coffee
+++ b/content_scripts/link_hints.coffee
@@ -178,9 +178,9 @@ LinkHints =
       else if (linksMatched.length == 1)
         @activateLink(linksMatched[0], delay)
       else
-        for i, marker of hintMarkers
+        for marker in hintMarkers
           @hideMarker(marker)
-        for i, matched of linksMatched
+        for matched in linksMatched
           @showMarker(matched, @markerMatcher.hintKeystrokeQueue.length)
     false # We've handled this key, so prevent propagation.
 
@@ -404,7 +404,7 @@ filterHints =
     if (event.keyCode == keyCodes.enter)
       # activate the lowest-numbered link hint that is visible
       for marker in hintMarkers
-        if (marker.style.display  != "none")
+        if (marker.style.display != "none")
           return { linksMatched: [ marker ] }
     else if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey)
       # backspace clears hint key queue first, then acts on link text key queue.
diff --git a/test_harnesses/automated.html b/test_harnesses/automated.html
deleted file mode 100644
index 4c5f08ab..00000000
--- a/test_harnesses/automated.html
+++ /dev/null
@@ -1,312 +0,0 @@
-
-
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-  
-  
-    
-    
-
-    Vimium Tests
-
-    
-
-  
-
diff --git a/test_harnesses/automated/automated.coffee b/test_harnesses/automated/automated.coffee
new file mode 100644
index 00000000..c6f7639a
--- /dev/null
+++ b/test_harnesses/automated/automated.coffee
@@ -0,0 +1,197 @@
+#
+# Dispatching keyboard events via the DOM would require async tests,
+# which tend to be more complicated. Here we create mock events and
+# invoke the handlers directly.
+# 
+mockKeyboardEvent = (keyChar) ->
+  event = {}
+  event.charCode = (if keyCodes[keyChar] isnt undefined then keyCodes[keyChar] else keyChar.charCodeAt(0))
+  event.keyIdentifier = "U+00" + event.charCode.toString(16)
+  event.keyCode = event.charCode
+  event.stopPropagation = ->
+  event.preventDefault = ->
+  event
+
+#
+# Retrieve the hint markers as an array object.
+# 
+getHintMarkers = ->
+  Array::slice.call document.getElementsByClassName("vimiumHintMarker"), 0
+
+#
+# Generate tests that are common to both default and filtered
+# link hinting modes.
+# 
+createGeneralHintTests = (isFilteredMode) ->
+
+  context "Link hints",
+
+    setup ->
+      testContent = "test" + "tress"
+      document.getElementById("test-div").innerHTML = testContent
+      stub settings.values, "filterLinkHints", false
+
+    tearDown ->
+      document.getElementById("test-div").innerHTML = ""
+
+    should "create hints when activated, discard them when deactivated", ->
+      LinkHints.activateMode()
+      assert.isFalse not LinkHints.hintMarkerContainingDiv?
+      LinkHints.deactivateMode()
+      assert.isTrue not LinkHints.hintMarkerContainingDiv?
+
+    should "position items correctly", ->
+      assertStartPosition = (element1, element2) ->
+        assert.equal element1.getClientRects()[0].left, element2.getClientRects()[0].left
+        assert.equal element1.getClientRects()[0].top, element2.getClientRects()[0].top
+      stub document.body, "style", "static"
+      LinkHints.activateMode()
+      hintMarkers = getHintMarkers()
+      assertStartPosition document.getElementsByTagName("a")[0], hintMarkers[0]
+      assertStartPosition document.getElementsByTagName("a")[1], hintMarkers[1]
+      LinkHints.deactivateMode()
+      stub document.body.style, "position", "relative"
+      LinkHints.activateMode()
+      hintMarkers = getHintMarkers()
+      assertStartPosition document.getElementsByTagName("a")[0], hintMarkers[0]
+      assertStartPosition document.getElementsByTagName("a")[1], hintMarkers[1]
+      LinkHints.deactivateMode()
+
+createGeneralHintTests false
+createGeneralHintTests true
+
+context "Alphabetical link hints",
+
+  setup ->
+    stub settings.values, "filterLinkHints", false
+    stub settings.values, "linkHintCharacters", "ab"
+
+    # Three hints will trigger double hint chars.
+    createLinks 3
+    LinkHints.init()
+    LinkHints.activateMode()
+
+  tearDown ->
+    LinkHints.deactivateMode()
+    document.getElementById("test-div").innerHTML = ""
+
+  should "label the hints correctly", ->
+    # TODO(philc): This test verifies the current behavior, but the current behavior is incorrect.
+    # The output here should be something like aa, ab, b.
+    hintMarkers = getHintMarkers()
+    expectedHints = ["aa", "ba", "ab"]
+    for hint, i in expectedHints
+      assert.equal hint, hintMarkers[i].hintString
+
+  should "narrow the hints", ->
+    hintMarkers = getHintMarkers()
+    LinkHints.onKeyDownInMode hintMarkers, mockKeyboardEvent("A")
+    assert.equal "none", hintMarkers[1].style.display
+    assert.equal "", hintMarkers[0].style.display
+
+context "Filtered link hints",
+
+  setup ->
+    stub settings.values, "filterLinkHints", true
+
+  context "Text hints",
+
+    setup ->
+      testContent = "test" + "tress" + "trait" + "track![alt text]() "
+      document.getElementById("test-div").innerHTML = testContent
+      LinkHints.init()
+      LinkHints.activateMode()
+
+    tearDown ->
+      document.getElementById("test-div").innerHTML = ""
+      LinkHints.deactivateMode()
+
+    should "label the hints", ->
+      hintMarkers = getHintMarkers()
+      for i in [0...4]
+        assert.equal (i + 1).toString(), hintMarkers[i].textContent.toLowerCase()
+
+    should "narrow the hints", ->
+      hintMarkers = getHintMarkers()
+      LinkHints.onKeyDownInMode hintMarkers, mockKeyboardEvent("T")
+      LinkHints.onKeyDownInMode hintMarkers, mockKeyboardEvent("R")
+      assert.equal "none", hintMarkers[0].style.display
+      assert.equal "1", hintMarkers[1].hintString
+      assert.equal "", hintMarkers[1].style.display
+      LinkHints.onKeyDownInMode hintMarkers, mockKeyboardEvent("A")
+      assert.equal "2", hintMarkers[3].hintString
+
+  context "Image hints",
+
+    setup ->
+      testContent = "
"
+      document.getElementById("test-div").innerHTML = testContent
+      LinkHints.init()
+      LinkHints.activateMode()
+
+    tearDown ->
+      document.getElementById("test-div").innerHTML = ""
+      LinkHints.deactivateMode()
+
+    should "label the hints", ->
+      hintMarkers = getHintMarkers()
+      for i in [0...4]
+        assert.equal (i + 1).toString(), hintMarkers[i].textContent.toLowerCase()
+
+    should "narrow the hints", ->
+      hintMarkers = getHintMarkers()
+      LinkHints.onKeyDownInMode hintMarkers, mockKeyboardEvent("T")
+      LinkHints.onKeyDownInMode hintMarkers, mockKeyboardEvent("R")
+      assert.equal "none", hintMarkers[0].style.display
+      assert.equal "1", hintMarkers[1].hintString
+      assert.equal "", hintMarkers[1].style.display
+      LinkHints.onKeyDownInMode hintMarkers, mockKeyboardEvent("A")
+      assert.equal "2", hintMarkers[3].hintString
+
+  context "Image hints",
+
+    setup ->
+      testContent = "![alt text]() " + "
" + "![some title alt text]() " + "
" + "![some title]() " + "
" + "![]() "
+      document.getElementById("test-div").innerHTML = testContent
+      LinkHints.activateMode()
+
+    tearDown ->
+      document.getElementById("test-div").innerHTML = ""
+      LinkHints.deactivateMode()
+
+    should "label the images", ->
+      hintMarkers = getHintMarkers()
+      assert.equal "1: alt text", hintMarkers[0].textContent.toLowerCase()
+      assert.equal "2: alt text", hintMarkers[1].textContent.toLowerCase()
+      assert.equal "3: some title", hintMarkers[2].textContent.toLowerCase()
+      assert.equal "4", hintMarkers[3].textContent.toLowerCase()
+
+  context "Input hints",
+
+    setup ->
+      testContent = "" + "" + "" + "a label" + "a label: "
+      document.getElementById("test-div").innerHTML = testContent
+      LinkHints.activateMode()
+
+    tearDown ->
+      document.getElementById("test-div").innerHTML = ""
+      LinkHints.deactivateMode()
+
+    should "label the input elements", ->
+      hintMarkers = getHintMarkers()
+      assert.equal "1", hintMarkers[0].textContent.toLowerCase()
+      assert.equal "2", hintMarkers[1].textContent.toLowerCase()
+      assert.equal "3", hintMarkers[2].textContent.toLowerCase()
+      assert.equal "4: a label", hintMarkers[3].textContent.toLowerCase()
+      assert.equal "5: a label", hintMarkers[4].textContent.toLowerCase()
+
+context "Input focus",
+
+  setup ->
+    testContent = "" + "" + ""
+    document.getElementById("test-div").innerHTML = testContent
+
+  tearDown ->
+    document.getElementById("test-div").innerHTML = ""
+
+  should "focus the right element", ->
+    focusInput 1
+    assert.equal "first", document.activeElement.id
+    # deactivate the tabbing mode and its overlays
+    handlerStack[handlerStack.length - 1].keydown mockKeyboardEvent("A")
+
+    focusInput 100
+    assert.equal "third", document.activeElement.id
+    handlerStack[handlerStack.length - 1].keydown mockKeyboardEvent("A")
+
+Tests.outputMethod = (args...) ->
+  newOutput = args.join "\n"
+  # escape html
+  newOutput = newOutput.replace(/&/g, "&").replace(//g, ">")
+  # highlight the source of the error
+  newOutput = newOutput.replace(/\/([^:/]+):([0-9]+):([0-9]+)/, "/$1:$2:$3")
+  document.getElementById("output-div").innerHTML += "
"
+      document.getElementById("test-div").innerHTML = testContent
+      LinkHints.activateMode()
+
+    tearDown ->
+      document.getElementById("test-div").innerHTML = ""
+      LinkHints.deactivateMode()
+
+    should "label the images", ->
+      hintMarkers = getHintMarkers()
+      assert.equal "1: alt text", hintMarkers[0].textContent.toLowerCase()
+      assert.equal "2: alt text", hintMarkers[1].textContent.toLowerCase()
+      assert.equal "3: some title", hintMarkers[2].textContent.toLowerCase()
+      assert.equal "4", hintMarkers[3].textContent.toLowerCase()
+
+  context "Input hints",
+
+    setup ->
+      testContent = "" + "" + "" + "a label" + "a label: "
+      document.getElementById("test-div").innerHTML = testContent
+      LinkHints.activateMode()
+
+    tearDown ->
+      document.getElementById("test-div").innerHTML = ""
+      LinkHints.deactivateMode()
+
+    should "label the input elements", ->
+      hintMarkers = getHintMarkers()
+      assert.equal "1", hintMarkers[0].textContent.toLowerCase()
+      assert.equal "2", hintMarkers[1].textContent.toLowerCase()
+      assert.equal "3", hintMarkers[2].textContent.toLowerCase()
+      assert.equal "4: a label", hintMarkers[3].textContent.toLowerCase()
+      assert.equal "5: a label", hintMarkers[4].textContent.toLowerCase()
+
+context "Input focus",
+
+  setup ->
+    testContent = "" + "" + ""
+    document.getElementById("test-div").innerHTML = testContent
+
+  tearDown ->
+    document.getElementById("test-div").innerHTML = ""
+
+  should "focus the right element", ->
+    focusInput 1
+    assert.equal "first", document.activeElement.id
+    # deactivate the tabbing mode and its overlays
+    handlerStack[handlerStack.length - 1].keydown mockKeyboardEvent("A")
+
+    focusInput 100
+    assert.equal "third", document.activeElement.id
+    handlerStack[handlerStack.length - 1].keydown mockKeyboardEvent("A")
+
+Tests.outputMethod = (args...) ->
+  newOutput = args.join "\n"
+  # escape html
+  newOutput = newOutput.replace(/&/g, "&").replace(//g, ">")
+  # highlight the source of the error
+  newOutput = newOutput.replace(/\/([^:/]+):([0-9]+):([0-9]+)/, "/$1:$2:$3")
+  document.getElementById("output-div").innerHTML += "" + newOutput + "
"
+  console.log.apply console, args
+
+document.addEventListener "DOMContentLoaded", ->
+  setTimeout Tests.run, 200
+
+# ensure the extension has time to load before commencing the tests
+createLinks = (n) ->
+  for i in [0...n] by 1
+    link = document.createElement("a")
+    link.textContent = "test"
+    document.getElementById("test-div").appendChild link
diff --git a/test_harnesses/automated/automated.html b/test_harnesses/automated/automated.html
new file mode 100644
index 00000000..a0c8c7de
--- /dev/null
+++ b/test_harnesses/automated/automated.html
@@ -0,0 +1,49 @@
+
+
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+
+    Vimium Tests
+
+    
+
+  
+
-- 
cgit v1.2.3