aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/dom_tests/bind.js27
-rw-r--r--tests/dom_tests/chrome.coffee20
-rw-r--r--tests/dom_tests/dom_tests.coffee200
-rw-r--r--tests/dom_tests/dom_tests.html51
-rw-r--r--tests/dom_tests/phantom_runner.coffee32
-rw-r--r--tests/unit_tests/completion_test.coffee (renamed from tests/completion_test.coffee)4
-rw-r--r--tests/unit_tests/test_helper.coffee (renamed from tests/test_helper.coffee)4
-rw-r--r--tests/unit_tests/utils_test.coffee (renamed from tests/utils_test.coffee)2
8 files changed, 335 insertions, 5 deletions
diff --git a/tests/dom_tests/bind.js b/tests/dom_tests/bind.js
new file mode 100644
index 00000000..833f8006
--- /dev/null
+++ b/tests/dom_tests/bind.js
@@ -0,0 +1,27 @@
+/*
+ * Polyfill taken from https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
+ * Necessary because the current version of PhantomJS doesn't yet support bind().
+ */
+if (!Function.prototype.bind) {
+ Function.prototype.bind = function (oThis) {
+ if (typeof this !== "function") {
+ // closest thing possible to the ECMAScript 5 internal IsCallable function
+ throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
+ }
+
+ var aArgs = Array.prototype.slice.call(arguments, 1),
+ fToBind = this,
+ fNOP = function () {},
+ fBound = function () {
+ return fToBind.apply(this instanceof fNOP && oThis
+ ? this
+ : oThis,
+ aArgs.concat(Array.prototype.slice.call(arguments)));
+ };
+
+ fNOP.prototype = this.prototype;
+ fBound.prototype = new fNOP();
+
+ return fBound;
+ };
+}
diff --git a/tests/dom_tests/chrome.coffee b/tests/dom_tests/chrome.coffee
new file mode 100644
index 00000000..ff7a53d0
--- /dev/null
+++ b/tests/dom_tests/chrome.coffee
@@ -0,0 +1,20 @@
+#
+# Mock the Chrome extension API.
+#
+
+root = exports ? window
+
+root.chrome = {
+ extension: {
+ connect: -> {
+ onMessage: {
+ addListener: ->
+ }
+ postMessage: ->
+ }
+ onRequest: {
+ addListener: ->
+ }
+ sendRequest: ->
+ }
+}
diff --git a/tests/dom_tests/dom_tests.coffee b/tests/dom_tests/dom_tests.coffee
new file mode 100644
index 00000000..f4e63270
--- /dev/null
+++ b/tests/dom_tests/dom_tests.coffee
@@ -0,0 +1,200 @@
+#
+# 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
+ stub settings.values, "linkHintCharacters", "ab"
+
+ 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
+
+# PhantomJS will call the tests manually
+unless navigator.userAgent == 'phantom'
+ # ensure the extension has time to load before commencing the tests
+ document.addEventListener "DOMContentLoaded", ->
+ setTimeout Tests.run, 200
+
+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/tests/dom_tests/dom_tests.html b/tests/dom_tests/dom_tests.html
new file mode 100644
index 00000000..1dc45782
--- /dev/null
+++ b/tests/dom_tests/dom_tests.html
@@ -0,0 +1,51 @@
+<!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="bind.js"></script>
+ <script type="text/javascript" src="chrome.js"></script>
+ <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="../shoulda.js/shoulda.js"></script>
+ <script type="text/javascript" src="dom_tests.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>
diff --git a/tests/dom_tests/phantom_runner.coffee b/tests/dom_tests/phantom_runner.coffee
new file mode 100644
index 00000000..f0f2b128
--- /dev/null
+++ b/tests/dom_tests/phantom_runner.coffee
@@ -0,0 +1,32 @@
+page = require('webpage').create()
+
+page.settings.userAgent = 'phantom'
+
+# ensure that the elements we test the link hints on are actually visible
+page.viewportSize =
+ width: 900
+ height: 600
+
+page.onConsoleMessage = (msg) ->
+ console.log msg
+
+system = require 'system'
+fs = require 'fs'
+
+pathParts = system.args[0].split(fs.separator)
+pathParts[pathParts.length - 1] = ''
+dirname = pathParts.join(fs.separator)
+
+page.open dirname + 'dom_tests.html', (status) ->
+ if status != 'success'
+ console.log 'Unable to load tests.'
+ phantom.exit 1
+
+ testsFailed = page.evaluate ->
+ Tests.run()
+ return Tests.testsFailed
+
+ if testsFailed > 0
+ phantom.exit 1
+ else
+ phantom.exit 0
diff --git a/tests/completion_test.coffee b/tests/unit_tests/completion_test.coffee
index 7094d720..d3369398 100644
--- a/tests/completion_test.coffee
+++ b/tests/unit_tests/completion_test.coffee
@@ -1,6 +1,6 @@
require "./test_helper.js"
-extend(global, require "../lib/utils.js")
-extend(global, require "../background_scripts/completion.js")
+extend(global, require "../../lib/utils.js")
+extend(global, require "../../background_scripts/completion.js")
global.chrome = {}
diff --git a/tests/test_helper.coffee b/tests/unit_tests/test_helper.coffee
index 237f8e24..bb73bf54 100644
--- a/tests/test_helper.coffee
+++ b/tests/unit_tests/test_helper.coffee
@@ -1,5 +1,5 @@
-require("./shoulda.js/shoulda.js")
+require("../shoulda.js/shoulda.js")
global.extend = (hash1, hash2) ->
for key of hash2
hash1[key] = hash2[key]
- hash1 \ No newline at end of file
+ hash1
diff --git a/tests/utils_test.coffee b/tests/unit_tests/utils_test.coffee
index c5e5d002..6a44b460 100644
--- a/tests/utils_test.coffee
+++ b/tests/unit_tests/utils_test.coffee
@@ -1,5 +1,5 @@
require "./test_helper.js"
-extend(global, require "../lib/utils.js")
+extend(global, require "../../lib/utils.js")
context "convertToUrl",
should "detect and clean up valid URLs", ->