aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cakefile3
-rw-r--r--background_scripts/main.coffee2
-rw-r--r--content_scripts/link_hints.coffee6
-rw-r--r--test_harnesses/automated.html312
-rw-r--r--test_harnesses/automated/automated.coffee197
-rw-r--r--test_harnesses/automated/automated.html49
6 files changed, 252 insertions, 317 deletions
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 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
- <head>
- <style type="text/css">
- body {
- font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
- width: 800px;
- margin: 0px auto;
- }
- #output-div {
- white-space: pre-wrap;
- background-color: #eee;
- font-family: monospace;
- margin: 0 0 50px 0;
- border-style: dashed;
- border-width: 1px 1px 0 1px;
- border-color: #999;
- }
- .errorPosition {
- color: #f33;
- font-weight: bold;
- }
- .output-section {
- padding: 10px 15px 10px 15px;
- border-bottom: dashed 1px #999;
- }
- </style>
- <link rel="stylesheet" type="text/css" href="../vimium.css" />
- <script type="text/javascript" src="../lib/utils.js"></script>
- <script type="text/javascript" src="../lib/keyboard_utils.js"></script>
- <script type="text/javascript" src="../lib/dom_utils.js"></script>
- <script type="text/javascript" src="../content_scripts/link_hints.js"></script>
- <script type="text/javascript" src="../lib/clipboard.js"></script>
- <script type="text/javascript" src="../content_scripts/vimium_frontend.js"></script>
- <script type="text/javascript" src="../tests/shoulda.js/shoulda.js"></script>
- <script type="text/javascript">
- /*
- * 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.
- */
- function mockKeyboardEvent(keyChar) {
- var event = {};
- event.charCode = keyCodes[keyChar] !== undefined ? keyCodes[keyChar] : keyChar.charCodeAt(0);
- event.keyIdentifier = "U+00" + event.charCode.toString(16);
- event.keyCode = event.charCode;
- event.stopPropagation = function(){};
- event.preventDefault = function(){};
- return event;
- }
-
- /*
- * Generate tests that are common to both default and filtered
- * link hinting modes.
- */
- function createGeneralHintTests(isFilteredMode) {
- context("Link hints",
-
- setup(function() {
- var testContent =
- "<a>test</a>" +
- "<a>tress</a>";
- document.getElementById("test-div").innerHTML = testContent;
- LinkHints.markerMatcher = alphabetHints;
- }),
-
- tearDown(function() {
- document.getElementById("test-div").innerHTML = "";
- }),
-
- should("create hints when activated, discard them when deactivated", function() {
- LinkHints.activateMode();
- assert.isFalse(LinkHints.hintMarkerContainingDiv == null);
- LinkHints.deactivateMode();
- assert.isTrue(LinkHints.hintMarkerContainingDiv == null);
- }),
-
- should("position items correctly", function() {
- function 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();
- assertStartPosition(document.getElementsByTagName("a")[0], LinkHints.hintMarkers[0]);
- assertStartPosition(document.getElementsByTagName("a")[1], LinkHints.hintMarkers[1]);
- LinkHints.deactivateMode();
-
- stub(document.body.style, "position", "relative");
- LinkHints.activateMode();
- assertStartPosition(document.getElementsByTagName("a")[0], LinkHints.hintMarkers[0]);
- assertStartPosition(document.getElementsByTagName("a")[1], LinkHints.hintMarkers[1]);
- LinkHints.deactivateMode();
- })
-
- );
- }
- createGeneralHintTests(false);
- createGeneralHintTests(true);
-
- context("Alphabetical link hints",
-
- setup(function() {
- stub(settings.values, "filterLinkHints", "false");
- stub(settings.values, "linkHintCharacters", "ab")
- LinkHints.markerMatcher = alphabetHints;
-
- // Three hints will trigger double hint chars.
- createLinks(3);
- LinkHints.activateMode();
- }),
-
- tearDown(function() {
- LinkHints.deactivateMode();
- document.getElementById("test-div").innerHTML = "";
- }),
-
- should("label the hints correctly", function() {
- // TODO(philc): This test verifies the current behavior, but the current behavior is incorrect.
- // The output here should be something like aa, ab, b.
- var expectedHints = ["aa", "ba", "ab"];
- console.log(LinkHints.hintMarkers);
- for (var i = 0; i < expectedHints.length; i++)
- assert.equal(expectedHints[i], LinkHints.hintMarkers[i].hintString);
- }),
-
- should("narrow the hints", function() {
- LinkHints.onKeyDownInMode(mockKeyboardEvent("A"));
- assert.equal("none", LinkHints.hintMarkers[1].style.display);
- assert.equal("", LinkHints.hintMarkers[0].style.display);
- })
-
- );
-
- context("Filtered link hints",
-
- setup(function() {
- stub(settings.values, "filterLinkHints", "true");
- LinkHints.markerMatcher = filterHints;
- }),
-
- context("Text hints",
-
- setup(function() {
- var testContent =
- "<a>test</a>" +
- "<a>tress</a>" +
- "<a>trait</a>" +
- "<a>track<img alt='alt text'/></a>";
- document.getElementById("test-div").innerHTML = testContent;
- LinkHints.activateMode();
- }),
-
- tearDown(function() {
- document.getElementById("test-div").innerHTML = "";
- LinkHints.deactivateMode();
- }),
-
- should("label the hints", function() {
- for (var i = 0; i < 4; i++)
- assert.equal((i + 1).toString(), LinkHints.hintMarkers[i].textContent.toLowerCase());
- }),
-
- should("narrow the hints", function() {
- LinkHints.onKeyDownInMode(mockKeyboardEvent("T"));
- LinkHints.onKeyDownInMode(mockKeyboardEvent("R"));
- assert.equal("none", LinkHints.hintMarkers[0].style.display);
- assert.equal("1", LinkHints.hintMarkers[1].hintString);
- assert.equal("", LinkHints.hintMarkers[1].style.display);
- LinkHints.onKeyDownInMode(mockKeyboardEvent("A"));
- assert.equal("2", LinkHints.hintMarkers[3].hintString);
- })
-
- ),
-
- context("Image hints",
-
- setup(function() {
- var testContent =
- "<a><img alt='alt text'/></a>" +
- "<a><img alt='alt text' title='some title'/></a>" +
- "<a><img title='some title'/></a>" +
- "<a><img src='' width='320px' height='100px'/></a>";
- document.getElementById("test-div").innerHTML = testContent;
- LinkHints.activateMode();
- }),
-
- tearDown(function() {
- document.getElementById("test-div").innerHTML = "";
- LinkHints.deactivateMode();
- }),
-
- should("label the images", function() {
- assert.equal("1: alt text", LinkHints.hintMarkers[0].textContent.toLowerCase());
- assert.equal("2: alt text", LinkHints.hintMarkers[1].textContent.toLowerCase());
- assert.equal("3: some title", LinkHints.hintMarkers[2].textContent.toLowerCase());
- assert.equal("4", LinkHints.hintMarkers[3].textContent.toLowerCase());
- })
-
- ),
-
- context("Input hints",
-
- setup(function() {
- var testContent =
- "<input type='text' value='some value'/>" +
- "<input type='password' value='some value'/>" +
- "<textarea>some text</textarea>" +
- "<label for='test-input'/>a label</label><input type='text' id='test-input' value='some value'/>" +
- "<label for='test-input-2'/>a label: </label><input type='text' id='test-input-2' value='some value'/>";
- document.getElementById("test-div").innerHTML = testContent;
- LinkHints.activateMode();
- }),
-
- tearDown(function() {
- document.getElementById("test-div").innerHTML = "";
- LinkHints.deactivateMode();
- }),
-
- should("label the input elements", function() {
- assert.equal("1", LinkHints.hintMarkers[0].textContent.toLowerCase());
- assert.equal("2", LinkHints.hintMarkers[1].textContent.toLowerCase());
- assert.equal("3", LinkHints.hintMarkers[2].textContent.toLowerCase());
- assert.equal("4: a label", LinkHints.hintMarkers[3].textContent.toLowerCase());
- assert.equal("5: a label", LinkHints.hintMarkers[4].textContent.toLowerCase());
- })
-
- ),
-
- context("Input focus",
-
- setup(function() {
- var testContent =
- "<input type='text' id='first'/>" +
- "<input style='display:none;' id='second'/>" +
- "<input type='password' id='third' value='some value'/>";
- document.getElementById("test-div").innerHTML = testContent;
- }),
-
- tearDown(function() {
- document.getElementById("test-div").innerHTML = "";
- }),
-
- should("focus the right element", function() {
- focusInput(1);
- assert.equal('first', document.activeElement.id);
- focusInput(100);
- assert.equal('third', document.activeElement.id);
- })
- )
-
- );
-
- context("Input focus",
-
- setup(function() {
- var testContent =
- "<input type='text' id='first'/>" +
- "<input style='display:none;' id='second'/>" +
- "<input type='password' id='third' value='some value'/>";
- document.getElementById("test-div").innerHTML = testContent;
- }),
-
- tearDown(function() {
- document.getElementById("test-div").innerHTML = "";
- }),
-
- should("focus the right element", function() {
- focusInput(1);
- assert.equal('first', document.activeElement.id);
- focusInput(100);
- assert.equal('third', document.activeElement.id);
- })
-
- );
-
- Tests.outputMethod = function(output) {
- var newOutput = Array.prototype.join.call(arguments, "\n");
- newOutput = newOutput.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"); // escape html
- // highlight the source of the error
- newOutput = newOutput.replace(/\/([^:/]+):([0-9]+):([0-9]+)/,
- "/<span class='errorPosition'>$1:$2</span>:$3");
- document.getElementById("output-div").innerHTML +=
- "<div class='output-section'>" + newOutput + "</div>";
- console.log.apply(console, arguments);
- }
-
- // ensure the extension has time to load before commencing the tests
- document.addEventListener("DOMContentLoaded", function() {
- setTimeout(Tests.run, 200);
- });
-
- function createLinks(n) {
- for (var i = 0; i < n; i++) {
- var link = document.createElement("a");
- link.textContent = "test";
- document.getElementById("test-div").appendChild(link);
- }
- }
- </script>
- </head>
- <body>
- <!-- should always be the first element on the page -->
- <div id="test-div"></div>
-
- <h1>Vimium Tests</h1>
-
- <div id="output-div"></div>
-
- </body>
-</html>
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 = "<a>test</a>" + "<a>tress</a>"
+ 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 = "<a>test</a>" + "<a>tress</a>" + "<a>trait</a>" + "<a>track<img alt='alt text'/></a>"
+ 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 = "<a><img alt='alt text'/></a>" + "<a><img alt='alt text' title='some title'/></a>" + "<a><img title='some title'/></a>" + "<a><img src='' width='320px' height='100px'/></a>"
+ 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 = "<input type='text' value='some value'/>" + "<input type='password' value='some value'/>" + "<textarea>some text</textarea>" + "<label for='test-input'/>a label</label><input type='text' id='test-input' value='some value'/>" + "<label for='test-input-2'/>a label: </label><input type='text' id='test-input-2' value='some value'/>"
+ 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 = "<input type='text' id='first'/>" + "<input style='display:none;' id='second'/>" + "<input type='password' id='third' value='some value'/>"
+ 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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
+ # highlight the source of the error
+ newOutput = newOutput.replace(/\/([^:/]+):([0-9]+):([0-9]+)/, "/<span class='errorPosition'>$1:$2</span>:$3")
+ document.getElementById("output-div").innerHTML += "<div class='output-section'>" + newOutput + "</div>"
+ 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <style type="text/css">
+ body {
+ font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
+ width: 800px;
+ margin: 0px auto;
+ }
+ #output-div {
+ white-space: pre-wrap;
+ background-color: #eee;
+ font-family: monospace;
+ margin: 0 0 50px 0;
+ border-style: dashed;
+ border-width: 1px 1px 0 1px;
+ border-color: #999;
+ }
+ .errorPosition {
+ color: #f33;
+ font-weight: bold;
+ }
+ .output-section {
+ padding: 10px 15px 10px 15px;
+ border-bottom: dashed 1px #999;
+ }
+ </style>
+ <link rel="stylesheet" type="text/css" href="../../vimium.css" />
+ <script type="text/javascript" src="../../lib/utils.js"></script>
+ <script type="text/javascript" src="../../lib/keyboard_utils.js"></script>
+ <script type="text/javascript" src="../../lib/dom_utils.js"></script>
+ <script type="text/javascript" src="../../lib/clipboard.js"></script>
+ <script type="text/javascript" src="../../content_scripts/link_hints.js"></script>
+ <script type="text/javascript" src="../../content_scripts/vomnibar.js"></script>
+ <script type="text/javascript" src="../../content_scripts/vimium_frontend.js"></script>
+ <script type="text/javascript" src="../../tests/shoulda.js/shoulda.js"></script>
+ <script type="text/javascript" src="automated.js"></script>
+ </head>
+ <body>
+ <!-- should always be the first element on the page -->
+ <div id="test-div"></div>
+
+ <h1>Vimium Tests</h1>
+
+ <div id="output-div"></div>
+
+ </body>
+</html>