| <!DOCTYPE html> |
| <!-- |
| @license |
| Copyright (C) 2015 The Android Open Source Project |
| |
| 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. |
| --> |
| |
| <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> |
| <meta charset="utf-8"> |
| <title>gr-linked-text</title> |
| |
| <script src="/node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script> |
| |
| <script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script> |
| <script src="/components/wct-browser-legacy/browser.js"></script> |
| |
| <test-fixture id="basic"> |
| <template> |
| <gr-linked-text> |
| <div id="output"></div> |
| </gr-linked-text> |
| </template> |
| </test-fixture> |
| |
| <script type="module"> |
| import '../../../test/common-test-setup.js'; |
| import './gr-linked-text.js'; |
| import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js'; |
| import {GerritNav} from '../../core/gr-navigation/gr-navigation.js'; |
| |
| suite('gr-linked-text tests', () => { |
| let element; |
| let sandbox; |
| |
| setup(() => { |
| element = fixture('basic'); |
| sandbox = sinon.sandbox.create(); |
| sandbox.stub(GerritNav, 'mapCommentlinks', x => x); |
| element.config = { |
| ph: { |
| match: '([Bb]ug|[Ii]ssue)\\s*#?(\\d+)', |
| link: 'https://bugs.chromium.org/p/gerrit/issues/detail?id=$2', |
| }, |
| prefixsameinlinkandpattern: { |
| match: '([Hh][Tt][Tt][Pp]example)\\s*#?(\\d+)', |
| link: 'https://bugs.chromium.org/p/gerrit/issues/detail?id=$2', |
| }, |
| changeid: { |
| match: '(I[0-9a-f]{8,40})', |
| link: '#/q/$1', |
| }, |
| changeid2: { |
| match: 'Change-Id: +(I[0-9a-f]{8,40})', |
| link: '#/q/$1', |
| }, |
| googlesearch: { |
| match: 'google:(.+)', |
| link: 'https://bing.com/search?q=$1', // html should supercede link. |
| html: '<a href="https://google.com/search?q=$1">$1</a>', |
| }, |
| hashedhtml: { |
| match: 'hash:(.+)', |
| html: '<a href="#/awesomesauce">$1</a>', |
| }, |
| baseurl: { |
| match: 'test (.+)', |
| html: '<a href="/r/awesomesauce">$1</a>', |
| }, |
| anotatstartwithbaseurl: { |
| match: 'a test (.+)', |
| html: '[Lookup: <a href="/r/awesomesauce">$1</a>]', |
| }, |
| disabledconfig: { |
| match: 'foo:(.+)', |
| link: 'https://google.com/search?q=$1', |
| enabled: false, |
| }, |
| }; |
| }); |
| |
| teardown(() => { |
| sandbox.restore(); |
| }); |
| |
| test('URL pattern was parsed and linked.', () => { |
| // Regular inline link. |
| const url = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650'; |
| element.content = url; |
| const linkEl = element.$.output.childNodes[0]; |
| assert.equal(linkEl.target, '_blank'); |
| assert.equal(linkEl.rel, 'noopener'); |
| assert.equal(linkEl.href, url); |
| assert.equal(linkEl.textContent, url); |
| }); |
| |
| test('Bug pattern was parsed and linked', () => { |
| // "Issue/Bug" pattern. |
| element.content = 'Issue 3650'; |
| |
| let linkEl = element.$.output.childNodes[0]; |
| const url = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650'; |
| assert.equal(linkEl.target, '_blank'); |
| assert.equal(linkEl.href, url); |
| assert.equal(linkEl.textContent, 'Issue 3650'); |
| |
| element.content = 'Bug 3650'; |
| linkEl = element.$.output.childNodes[0]; |
| assert.equal(linkEl.target, '_blank'); |
| assert.equal(linkEl.rel, 'noopener'); |
| assert.equal(linkEl.href, url); |
| assert.equal(linkEl.textContent, 'Bug 3650'); |
| }); |
| |
| test('Pattern with same prefix as link was correctly parsed', () => { |
| // Pattern starts with the same prefix (`http`) as the url. |
| element.content = 'httpexample 3650'; |
| |
| assert.equal(element.$.output.childNodes.length, 1); |
| const linkEl = element.$.output.childNodes[0]; |
| const url = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650'; |
| assert.equal(linkEl.target, '_blank'); |
| assert.equal(linkEl.href, url); |
| assert.equal(linkEl.textContent, 'httpexample 3650'); |
| }); |
| |
| test('Change-Id pattern was parsed and linked', () => { |
| // "Change-Id:" pattern. |
| const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e'; |
| const prefix = 'Change-Id: '; |
| element.content = prefix + changeID; |
| |
| const textNode = element.$.output.childNodes[0]; |
| const linkEl = element.$.output.childNodes[1]; |
| assert.equal(textNode.textContent, prefix); |
| const url = '/q/' + changeID; |
| assert.isFalse(linkEl.hasAttribute('target')); |
| // Since url is a path, the host is added automatically. |
| assert.isTrue(linkEl.href.endsWith(url)); |
| assert.equal(linkEl.textContent, changeID); |
| }); |
| |
| test('Change-Id pattern was parsed and linked with base url', () => { |
| window.CANONICAL_PATH = '/r'; |
| |
| // "Change-Id:" pattern. |
| const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e'; |
| const prefix = 'Change-Id: '; |
| element.content = prefix + changeID; |
| |
| const textNode = element.$.output.childNodes[0]; |
| const linkEl = element.$.output.childNodes[1]; |
| assert.equal(textNode.textContent, prefix); |
| const url = '/r/q/' + changeID; |
| assert.isFalse(linkEl.hasAttribute('target')); |
| // Since url is a path, the host is added automatically. |
| assert.isTrue(linkEl.href.endsWith(url)); |
| assert.equal(linkEl.textContent, changeID); |
| }); |
| |
| test('Multiple matches', () => { |
| element.content = 'Issue 3650\nIssue 3450'; |
| const linkEl1 = element.$.output.childNodes[0]; |
| const linkEl2 = element.$.output.childNodes[2]; |
| |
| assert.equal(linkEl1.target, '_blank'); |
| assert.equal(linkEl1.href, |
| 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650'); |
| assert.equal(linkEl1.textContent, 'Issue 3650'); |
| |
| assert.equal(linkEl2.target, '_blank'); |
| assert.equal(linkEl2.href, |
| 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3450'); |
| assert.equal(linkEl2.textContent, 'Issue 3450'); |
| }); |
| |
| test('Change-Id pattern parsed before bug pattern', () => { |
| // "Change-Id:" pattern. |
| const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e'; |
| const prefix = 'Change-Id: '; |
| |
| // "Issue/Bug" pattern. |
| const bug = 'Issue 3650'; |
| |
| const changeUrl = '/q/' + changeID; |
| const bugUrl = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650'; |
| |
| element.content = prefix + changeID + bug; |
| |
| const textNode = element.$.output.childNodes[0]; |
| const changeLinkEl = element.$.output.childNodes[1]; |
| const bugLinkEl = element.$.output.childNodes[2]; |
| |
| assert.equal(textNode.textContent, prefix); |
| |
| assert.isFalse(changeLinkEl.hasAttribute('target')); |
| assert.isTrue(changeLinkEl.href.endsWith(changeUrl)); |
| assert.equal(changeLinkEl.textContent, changeID); |
| |
| assert.equal(bugLinkEl.target, '_blank'); |
| assert.equal(bugLinkEl.href, bugUrl); |
| assert.equal(bugLinkEl.textContent, 'Issue 3650'); |
| }); |
| |
| test('html field in link config', () => { |
| element.content = 'google:do a barrel roll'; |
| const linkEl = element.$.output.childNodes[0]; |
| assert.equal(linkEl.getAttribute('href'), |
| 'https://google.com/search?q=do a barrel roll'); |
| assert.equal(linkEl.textContent, 'do a barrel roll'); |
| }); |
| |
| test('removing hash from links', () => { |
| element.content = 'hash:foo'; |
| const linkEl = element.$.output.childNodes[0]; |
| assert.isTrue(linkEl.href.endsWith('/awesomesauce')); |
| assert.equal(linkEl.textContent, 'foo'); |
| }); |
| |
| test('html with base url', () => { |
| window.CANONICAL_PATH = '/r'; |
| |
| element.content = 'test foo'; |
| const linkEl = element.$.output.childNodes[0]; |
| assert.isTrue(linkEl.href.endsWith('/r/awesomesauce')); |
| assert.equal(linkEl.textContent, 'foo'); |
| }); |
| |
| test('a is not at start', () => { |
| window.CANONICAL_PATH = '/r'; |
| |
| element.content = 'a test foo'; |
| const linkEl = element.$.output.childNodes[1]; |
| assert.isTrue(linkEl.href.endsWith('/r/awesomesauce')); |
| assert.equal(linkEl.textContent, 'foo'); |
| }); |
| |
| test('hash html with base url', () => { |
| window.CANONICAL_PATH = '/r'; |
| |
| element.content = 'hash:foo'; |
| const linkEl = element.$.output.childNodes[0]; |
| assert.isTrue(linkEl.href.endsWith('/r/awesomesauce')); |
| assert.equal(linkEl.textContent, 'foo'); |
| }); |
| |
| test('disabled config', () => { |
| element.content = 'foo:baz'; |
| assert.equal(element.$.output.innerHTML, 'foo:baz'); |
| }); |
| |
| test('R=email labels link correctly', () => { |
| element.removeZeroWidthSpace = true; |
| element.content = 'R=\u200Btest@google.com'; |
| assert.equal(element.$.output.textContent, 'R=test@google.com'); |
| assert.equal(element.$.output.innerHTML.match(/(R=<a)/g).length, 1); |
| }); |
| |
| test('CC=email labels link correctly', () => { |
| element.removeZeroWidthSpace = true; |
| element.content = 'CC=\u200Btest@google.com'; |
| assert.equal(element.$.output.textContent, 'CC=test@google.com'); |
| assert.equal(element.$.output.innerHTML.match(/(CC=<a)/g).length, 1); |
| }); |
| |
| test('only {http,https,mailto} protocols are linkified', () => { |
| element.content = 'xx mailto:test@google.com yy'; |
| let links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 1); |
| assert.equal(links[0].getAttribute('href'), 'mailto:test@google.com'); |
| assert.equal(links[0].innerHTML, 'mailto:test@google.com'); |
| |
| element.content = 'xx http://google.com yy'; |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 1); |
| assert.equal(links[0].getAttribute('href'), 'http://google.com'); |
| assert.equal(links[0].innerHTML, 'http://google.com'); |
| |
| element.content = 'xx https://google.com yy'; |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 1); |
| assert.equal(links[0].getAttribute('href'), 'https://google.com'); |
| assert.equal(links[0].innerHTML, 'https://google.com'); |
| |
| element.content = 'xx ssh://google.com yy'; |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 0); |
| |
| element.content = 'xx ftp://google.com yy'; |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 0); |
| }); |
| |
| test('links without leading whitespace are linkified', () => { |
| element.content = 'xx abcmailto:test@google.com yy'; |
| assert.equal(element.$.output.innerHTML.substr(0, 6), 'xx abc'); |
| let links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 1); |
| assert.equal(links[0].getAttribute('href'), 'mailto:test@google.com'); |
| assert.equal(links[0].innerHTML, 'mailto:test@google.com'); |
| |
| element.content = 'xx defhttp://google.com yy'; |
| assert.equal(element.$.output.innerHTML.substr(0, 6), 'xx def'); |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 1); |
| assert.equal(links[0].getAttribute('href'), 'http://google.com'); |
| assert.equal(links[0].innerHTML, 'http://google.com'); |
| |
| element.content = 'xx qwehttps://google.com yy'; |
| assert.equal(element.$.output.innerHTML.substr(0, 6), 'xx qwe'); |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 1); |
| assert.equal(links[0].getAttribute('href'), 'https://google.com'); |
| assert.equal(links[0].innerHTML, 'https://google.com'); |
| |
| // Non-latin character |
| element.content = 'xx абвhttps://google.com yy'; |
| assert.equal(element.$.output.innerHTML.substr(0, 6), 'xx абв'); |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 1); |
| assert.equal(links[0].getAttribute('href'), 'https://google.com'); |
| assert.equal(links[0].innerHTML, 'https://google.com'); |
| |
| element.content = 'xx ssh://google.com yy'; |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 0); |
| |
| element.content = 'xx ftp://google.com yy'; |
| links = element.$.output.querySelectorAll('a'); |
| assert.equal(links.length, 0); |
| }); |
| |
| test('overlapping links', () => { |
| element.config = { |
| b1: { |
| match: '(B:\\s*)(\\d+)', |
| html: '$1<a href="ftp://foo/$2">$2</a>', |
| }, |
| b2: { |
| match: '(B:\\s*\\d+\\s*,\\s*)(\\d+)', |
| html: '$1<a href="ftp://foo/$2">$2</a>', |
| }, |
| }; |
| element.content = '- B: 123, 45'; |
| const links = dom(element.root).querySelectorAll('a'); |
| |
| assert.equal(links.length, 2); |
| assert.equal(element.shadowRoot |
| .querySelector('span').textContent, '- B: 123, 45'); |
| |
| assert.equal(links[0].href, 'ftp://foo/123'); |
| assert.equal(links[0].textContent, '123'); |
| |
| assert.equal(links[1].href, 'ftp://foo/45'); |
| assert.equal(links[1].textContent, '45'); |
| }); |
| |
| test('_contentOrConfigChanged called with config', () => { |
| const contentStub = sandbox.stub(element, '_contentChanged'); |
| const contentConfigStub = sandbox.stub(element, '_contentOrConfigChanged'); |
| element.content = 'some text'; |
| assert.isTrue(contentStub.called); |
| assert.isTrue(contentConfigStub.called); |
| }); |
| }); |
| </script> |