/** * @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. */ import '../../../test/common-test-setup-karma.js'; import './gr-linked-text.js'; import {GerritNav} from '../../core/gr-navigation/gr-navigation.js'; import {html} from '@polymer/polymer/lib/utils/html-tag.js'; const basicFixture = fixtureFromTemplate(html`
`); suite('gr-linked-text tests', () => { let element; let originalCanonicalPath; setup(() => { originalCanonicalPath = window.CANONICAL_PATH; element = basicFixture.instantiate(); sinon.stub(GerritNav, 'mapCommentlinks').value( 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: '$1', }, hashedhtml: { match: 'hash:(.+)', html: '$1', }, baseurl: { match: 'test (.+)', html: '$1', }, anotatstartwithbaseurl: { match: 'a test (.+)', html: '[Lookup: $1]', }, disabledconfig: { match: 'foo:(.+)', link: 'https://google.com/search?q=$1', enabled: false, }, }; }); teardown(() => { window.CANONICAL_PATH = originalCanonicalPath; }); 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= { 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= { 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$2', }, b2: { match: '(B:\\s*\\d+\\s*,\\s*)(\\d+)', html: '$1$2', }, }; element.content = '- B: 123, 45'; const links = 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 = sinon.stub(element, '_contentChanged'); const contentConfigStub = sinon.stub(element, '_contentOrConfigChanged'); element.content = 'some text'; assert.isTrue(contentStub.called); assert.isTrue(contentConfigStub.called); }); });