diff options
| author | Stephen Blott | 2015-01-11 07:15:20 +0000 | 
|---|---|---|
| committer | Stephen Blott | 2015-01-11 10:14:38 +0000 | 
| commit | e8f10007f1528808f72be6fac829cc55309527f2 (patch) | |
| tree | 2311d31a869cb2b7bf32c857b0728eae1eb19589 | |
| parent | d65075a3b66fae93a10b849162fa907d0eb99846 (diff) | |
| download | vimium-e8f10007f1528808f72be6fac829cc55309527f2.tar.bz2 | |
Modes; add DOM tests.
| -rw-r--r-- | content_scripts/mode.coffee | 4 | ||||
| -rw-r--r-- | lib/handler_stack.coffee | 8 | ||||
| -rw-r--r-- | tests/dom_tests/dom_tests.coffee | 309 | 
3 files changed, 294 insertions, 27 deletions
| diff --git a/content_scripts/mode.coffee b/content_scripts/mode.coffee index 46f5c3b7..6e40089e 100644 --- a/content_scripts/mode.coffee +++ b/content_scripts/mode.coffee @@ -44,7 +44,7 @@ count = 0  class Mode    # If Mode.debug is true, then we generate a trace of modes being activated and deactivated on the console, along    # with a list of the currently active modes. -  debug: false +  debug: true    @modes: []    # Constants; short, readable names for handlerStack event-handler return values. @@ -121,7 +121,7 @@ class Mode          keypress: (event) =>            @alwaysContinueBubbling =>              if event.srcElement == @options.suppressPrintableEvents -              if KeyboardUtils.isPrintable(event) +              if KeyboardUtils.isPrintable event                  event.vimium_suppress_event = true      Mode.updateBadge() if @badge diff --git a/lib/handler_stack.coffee b/lib/handler_stack.coffee index c21ba8a8..b4cacf74 100644 --- a/lib/handler_stack.coffee +++ b/lib/handler_stack.coffee @@ -102,13 +102,5 @@ class HandlerStack      line = args.join " "      console.log line -  # Used by tests to get a duplicate copy of the initialized handler stack. -  duplicate: -> -    dup = new HandlerStack() -    dup.stack = @stack[..] -    for prop in [ "stopBubblingAndTrue", "stopBubblingAndFalse", "restartBubbling" ] -      dup[prop] = @[prop] -    dup -  root.HandlerStack = HandlerStack  root.handlerStack = new HandlerStack() diff --git a/tests/dom_tests/dom_tests.coffee b/tests/dom_tests/dom_tests.coffee index ce54190a..c9fab56b 100644 --- a/tests/dom_tests/dom_tests.coffee +++ b/tests/dom_tests/dom_tests.coffee @@ -12,10 +12,16 @@ mockKeyboardEvent = (keyChar) ->    event.preventDefault = (event) -> @suppressed = true    event -# Some of these tests have side effects on the handler stack.  Therefore, we take backups of the stack, and -# restore them later. -backupHandlerStack = -> handlerStack.backup = handlerStack.stack -restoreHandlerStack = -> handlerStack.stack = handlerStack.backup +# Some of these tests have side effects on the handler stack and mode.  Therefore, we take backups and restore +# them later. +backupStackState = -> +  Mode.backup = Mode.modes[..] +  handlerStack.backup = handlerStack.stack[..] +restoreStackState = -> +  for mode in Mode.modes +    mode.exit() unless mode in Mode.backup +  Mode.modes = Mode.backup +  handlerStack.stack = handlerStack.backup  #  # Retrieve the hint markers as an array object. @@ -175,11 +181,11 @@ context "Input focus",      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 -    backupHandlerStack() +    backupStackState()    tearDown ->      document.getElementById("test-div").innerHTML = "" -    restoreHandlerStack() +    restoreStackState()    should "focus the right element", ->      focusInput 1 @@ -258,13 +264,13 @@ createLinks = (n) ->  context "Normal mode",    setup -> -    backupHandlerStack() +    backupStackState()      refreshCompletionKeys        completionKeys: "o"        validFirstKeys: "o"    tearDown -> -    restoreHandlerStack() +    restoreStackState()    should "suppress mapped keys", ->      for event in [ "keydown", "keypress", "keyup" ] @@ -280,7 +286,7 @@ context "Normal mode",  context "Passkeys mode",    setup -> -    backupHandlerStack() +    backupStackState()      refreshCompletionKeys        completionKeys: "oj"        validFirstKeys: "oj" @@ -290,7 +296,7 @@ context "Passkeys mode",        passKeys: "j"    tearDown -> -    restoreHandlerStack() +    restoreStackState()      handlerStack.bubbleEvent "registerStateChange",        enabled: true        passKeys: "" @@ -310,13 +316,13 @@ context "Passkeys mode",  context "Insert mode",    setup -> -    backupHandlerStack() +    backupStackState()      refreshCompletionKeys        completionKeys: "o"        validFirstKeys: "o"    tearDown -> -    backupHandlerStack() +    backupStackState()    should "not suppress mapped keys in insert mode", ->      # First check normal-mode key (just to verify the framework). @@ -336,21 +342,290 @@ context "Insert mode",      insertMode.exit() -    # Then check insert mode has been successfully removed. +    # Then verify that insert mode has been successfully removed.      for event in [ "keydown", "keypress", "keyup" ]        key = mockKeyboardEvent "o"        handlerStack.bubbleEvent event, key        assert.isTrue key.suppressed -context "Insert mode trigger", +context "Insert-mode trigger",    setup -> -    backupHandlerStack() +    backupStackState()      refreshCompletionKeys        completionKeys: "o"        validFirstKeys: "o" +    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 -> +    restoreStackState() +    document.getElementById("test-div").innerHTML = "" + +  should "trigger insert mode on focus of contentEditable elements", -> +    handlerStack.bubbleEvent "focus", +      target: +        isContentEditable: true + +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "insert" + +  should "trigger insert mode on focus of text input", -> +    document.getElementById("first").focus() +    handlerStack.bubbleEvent "focus", { target: document.activeElement } + +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "insert" + +  should "trigger insert mode on focus of password input", -> +    document.getElementById("third").focus() +    handlerStack.bubbleEvent "focus", { target: document.activeElement } + +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "insert" + +  should "not trigger insert mode on focus of contentEditable elements", -> +    new InsertModeBlocker() +    handlerStack.bubbleEvent "focus", +      target: +        isContentEditable: true + +    assert.isTrue Mode.modes[Mode.modes.length-1].name != "insert" + +  should "not trigger insert mode on focus of text input", -> +    new InsertModeBlocker() +    document.getElementById("first").focus() +    handlerStack.bubbleEvent "focus", { target: document.activeElement } + +    assert.isTrue Mode.modes[Mode.modes.length-1].name != "insert" + +  should "not trigger insert mode on focus of password input", -> +    new InsertModeBlocker() +    document.getElementById("third").focus() +    handlerStack.bubbleEvent "focus", { target: document.activeElement } + +    assert.isTrue Mode.modes[Mode.modes.length-1].name != "insert" + +context "Mode utilities", +  setup -> +    backupStackState() +    refreshCompletionKeys +      completionKeys: "o" +      validFirstKeys: "o" + +    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 -> -    backupHandlerStack() +    restoreStackState() +    document.getElementById("test-div").innerHTML = "" + +  should "not have duplicate singletons", -> +    count = 0 + +    class Test extends Mode +      constructor: -> +        count += 1 +        super +          singleton: Test + +      exit: -> +        count -= 1 +        super() + +    assert.isTrue count == 0 +    new Test() +    assert.isTrue count == 1 +    new Test() +    assert.isTrue count == 1 + +  should "exit on escape", -> +    escape = +      keyCode: 27 + +    new Mode +      exitOnEscape: true +      name: "test" + +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "test" +    handlerStack.bubbleEvent "keydown", escape +    assert.isTrue Mode.modes[Mode.modes.length-1].name != "test" + +  should "exit on blur", -> +    element = document.getElementById("first") + +    new Mode +      exitOnBlur: element +      name: "test" + +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "test" +    handlerStack.bubbleEvent "blur", { srcElement: element } +    assert.isTrue Mode.modes[Mode.modes.length-1].name != "test" + +  should "register state change", -> +    enabled = null +    passKeys = null + +    class Test extends Mode +      constructor: -> +        super +          trackState: true + +      registerStateChange: -> +        enabled = @enabled +        passKeys = @passKeys + +    new Test() +    handlerStack.bubbleEvent "registerStateChange", +      enabled: "enabled" +      passKeys: "passKeys" +    assert.isTrue enabled == "enabled" +    assert.isTrue passKeys == "passKeys" + +  should "suppress printable keys", -> +    element = document.getElementById("first") + +    # Verify key is always passed through. +    for event in [ "keydown", "keypress", "keyup" ] +      key = mockKeyboardEvent "A" +      handlerStack.bubbleEvent event, key +      assert.isFalse key.suppressed + +    new Mode +      suppressPrintableEvents: element + +    # Verify key is now suppressed for keypress. +    key = mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keypress", +      extend key, +         srcElement: element +    assert.isTrue key.suppressed + +    # Verify key is not suppressed with Control key. +    key = mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keypress", +      extend key, +         srcElement: element +         ctrlKey: true +    assert.isFalse key.suppressed + +    # Verify key is not suppressed with Meta key. +    key = mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keypress", +      extend key, +         srcElement: element +         metaKey: true +    assert.isFalse key.suppressed + +    # Verify other keyboard events are not suppressed. +    key = mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keydown", +      extend key, +         srcElement: element +    assert.isFalse key.suppressed + +context "PostFindMode", +  setup -> +    backupStackState() +    refreshCompletionKeys +      completionKeys: "o" +      validFirstKeys: "o" + +    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 -> +    restoreStackState() +    document.getElementById("test-div").innerHTML = "" + +  should "be a singleton", -> +    element = document.getElementById("first") +    element.focus() +    count = 0 + +    class Test extends PostFindMode +      constructor: (element) -> +        count += 1 +        super element + +      exit: -> +        count -= 1 +        super() + +    assert.isTrue count == 0 +    new Test element +    assert.isTrue count == 1 +    new Test element +    assert.isTrue count == 1 + +  should "suppress unmapped printable keypress events", -> +    element = document.getElementById("first") +    element.focus() + +    # Verify key is passed through. +    for event in [ "keydown", "keypress", "keyup" ] +      key = mockKeyboardEvent "A" +      handlerStack.bubbleEvent event, key +      assert.isFalse key.suppressed -  should "trigger insert mode on input-focus events", -> +    new PostFindMode element + +    # Verify key is now suppressed for keypress. +    key = mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keypress", +      extend key, +         srcElement: element +    assert.isTrue key.suppressed + +    # Verify other keyboard events are not suppressed. +    key = mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keydown", +      extend key, +         srcElement: element +    assert.isFalse key.suppressed + +    # Verify keyboard events on other elements are not suppressed. +    key = mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keypress", +      extend key, +         srcElement: document.body +    assert.isFalse key.suppressed + +  should "be clickable to focus", -> +    element = document.getElementById("first") +    element.focus() + +    new PostFindMode element + +    assert.isTrue Mode.modes[Mode.modes.length-1].name != "insert" +    handlerStack.bubbleEvent "click", { target: document.activeElement } +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "insert" + +  should "enter insert mode on immediate escape", -> +    escape = +      keyCode: 27 +    element = document.getElementById("first") +    element.focus() + +    new PostFindMode element +    assert.isTrue Mode.modes[Mode.modes.length-1].name != "insert" +    handlerStack.bubbleEvent "keydown", escape +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "insert" + +  should "enter not insert mode on subsequent escape", -> +    escape = +      keyCode: 27 +      keyIdentifier: "" +      stopImmediatePropagation: -> +    element = document.getElementById("first") +    element.focus() + +    new PostFindMode element +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "post-find" +    handlerStack.bubbleEvent "keydown", mockKeyboardEvent "A" +    handlerStack.bubbleEvent "keydown", escape +    assert.isTrue Mode.modes[Mode.modes.length-1].name == "post-find" | 
