123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- // Copyright 2008 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.editor.plugins.LinkBubbleTest');
- goog.setTestOnly('goog.editor.plugins.LinkBubbleTest');
- goog.require('goog.dom');
- goog.require('goog.dom.Range');
- goog.require('goog.dom.TagName');
- goog.require('goog.editor.Command');
- goog.require('goog.editor.Link');
- goog.require('goog.editor.plugins.LinkBubble');
- goog.require('goog.events.BrowserEvent');
- goog.require('goog.events.Event');
- goog.require('goog.events.EventType');
- goog.require('goog.events.KeyCodes');
- goog.require('goog.string');
- goog.require('goog.style');
- goog.require('goog.testing.FunctionMock');
- goog.require('goog.testing.PropertyReplacer');
- goog.require('goog.testing.editor.FieldMock');
- goog.require('goog.testing.editor.TestHelper');
- goog.require('goog.testing.events');
- goog.require('goog.testing.jsunit');
- goog.require('goog.userAgent');
- var fieldDiv;
- var FIELDMOCK;
- var linkBubble;
- var link;
- var linkChild;
- var mockWindowOpen;
- var stubs;
- var testHelper;
- function setUpPage() {
- fieldDiv = goog.dom.$('field');
- stubs = new goog.testing.PropertyReplacer();
- testHelper = new goog.testing.editor.TestHelper(goog.dom.getElement('field'));
- }
- function setUp() {
- testHelper.setUpEditableElement();
- FIELDMOCK = new goog.testing.editor.FieldMock();
- linkBubble = new goog.editor.plugins.LinkBubble();
- linkBubble.fieldObject = FIELDMOCK;
- link = fieldDiv.firstChild;
- linkChild = link.lastChild;
- mockWindowOpen = new goog.testing.FunctionMock('open');
- stubs.set(window, 'open', mockWindowOpen);
- }
- function tearDown() {
- linkBubble.closeBubble();
- testHelper.tearDownEditableElement();
- stubs.reset();
- }
- function testLinkSelected() {
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- goog.dom.Range.createFromNodeContents(link).select();
- linkBubble.handleSelectionChange();
- assertBubble();
- FIELDMOCK.$verify();
- }
- function testLinkClicked() {
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- FIELDMOCK.$verify();
- }
- function testImageLink() {
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- link.setAttribute('imageanchor', 1);
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- FIELDMOCK.$verify();
- }
- function closeBox() {
- var closeBox = goog.dom.getElementsByTagNameAndClass(
- goog.dom.TagName.DIV, 'tr_bubble_closebox');
- assertEquals('Should find only one close box', 1, closeBox.length);
- assertNotNull('Found close box', closeBox[0]);
- goog.testing.events.fireClickSequence(closeBox[0]);
- }
- function testCloseBox() {
- testLinkClicked();
- closeBox();
- assertNoBubble();
- FIELDMOCK.$verify();
- }
- function testChangeClicked() {
- FIELDMOCK.execCommand(
- goog.editor.Command.MODAL_LINK_EDITOR, new goog.editor.Link(link, false));
- FIELDMOCK.$registerArgumentListVerifier('execCommand', function(arr1, arr2) {
- return arr1.length == arr2.length && arr1.length == 2 &&
- arr1[0] == goog.editor.Command.MODAL_LINK_EDITOR &&
- arr2[0] == goog.editor.Command.MODAL_LINK_EDITOR &&
- arr1[1] instanceof goog.editor.Link &&
- arr2[1] instanceof goog.editor.Link;
- });
- FIELDMOCK.$times(1);
- FIELDMOCK.$returns(true);
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- goog.testing.events.fireClickSequence(
- goog.dom.$(goog.editor.plugins.LinkBubble.CHANGE_LINK_ID_));
- assertNoBubble();
- FIELDMOCK.$verify();
- }
- function testChangePressed() {
- FIELDMOCK.execCommand(
- goog.editor.Command.MODAL_LINK_EDITOR, new goog.editor.Link(link, false));
- FIELDMOCK.$registerArgumentListVerifier('execCommand', function(arr1, arr2) {
- return arr1.length == arr2.length && arr1.length == 2 &&
- arr1[0] == goog.editor.Command.MODAL_LINK_EDITOR &&
- arr2[0] == goog.editor.Command.MODAL_LINK_EDITOR &&
- arr1[1] instanceof goog.editor.Link &&
- arr2[1] instanceof goog.editor.Link;
- });
- FIELDMOCK.$times(1);
- FIELDMOCK.$returns(true);
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- var defaultPrevented = !goog.testing.events.fireKeySequence(
- goog.dom.$(goog.editor.plugins.LinkBubble.CHANGE_LINK_ID_),
- goog.events.KeyCodes.ENTER);
- assertTrue(defaultPrevented);
- assertNoBubble();
- FIELDMOCK.$verify();
- }
- function testDeleteClicked() {
- FIELDMOCK.dispatchBeforeChange();
- FIELDMOCK.$times(1);
- FIELDMOCK.dispatchChange();
- FIELDMOCK.$times(1);
- FIELDMOCK.focus();
- FIELDMOCK.$times(1);
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- goog.testing.events.fireClickSequence(
- goog.dom.$(goog.editor.plugins.LinkBubble.DELETE_LINK_ID_));
- var element = goog.userAgent.GECKO ? document.body : fieldDiv;
- assertNotEquals(
- 'Link removed', element.firstChild.nodeName, String(goog.dom.TagName.A));
- assertNoBubble();
- var range = goog.dom.Range.createFromWindow();
- assertEquals('Link selection on link text', linkChild, range.getEndNode());
- assertEquals(
- 'Link selection on link text end',
- goog.dom.getRawTextContent(linkChild).length, range.getEndOffset());
- FIELDMOCK.$verify();
- }
- function testDeletePressed() {
- FIELDMOCK.dispatchBeforeChange();
- FIELDMOCK.$times(1);
- FIELDMOCK.dispatchChange();
- FIELDMOCK.$times(1);
- FIELDMOCK.focus();
- FIELDMOCK.$times(1);
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- var defaultPrevented = !goog.testing.events.fireKeySequence(
- goog.dom.$(goog.editor.plugins.LinkBubble.DELETE_LINK_ID_),
- goog.events.KeyCodes.ENTER);
- assertTrue(defaultPrevented);
- var element = goog.userAgent.GECKO ? document.body : fieldDiv;
- assertNotEquals(
- 'Link removed', element.firstChild.nodeName, String(goog.dom.TagName.A));
- assertNoBubble();
- var range = goog.dom.Range.createFromWindow();
- assertEquals('Link selection on link text', linkChild, range.getEndNode());
- assertEquals(
- 'Link selection on link text end',
- goog.dom.getRawTextContent(linkChild).length, range.getEndOffset());
- FIELDMOCK.$verify();
- }
- function testActionClicked() {
- var SPAN = 'actionSpanId';
- var LINK = 'actionLinkId';
- var toShowCount = 0;
- var actionCount = 0;
- var linkAction = new goog.editor.plugins.LinkBubble.Action(
- SPAN, LINK, 'message',
- function() {
- toShowCount++;
- return toShowCount == 1; // Show it the first time.
- },
- function() { actionCount++; });
- linkBubble = new goog.editor.plugins.LinkBubble(linkAction);
- linkBubble.fieldObject = FIELDMOCK;
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- // The first time the bubble is shown, show our custom action.
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- assertEquals('Should check showing the action', 1, toShowCount);
- assertEquals('Action should not have fired yet', 0, actionCount);
- assertTrue(
- 'Action should be visible 1st time',
- goog.style.isElementShown(goog.dom.$(SPAN)));
- goog.testing.events.fireClickSequence(goog.dom.$(LINK));
- assertEquals('Should not check showing again yet', 1, toShowCount);
- assertEquals('Action should be fired', 1, actionCount);
- closeBox();
- assertNoBubble();
- // The action won't be shown the second time around.
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- assertEquals('Should check showing again', 2, toShowCount);
- assertEquals('Action should not fire again', 1, actionCount);
- assertFalse(
- 'Action should not be shown 2nd time',
- goog.style.isElementShown(goog.dom.$(SPAN)));
- FIELDMOCK.$verify();
- }
- function testLinkTextClicked() {
- mockWindowOpen('http://www.google.com/', '_blank', '');
- mockWindowOpen.$replay();
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- goog.testing.events.fireClickSequence(
- goog.dom.$(goog.editor.plugins.LinkBubble.TEST_LINK_ID_));
- assertBubble();
- mockWindowOpen.$verify();
- FIELDMOCK.$verify();
- }
- function testLinkTextClickedCustomUrlFn() {
- mockWindowOpen('http://images.google.com/', '_blank', '');
- mockWindowOpen.$replay();
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- linkBubble.setTestLinkUrlFn(function(url) {
- return url.replace('www', 'images');
- });
- linkBubble.handleSelectionChange(createMouseEvent(link));
- assertBubble();
- goog.testing.events.fireClickSequence(
- goog.dom.$(goog.editor.plugins.LinkBubble.TEST_LINK_ID_));
- assertBubble();
- mockWindowOpen.$verify();
- FIELDMOCK.$verify();
- }
- /**
- * Urls with invalid schemes shouldn't be linkified.
- * @bug 2585360
- */
- function testDontLinkifyInvalidScheme() {
- mockWindowOpen.$replay();
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- var badLink = goog.dom.createElement(goog.dom.TagName.A);
- badLink.href = 'javascript:alert(1)';
- goog.dom.setTextContent(badLink, 'bad link');
- linkBubble.handleSelectionChange(createMouseEvent(badLink));
- assertBubble();
- // The link shouldn't exist at all
- assertNull(goog.dom.$(goog.editor.plugins.LinkBubble.TEST_LINK_ID_));
- assertBubble();
- mockWindowOpen.$verify();
- FIELDMOCK.$verify();
- }
- function testIsSafeSchemeToOpen() {
- // Urls with no scheme at all are ok too since 'http://' will be prepended.
- var good = [
- 'http://google.com', 'http://google.com/', 'https://google.com',
- 'null@google.com', 'http://www.google.com', 'http://site.com', 'google.com',
- 'google', 'http://google', 'HTTP://GOOGLE.COM', 'HtTp://www.google.com'
- ];
- var bad = [
- 'javascript:google.com', 'httpp://google.com', 'data:foo',
- 'javascript:alert(\'hi\');', 'abc:def'
- ];
- for (var i = 0; i < good.length; i++) {
- assertTrue(
- good[i] + ' should have a safe scheme',
- linkBubble.isSafeSchemeToOpen_(good[i]));
- }
- for (i = 0; i < bad.length; i++) {
- assertFalse(
- bad[i] + ' should have an unsafe scheme',
- linkBubble.isSafeSchemeToOpen_(bad[i]));
- }
- }
- function testShouldOpenWithWhitelist() {
- linkBubble.setSafeToOpenSchemes(['abc']);
- assertTrue(
- 'Scheme should be safe', linkBubble.shouldOpenUrl('abc://google.com'));
- assertFalse(
- 'Scheme should be unsafe', linkBubble.shouldOpenUrl('http://google.com'));
- linkBubble.setBlockOpeningUnsafeSchemes(false);
- assertTrue(
- 'Non-whitelisted should now be safe after disabling blocking',
- linkBubble.shouldOpenUrl('http://google.com'));
- }
- /**
- * @bug 763211
- * @bug 2182147
- */
- function testLongUrlTestLinkAnchorTextCorrect() {
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- var longUrl = 'http://www.reallylonglinkthatshouldbetruncated' +
- 'becauseitistoolong.com';
- var truncatedLongUrl = goog.string.truncateMiddle(longUrl, 48);
- var longLink = goog.dom.createElement(goog.dom.TagName.A);
- longLink.href = longUrl;
- goog.dom.setTextContent(longLink, 'Google');
- fieldDiv.appendChild(longLink);
- linkBubble.handleSelectionChange(createMouseEvent(longLink));
- assertBubble();
- var testLinkEl = goog.dom.$(goog.editor.plugins.LinkBubble.TEST_LINK_ID_);
- assertEquals(
- 'The test link\'s anchor text should be the truncated URL.',
- truncatedLongUrl, testLinkEl.innerHTML);
- fieldDiv.removeChild(longLink);
- FIELDMOCK.$verify();
- }
- /**
- * @bug 2416024
- */
- function testOverridingCreateBubbleContentsDoesntNpeGetTargetUrl() {
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- stubs.set(linkBubble, 'createBubbleContents', function(elem) {
- // getTargetUrl would cause an NPE if urlUtil_ wasn't defined yet.
- linkBubble.getTargetUrl();
- });
- assertNotThrows(
- 'Accessing this.urlUtil_ should not NPE',
- goog.bind(
- linkBubble.handleSelectionChange, linkBubble,
- createMouseEvent(link)));
- FIELDMOCK.$verify();
- }
- /**
- * @bug 15379294
- */
- function testUpdateLinkCommandDoesNotTriggerAnException() {
- FIELDMOCK.$replay();
- linkBubble.enable(FIELDMOCK);
- // At this point, the bubble was not created yet using its createBubble
- // public method.
- assertNotThrows(
- 'Executing goog.editor.Command.UPDATE_LINK_BUBBLE should not trigger ' +
- 'an exception even if the bubble was not created yet using its ' +
- 'createBubble method.',
- goog.bind(
- linkBubble.execCommandInternal, linkBubble,
- goog.editor.Command.UPDATE_LINK_BUBBLE));
- FIELDMOCK.$verify();
- }
- function assertBubble() {
- assertTrue('Link bubble visible', linkBubble.isVisible());
- assertNotNull(
- 'Link bubble created',
- goog.dom.$(goog.editor.plugins.LinkBubble.LINK_DIV_ID_));
- }
- function assertNoBubble() {
- assertFalse('Link bubble not visible', linkBubble.isVisible());
- assertNull(
- 'Link bubble not created',
- goog.dom.$(goog.editor.plugins.LinkBubble.LINK_DIV_ID_));
- }
- function createMouseEvent(target) {
- var eventObj = new goog.events.Event(goog.events.EventType.MOUSEUP, target);
- eventObj.button = goog.events.BrowserEvent.MouseButton.LEFT;
- return new goog.events.BrowserEvent(eventObj, target);
- }
|