text: // Copyright 2010 The Closure Library Authors. All Rights Reserved.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS-IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  goog.provide('goog.ui.editor.LinkDialogTest');
  goog.setTestOnly('goog.ui.editor.LinkDialogTest');
  
  goog.require('goog.dom');
  goog.require('goog.dom.DomHelper');
  goog.require('goog.dom.TagName');
  goog.require('goog.editor.BrowserFeature');
  goog.require('goog.editor.Link');
  goog.require('goog.events');
  goog.require('goog.events.Event');
  goog.require('goog.events.EventHandler');
  goog.require('goog.events.InputHandler');
  goog.require('goog.style');
  goog.require('goog.testing.MockControl');
  goog.require('goog.testing.PropertyReplacer');
  goog.require('goog.testing.dom');
  goog.require('goog.testing.events');
  goog.require('goog.testing.jsunit');
  goog.require('goog.testing.mockmatchers');
  goog.require('goog.testing.mockmatchers.ArgumentMatcher');
  goog.require('goog.ui.editor.AbstractDialog');
  goog.require('goog.ui.editor.LinkDialog');
  goog.require('goog.ui.editor.messages');
  goog.require('goog.userAgent');
  
  var dialog;
  var mockCtrl;
  var mockLink;
  var mockOkHandler;
  var mockGetViewportSize;
  var mockWindowOpen;
  var isNew;
  var anchorElem;
  var stubs = new goog.testing.PropertyReplacer();
  
  var ANCHOR_TEXT = 'anchor text';
  var ANCHOR_URL = 'http://www.google.com/';
  var ANCHOR_EMAIL = 'm@r.cos';
  var ANCHOR_MAILTO = 'mailto:' + ANCHOR_EMAIL;
  
  function setUp() {
    anchorElem = goog.dom.createElement(goog.dom.TagName.A);
    goog.dom.appendChild(goog.dom.getDocument().body, anchorElem);
  
    mockCtrl = new goog.testing.MockControl();
    mockLink = mockCtrl.createLooseMock(goog.editor.Link);
    mockOkHandler = mockCtrl.createLooseMock(goog.events.EventHandler);
  
    isNew = false;
    mockLink.isNew();
    mockLink.$anyTimes();
    mockLink.$does(function() {
      return isNew;
    });
    mockLink.getCurrentText();
    mockLink.$anyTimes();
    mockLink.$does(function() {
      return anchorElem.innerHTML;
    });
    mockLink.setTextAndUrl(goog.testing.mockmatchers.isString,
        goog.testing.mockmatchers.isString);
    mockLink.$anyTimes();
    mockLink.$does(function(text, url) {
      anchorElem.innerHTML = text;
      anchorElem.href = url;
    });
    mockLink.$registerArgumentListVerifier('placeCursorRightOf', function() {
      return true;
    });
    mockLink.placeCursorRightOf(goog.testing.mockmatchers.iBoolean);
    mockLink.$anyTimes();
    mockLink.getAnchor();
    mockLink.$anyTimes();
    mockLink.$returns(anchorElem);
  
    mockWindowOpen = mockCtrl.createFunctionMock('open');
    stubs.set(window, 'open', mockWindowOpen);
  }
  
  function tearDown() {
    dialog.dispose();
    goog.dom.removeNode(anchorElem);
    stubs.reset();
  }
  
  function setUpAnchor(href, text, opt_isNew, opt_target, opt_rel) {
    anchorElem.href = href;
    anchorElem.innerHTML = text;
    isNew = !!opt_isNew;
    if (opt_target) {
      anchorElem.target = opt_target;
    }
    if (opt_rel) {
      anchorElem.rel = opt_rel;
    }
  }
  
  
  /**
   * Creates and shows the dialog to be tested.
   * @param {Document=} opt_document Document to render the dialog into.
   *     Defaults to the main window's document.
   * @param {boolean=} opt_openInNewWindow Whether the open in new window
   *     checkbox should be shown.
   * @param {boolean=} opt_noFollow Whether rel=nofollow checkbox should be
   *     shown.
   */
  function createAndShow(opt_document, opt_openInNewWindow, opt_noFollow) {
    dialog = new goog.ui.editor.LinkDialog(new goog.dom.DomHelper(opt_document),
                                           mockLink);
    if (opt_openInNewWindow) {
      dialog.showOpenLinkInNewWindow(false);
    }
    if (opt_noFollow) {
      dialog.showRelNoFollow();
    }
    dialog.addEventListener(goog.ui.editor.AbstractDialog.EventType.OK,
        mockOkHandler);
    dialog.show();
  }
  
  
  /**
   * Sets up the mock event handler to expect an OK event with the given text
   * and url.
   */
  function expectOk(linkText, linkUrl, opt_openInNewWindow, opt_noFollow) {
    mockOkHandler.handleEvent(new goog.testing.mockmatchers.ArgumentMatcher(
        function(arg) {
          return arg.type == goog.ui.editor.AbstractDialog.EventType.OK &&
                 arg.linkText == linkText &&
                 arg.linkUrl == linkUrl &&
                 arg.openInNewWindow == !!opt_openInNewWindow &&
                 arg.noFollow == !!opt_noFollow;
        },
        '{linkText: ' + linkText + ', linkUrl: ' + linkUrl +
            ', openInNewWindow: ' + opt_openInNewWindow +
            ', noFollow: ' + opt_noFollow + '}'));
  }
  
  
  /**
   * Return true if we should use active element in our tests.
   * @return {boolean} .
   */
  function useActiveElement() {
    return goog.editor.BrowserFeature.HAS_ACTIVE_ELEMENT ||
        goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher(9);
  }
  
  
  /**
   * Tests that when you show the dialog for a new link, you can switch
   * to the URL view.
   * @param {Document=} opt_document Document to render the dialog into.
   *     Defaults to the main window's document.
   */
  function testShowNewLinkSwitchToUrl(opt_document) {
    mockCtrl.$replayAll();
    setUpAnchor('', '', true); // Must be done before creating the dialog.
    createAndShow(opt_document);
  
    var webRadio = dialog.dom.getElement(
        goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB).firstChild;
    var emailRadio = dialog.dom.getElement(
        goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB).firstChild;
    assertTrue('Web Radio Button selected', webRadio.checked);
    assertFalse('Email Radio Button selected', emailRadio.checked);
    if (useActiveElement()) {
      assertEquals('Focus should be on url input',
          getUrlInput(),
          dialog.dom.getActiveElement());
    }
  
    emailRadio.click();
    assertFalse('Web Radio Button selected', webRadio.checked);
    assertTrue('Email Radio Button selected', emailRadio.checked);
    if (useActiveElement()) {
      assertEquals('Focus should be on url input',
          getEmailInput(),
          dialog.dom.getActiveElement());
    }
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Tests that when you show the dialog for a new link, the input fields are
   * empty, the web tab is selected and focus is in the url input field.
   * @param {Document=} opt_document Document to render the dialog into.
   *     Defaults to the main window's document.
   */
  function testShowForNewLink(opt_document) {
    mockCtrl.$replayAll();
    setUpAnchor('', '', true); // Must be done before creating the dialog.
    createAndShow(opt_document);
  
    assertEquals('Display text input field should be empty',
                 '',
                 getDisplayInputText());
    assertEquals('Url input field should be empty',
                 '',
                 getUrlInputText());
    assertEquals('On the web tab should be selected',
                 goog.ui.editor.LinkDialog.Id_.ON_WEB,
                 dialog.curTabId_);
    if (useActiveElement()) {
      assertEquals('Focus should be on url input',
                   getUrlInput(),
                   dialog.dom.getActiveElement());
    }
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Fakes that the mock field is using an iframe and does the same test as
   * testShowForNewLink().
   */
  function testShowForNewLinkWithDiffAppWindow() {
    testShowForNewLink(goog.dom.getElement('appWindowIframe').contentDocument);
  }
  
  
  /**
   * Tests that when you show the dialog for a url link, the input fields are
   * filled in, the web tab is selected and focus is in the url input field.
   */
  function testShowForUrlLink() {
    mockCtrl.$replayAll();
    setUpAnchor(ANCHOR_URL, ANCHOR_TEXT);
    createAndShow();
  
    assertEquals('Display text input field should be filled in',
                 ANCHOR_TEXT,
                 getDisplayInputText());
    assertEquals('Url input field should be filled in',
                 ANCHOR_URL,
                 getUrlInputText());
    assertEquals('On the web tab should be selected',
                 goog.ui.editor.LinkDialog.Id_.ON_WEB,
                 dialog.curTabId_);
    if (useActiveElement()) {
      assertEquals('Focus should be on url input',
                   getUrlInput(),
                   dialog.dom.getActiveElement());
    }
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Tests that when you show the dialog for a mailto link, the input fields are
   * filled in, the email tab is selected and focus is in the email input field.
   */
  function testShowForMailtoLink() {
    mockCtrl.$replayAll();
    setUpAnchor(ANCHOR_MAILTO, ANCHOR_TEXT);
    createAndShow();
  
    assertEquals('Display text input field should be filled in',
                 ANCHOR_TEXT,
                 getDisplayInputText());
    assertEquals('Email input field should be filled in',
                 ANCHOR_EMAIL, // The 'mailto:' is not in the input!
                 getEmailInputText());
    assertEquals('Email tab should be selected',
                 goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS,
                 dialog.curTabId_);
    if (useActiveElement()) {
      assertEquals('Focus should be on email input',
                   getEmailInput(),
                   dialog.dom.getActiveElement());
    }
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Tests that the display text is autogenerated from the url input in the
   * right situations (and not generated when appropriate too).
   */
  function testAutogeneration() {
    mockCtrl.$replayAll();
    setUpAnchor('', '', true);
    createAndShow();
  
    // Simulate typing a url when everything is empty, should autogen.
    setUrlInputText(ANCHOR_URL);
    assertEquals('Display text should have been autogenerated',
                 ANCHOR_URL,
                 getDisplayInputText());
  
    // Simulate typing text when url is set, afterwards should not autogen.
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_MAILTO);
    assertNotEquals('Display text should not have been autogenerated',
                    ANCHOR_MAILTO,
                    getDisplayInputText());
    assertEquals('Display text should have remained the same',
                 ANCHOR_TEXT,
                 getDisplayInputText());
  
    // Simulate typing text equal to existing url, afterwards should autogen.
    setDisplayInputText(ANCHOR_MAILTO);
    setUrlInputText(ANCHOR_URL);
    assertEquals('Display text should have been autogenerated',
                 ANCHOR_URL,
                 getDisplayInputText());
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Tests that the display text is not autogenerated from the url input in all
   * situations when the autogeneration feature is turned off.
   */
  function testAutogenerationOff() {
    mockCtrl.$replayAll();
  
    setUpAnchor('', '', true);
    createAndShow();
  
    // Disable the autogen feature
    dialog.setAutogenFeatureEnabled(false);
  
    // Simulate typing a url when everything is empty, should not autogen.
    setUrlInputText(ANCHOR_URL);
    assertEquals('Display text should not have been autogenerated',
                 '',
                 getDisplayInputText());
  
    // Simulate typing text when url is set, afterwards should not autogen.
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_MAILTO);
    assertNotEquals('Display text should not have been autogenerated',
                    ANCHOR_MAILTO,
                    getDisplayInputText());
    assertEquals('Display text should have remained the same',
                 ANCHOR_TEXT,
                 getDisplayInputText());
  
    // Simulate typing text equal to existing url, afterwards should not
    // autogen.
    setDisplayInputText(ANCHOR_MAILTO);
    setUrlInputText(ANCHOR_URL);
    assertEquals('Display text should not have been autogenerated',
                 ANCHOR_MAILTO,
                 getDisplayInputText());
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Tests that clicking OK with the url tab selected dispatches an event with
   * the proper link data.
   */
  function testOkForUrl() {
    expectOk(ANCHOR_TEXT, ANCHOR_URL);
    mockCtrl.$replayAll();
    setUpAnchor('', '', true);
    createAndShow();
  
    dialog.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB);
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_URL);
    goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Tests that clicking OK with the url tab selected but with an email address
   * in the url field dispatches an event with the proper link data.
   */
  function testOkForUrlWithEmail() {
    expectOk(ANCHOR_TEXT, ANCHOR_MAILTO);
    mockCtrl.$replayAll();
    setUpAnchor('', '', true);
    createAndShow();
  
    dialog.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB);
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_EMAIL);
    goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Tests that clicking OK with the email tab selected dispatches an event with
   * the proper link data.
   */
  function testOkForEmail() {
    expectOk(ANCHOR_TEXT, ANCHOR_MAILTO);
    mockCtrl.$replayAll();
    setUpAnchor('', '', true);
    createAndShow();
  
    dialog.tabPane_.setSelectedTabId(
        goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_TAB);
  
    setDisplayInputText(ANCHOR_TEXT);
    setEmailInputText(ANCHOR_EMAIL);
    goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
  
    mockCtrl.$verifyAll();
  }
  
  function testOpenLinkInNewWindowNewLink() {
    expectOk(ANCHOR_TEXT, ANCHOR_URL, true);
    expectOk(ANCHOR_TEXT, ANCHOR_URL, false);
    mockCtrl.$replayAll();
  
    setUpAnchor('', '', true);
    createAndShow(undefined, true);
    dialog.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB);
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_URL);
  
    assertFalse('"Open in new window" should start unchecked',
        getOpenInNewWindowCheckboxChecked());
    setOpenInNewWindowCheckboxChecked(true);
    assertTrue('"Open in new window" should have gotten checked',
        getOpenInNewWindowCheckboxChecked());
    goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
  
    // Reopen same dialog
    dialog.show();
    dialog.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB);
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_URL);
  
    assertTrue('"Open in new window" should remember it was checked',
        getOpenInNewWindowCheckboxChecked());
    setOpenInNewWindowCheckboxChecked(false);
    assertFalse('"Open in new window" should have gotten unchecked',
        getOpenInNewWindowCheckboxChecked());
    goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
  }
  
  function testOpenLinkInNewWindowExistingLink() {
    mockCtrl.$replayAll();
  
    // Edit an existing link that already opens in a new window.
    setUpAnchor('', '', false, '_blank');
    createAndShow(undefined, true);
    dialog.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB);
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_URL);
  
    assertTrue('"Open in new window" should start checked for existing link',
        getOpenInNewWindowCheckboxChecked());
  
    mockCtrl.$verifyAll();
  }
  
  function testRelNoFollowNewLink() {
    expectOk(ANCHOR_TEXT, ANCHOR_URL, null, true);
    expectOk(ANCHOR_TEXT, ANCHOR_URL, null, false);
    mockCtrl.$replayAll();
  
    setUpAnchor('', '', true, true);
    createAndShow(null, null, true);
    dialog.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB);
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_URL);
    assertFalse('rel=nofollow should start unchecked',
        dialog.relNoFollowCheckbox_.checked);
  
    // Check rel=nofollow and close the dialog.
    dialog.relNoFollowCheckbox_.checked = true;
    goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
  
    // Reopen the same dialog.
    anchorElem.rel = 'foo nofollow bar';
    dialog.show();
    dialog.tabPane_.setSelectedTabId(goog.ui.editor.LinkDialog.Id_.ON_WEB_TAB);
    setDisplayInputText(ANCHOR_TEXT);
    setUrlInputText(ANCHOR_URL);
    assertTrue('rel=nofollow should start checked when reopening the dialog',
        dialog.relNoFollowCheckbox_.checked);
  }
  
  function testRelNoFollowExistingLink() {
    mockCtrl.$replayAll();
  
    setUpAnchor('', '', null, null, 'foo nofollow bar');
    createAndShow(null, null, true);
    assertTrue('rel=nofollow should start checked for existing link',
        dialog.relNoFollowCheckbox_.checked);
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Test that clicking on the test button opens a new window with the correct
   * options.
   */
  function testWebTestButton() {
    if (goog.userAgent.GECKO) {
      // TODO(robbyw): Figure out why this is flaky and fix it.
      return;
    }
  
    var width, height;
    mockWindowOpen(ANCHOR_URL, '_blank',
        new goog.testing.mockmatchers.ArgumentMatcher(function(str) {
          return str == 'width=' + width + ',height=' + height +
              ',toolbar=1,scrollbars=1,location=1,statusbar=0,' +
              'menubar=1,resizable=1';
        }, '3rd arg: (string) window.open() options'));
  
    mockCtrl.$replayAll();
    setUpAnchor(ANCHOR_URL, ANCHOR_TEXT);
    createAndShow();
  
    // Measure viewport after opening dialog because that might cause scrollbars
    // to appear and reduce the viewport size.
    var size = goog.dom.getViewportSize(window);
    width = Math.max(size.width - 50, 50);
    height = Math.max(size.height - 50, 50);
  
    var testLink = goog.testing.dom.findTextNode(
        goog.ui.editor.messages.MSG_TEST_THIS_LINK,
        dialog.dialogInternal_.getElement());
    goog.testing.events.fireClickSequence(testLink.parentNode);
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Test that clicking on the test button does not open a new window when
   * the event is canceled.
   */
  function testWebTestButtonPreventDefault() {
    mockCtrl.$replayAll();
    setUpAnchor(ANCHOR_URL, ANCHOR_TEXT);
    createAndShow();
  
    goog.events.listen(dialog,
        goog.ui.editor.LinkDialog.EventType.BEFORE_TEST_LINK,
        function(e) {
          assertEquals(e.url, ANCHOR_URL);
          e.preventDefault();
        });
    var testLink = goog.testing.dom.findTextNode(
        goog.ui.editor.messages.MSG_TEST_THIS_LINK,
        dialog.dialogInternal_.getElement());
    goog.testing.events.fireClickSequence(testLink.parentNode);
  
    mockCtrl.$verifyAll();
  }
  
  
  /**
   * Test that the setTextToDisplayVisible() correctly works.
   * options.
   */
  function testSetTextToDisplayVisible() {
    mockCtrl.$replayAll();
    setUpAnchor('', '', true);
    createAndShow();
  
    assertNotEquals('none',
                    goog.style.getStyle(dialog.textToDisplayDiv_, 'display'));
    dialog.setTextToDisplayVisible(false);
    assertEquals('none',
                 goog.style.getStyle(dialog.textToDisplayDiv_, 'display'));
    dialog.setTextToDisplayVisible(true);
    assertNotEquals('none',
                    goog.style.getStyle(dialog.textToDisplayDiv_, 'display'));
  
    mockCtrl.$verifyAll();
  }
  
  function getDisplayInput() {
    return dialog.dom.getElement(goog.ui.editor.LinkDialog.Id_.TEXT_TO_DISPLAY);
  }
  
  function getDisplayInputText() {
    return getDisplayInput().value;
  }
  
  function setDisplayInputText(text) {
    var textInput = getDisplayInput();
    textInput.value = text;
    // Fire event so that dialog behaves like when user types.
    goog.testing.events.fireBrowserEvent(new goog.events.Event('keyup',
                                                               textInput));
  }
  
  function getUrlInput() {
    var elt = dialog.dom.getElement(goog.ui.editor.LinkDialog.Id_.ON_WEB_INPUT);
    assertNotNullNorUndefined('UrlInput must be found', elt);
    return elt;
  }
  
  function getUrlInputText() {
    return getUrlInput().value;
  }
  
  function setUrlInputText(text) {
    var urlInput = getUrlInput();
    urlInput.value = text;
    // Fire event so that dialog behaves like when user types.
    dialog.urlInputHandler_.dispatchEvent(
        goog.events.InputHandler.EventType.INPUT);
  }
  
  function getEmailInput() {
    var elt = dialog.dom.getElement(
        goog.ui.editor.LinkDialog.Id_.EMAIL_ADDRESS_INPUT);
    assertNotNullNorUndefined('EmailInput must be found', elt);
    return elt;
  }
  
  function getEmailInputText() {
    return getEmailInput().value;
  }
  
  function setEmailInputText(text) {
    var emailInput = getEmailInput();
    emailInput.value = text;
    // Fire event so that dialog behaves like when user types.
    dialog.emailInputHandler_.dispatchEvent(
        goog.events.InputHandler.EventType.INPUT);
  }
  
  function getOpenInNewWindowCheckboxChecked() {
    return dialog.openInNewWindowCheckbox_.checked;
  }
  
  function setOpenInNewWindowCheckboxChecked(checked) {
    dialog.openInNewWindowCheckbox_.checked = checked;
  }
  