diff --git a/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.hbs b/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.hbs index 9702ac9e5..e4144bbbd 100644 --- a/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.hbs +++ b/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.hbs @@ -1,4 +1,8 @@ {{#if owner}} -

{{t 'testResult.owner.name'}}

-
{{owner}}
-{{/if}} \ No newline at end of file + {{t 'testResult.owner.name'}}: + {{#if owner.url}} + {{owner.displayName}} + {{else}} + {{owner.displayName}} + {{/if}} +{{/if}} diff --git a/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.js b/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.js index 2cb24ed0b..c84a599e8 100644 --- a/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.js +++ b/allure-generator/src/main/javascript/plugins/testresult-owner/OwnerView.js @@ -1,5 +1,6 @@ import { View } from "backbone.marionette"; import { className } from "../../decorators/index"; +import parseAddress from "../../utils/parseAddress"; import template from "./OwnerView.hbs"; @className("pane__section") @@ -9,7 +10,7 @@ class OwnerView extends View { serializeData() { const extra = this.model.get("extra"); return { - owner: extra ? extra.owner : null, + owner: extra ? parseAddress(extra.owner) : null, }; } } diff --git a/allure-generator/src/main/javascript/utils/parseAddress.js b/allure-generator/src/main/javascript/utils/parseAddress.js new file mode 100644 index 000000000..43fe1f1e7 --- /dev/null +++ b/allure-generator/src/main/javascript/utils/parseAddress.js @@ -0,0 +1,60 @@ +const RFC2822_ADDRESS = /^(.*) <(.*)>$/; +const LOOKS_LIKE_EMAIL = /^[^@]+@[^@]+$/; + +/** + * Parse a potentially RFC 2822 address into a display name and an address. + * + * @param {string | null | undefined} maybeAddress + * @returns {{ displayName: string, url?: string } | null + */ +export default function parseAddress(maybeAddress) { + if (!maybeAddress) { + return null; + } + + const match = maybeAddress.match(RFC2822_ADDRESS); + if (match) { + return { + displayName: match[1], + url: toHref(match[2]), + }; + } + + return { + displayName: maybeAddress, + url: toHref(maybeAddress), + }; +} + +/** + * If the address is a valid URL, returns the URL. + * If the address resembles an email address, returns a mailto: URL. + * Otherwise, returns undefined. + * + * @param {string} address + * @returns {string | undefined} + */ +function toHref(address) { + if (isValidURL(address)) { + return address; + } + + if (LOOKS_LIKE_EMAIL.test(address)) { + return `mailto:${address}`; + } +} + +/** + * If the address is a valid URL, returns the URL. + * + * @param {string} maybeURL + * @returns {boolean} + */ +function isValidURL(maybeURL) { + try { + new URL(maybeURL); + return true; + } catch (_error) { + return false; + } +}