diff --git a/edsdme/scripts/links.js b/edsdme/scripts/links.js index 5bc8bda..6c0f4b3 100644 --- a/edsdme/scripts/links.js +++ b/edsdme/scripts/links.js @@ -13,14 +13,14 @@ const domainMappings = { /** * Rewrite a link href domain based on production to stage domain mappings. * @param {string} href - The link href to rewrite. + * @param domainMap map of domains to update * @returns {string} - The rewritten link href, or the original if the environment is prod, * there was a problem processing, or there is no domain mapping defined for it. */ -export function rewriteLinkHref(href) { +export function rewriteHrefDomainOnStage(href, domainMap) { const { env } = getConfig(); if (env.name === 'prod') return href; - let url; try { @@ -29,8 +29,8 @@ export function rewriteLinkHref(href) { return href; } - if (domainMappings[url.hostname]) { - url.hostname = domainMappings[url.hostname]; + if (domainMap[url.hostname]) { + url.hostname = domainMap[url.hostname]; return url.toString(); } @@ -45,7 +45,7 @@ export function rewriteLinkHref(href) { export function applyGnavLinkRewriting(gnav) { const links = gnav.querySelectorAll('a[href]'); links.forEach((link) => { - link.href = rewriteLinkHref(link.href); + link.href = rewriteHrefDomainOnStage(link.href, domainMappings); }); return gnav; diff --git a/edsdme/scripts/rewriteLinks.js b/edsdme/scripts/rewriteLinks.js index d2a4424..d47a357 100644 --- a/edsdme/scripts/rewriteLinks.js +++ b/edsdme/scripts/rewriteLinks.js @@ -1,42 +1,145 @@ -import { getConfig } from '../blocks/utils/utils.js'; import { partnerIsSignedIn } from './utils.js'; +import { rewriteHrefDomainOnStage } from './links.js'; -export function rewriteLinks() { - const environments = { - cbcProd: 'https://cbconnection.adobe.com', - cbcStage: 'https://cbconnection-stage.adobe.com', - partnersProd: 'https://partners.adobe.com', - partnersStage: 'https://partners.stage.adobe.com', - }; +/** + * Domain map where the key is the production domain, + * and the value is the corresponding stage domain. + */ +const domainMap = { + 'cbconnection.adobe.com': 'cbconnection-stage.adobe.com', + 'partners.adobe.com': 'partners.stage.adobe.com', +}; - const { env } = getConfig(); - const isProd = env.name === 'prod'; +/** + * Domain configs where the key is the production domain, + * and the value is config object for it. + */ +const domainConfigs = { + 'cbconnection.adobe.com': { + localeMap: { + de: 'de', + cn: 'zh_cn', + fr: 'fr', + it: 'it', + jp: 'jp', + kr: 'ko', + es: 'es', + }, + expectedLocale: 'en', + loginPath: '/bin/fusion/modalImsLogin', + }, + 'www.adobe.com': { + localeMap: { + emea: 'uk', + fr: 'fr', + de: 'de', + it: 'it', + es: 'es', + kr: 'kr', + cn: 'cn', + jp: 'jp', + }, + }, + 'www.helpx.adobe.com': { + localeMap: { + emea: 'uk', + fr: 'fr', + de: 'de', + it: 'it', + es: 'es', + kr: 'kr', + cn: 'cn', + jp: 'jp', + }, + }, + 'www.business.adobe.com': { + localeMap: { + emea: 'uk', + fr: 'fr', + de: 'de', + it: 'it', + es: 'es', + kr: 'kr', + cn: 'cn', + jp: 'jp', + }, + }, +}; - const updateLinks = (currentDomain, newDomain, loginPath) => { - const isSignedIn = partnerIsSignedIn(); - document.querySelectorAll(`[href^="${currentDomain}"]`).forEach((link) => { - let url; - try { - url = new URL(link.href); - } catch { - return; - } - url.hostname = new URL(newDomain).hostname; - if (isSignedIn && loginPath && !url.pathname.includes(loginPath)) { - const resource = url.pathname; - url.searchParams.append('resource', resource); - url.pathname = loginPath; - } - link.href = url.toString(); - }); - }; +/** + * Modifies the given URL object by updating its search params + * (aimed to handle cbcconnection links and attach login path to them) + * @param {URL} url - The URL object to be modified. + */ +// eslint-disable-next-line consistent-return +function setLoginPathIfSignedIn(url) { + const loginPath = domainConfigs[url.hostname]?.loginPath; + if (loginPath) { + const isUserSignedIn = partnerIsSignedIn(); + if (isUserSignedIn && !url.pathname.includes(loginPath)) { + const resource = url.pathname; + url.searchParams.append('resource', resource); + url.pathname = loginPath; + } + } +} - // Update cbc links - const cbcDomain = isProd ? environments.cbcProd : environments.cbcStage; - updateLinks(environments.cbcProd, cbcDomain, '/bin/fusion/modalImsLogin'); +/** + * Modifies the given URL object by updating its path with correct locale for url domain, + * based on current page locale and locale maps that are defined for specific domains + * + * for cbcconnection it is expected that url already includes /en in path, + * so it will be updated to correct locale + * for other domains it is not expected to have locale in path, + * so correct locale will be appended to url.pathname + * @param {URL} url - The URL object to be modified. + */ +function setLocale(url) { + const localesToSkip = ['na', 'latam', 'apac']; + const currentPageLocale = window.location.pathname.split('/')?.[1]; + if (localesToSkip.indexOf(currentPageLocale) !== -1) return; + const domainConfig = domainConfigs[url.hostname]; + if (!domainConfig) return; + const localeFromMap = domainConfig.localeMap[currentPageLocale]; + if (!localeFromMap) return; + const pathParts = url.pathname.split('/').filter(Boolean); + if (domainConfig.expectedLocale) { + const localeFromHref = pathParts[0]; + if (localeFromHref !== domainConfig.expectedLocale) return; + pathParts[0] = localeFromMap; + } else { + pathParts.unshift(localeFromMap); + } + url.pathname = `/${pathParts.join('/')}`; +} - // Update partners links if not prod - if (!isProd) { - updateLinks(environments.partnersProd, environments.partnersStage); +/** + * Takes string that represent url href, + * updates locale, login path and domain + * @param href + * @returns {*|string} modified href + */ +function getUpdatedHref(href) { + let url; + try { + url = new URL(href); + } catch { + return href; } + setLocale(url); + setLoginPathIfSignedIn(url); + // always as last step since we need original domains for mappings + return rewriteHrefDomainOnStage(url.href, domainMap); +} + +/** + * Iterates throw all links on the page and updates their hrefs if conditions are fulfilled + * (conditions: appropriate domain, appropriate current page locale, + * environment and is user logged in) + */ +export function rewriteLinks() { + const links = document.querySelectorAll('a[href]'); + links.forEach((link) => { + link.href = getUpdatedHref(link.href); + }); } diff --git a/test/scripts/links.jest.js b/test/scripts/links.jest.js index 131c766..9936923 100644 --- a/test/scripts/links.jest.js +++ b/test/scripts/links.jest.js @@ -2,11 +2,16 @@ * @jest-environment jsdom */ -import { applyGnavLinkRewriting, rewriteLinkHref } from '../../edsdme/scripts/links.js'; +import { applyGnavLinkRewriting, rewriteHrefDomainOnStage } from '../../edsdme/scripts/links.js'; import { getConfig } from '../../edsdme/blocks/utils/utils.js'; jest.mock('../../edsdme/blocks/utils/utils.js', () => ({ getConfig: jest.fn() })); +const domainMappings = { + 'adobe.force.com': 'adobe--sfstage.sandbox.my.site.com', + 'io-partners-dx.adobe.com': 'io-partners-dx.stage.adobe.com', +}; + describe('Test links.js', () => { beforeEach(() => { getConfig.mockReturnValue({ env: { name: 'stage' } }); @@ -17,35 +22,35 @@ describe('Test links.js', () => { getConfig.mockReturnValue({ env: { name: 'prod' } }); const href = 'https://adobe.force.com/path'; - const result = rewriteLinkHref(href); + const result = rewriteHrefDomainOnStage(href, domainMappings); expect(result).toBe(href); }); test('should rewrite sales for link hrefs', () => { const href = 'https://adobe.force.com/path'; - const result = rewriteLinkHref(href); + const result = rewriteHrefDomainOnStage(href, domainMappings); expect(result).toBe('https://adobe--sfstage.sandbox.my.site.com/path'); }); test('should rewrite runtime link hrefs', () => { const href = 'https://io-partners-dx.adobe.com/path'; - const result = rewriteLinkHref(href); + const result = rewriteHrefDomainOnStage(href, domainMappings); expect(result).toBe('https://io-partners-dx.stage.adobe.com/path'); }); test('should return unchanged link hrefs if invalid', () => { const href = 'invalid-url'; - const result = rewriteLinkHref(href); + const result = rewriteHrefDomainOnStage(href, domainMappings); expect(result).toBe(href); }); test('should return unchanged link hrefs if domain is not mapped', () => { const href = 'https://unmapped-domain.com/path'; - const result = rewriteLinkHref(href); + const result = rewriteHrefDomainOnStage(href, domainMappings); expect(result).toBe(href); }); diff --git a/test/scripts/rewriteLinks.jest.js b/test/scripts/rewriteLinks.jest.js index d8c6c24..8f38466 100644 --- a/test/scripts/rewriteLinks.jest.js +++ b/test/scripts/rewriteLinks.jest.js @@ -6,7 +6,7 @@ import { getConfig } from '../../edsdme/blocks/utils/utils.js'; import { partnerIsSignedIn } from '../../edsdme/scripts/utils.js'; jest.mock('../../edsdme/blocks/utils/utils.js', () => ({ getConfig: jest.fn() })); -jest.mock('../../edsdme/scripts/utils.js', () => ({ partnerIsSignedIn: jest.fn() })); +jest.mock('../../edsdme/scripts/utils.js', () => ({ partnerIsSignedIn: jest.fn(() => ({ 'partner name': { company: 'test' } })) })); // Mock DOM document.body.innerHTML = ` @@ -20,6 +20,15 @@ describe('Test rewrite links', () => { beforeEach(() => { getConfig.mockReturnValue({ env: { name: 'stage' } }); partnerIsSignedIn.mockReturnValue({ 'partner name': { company: 'test' } }); + Object.defineProperty(window, 'location', { + writable: true, + value: { + pathname: '/cn/test-path', + href: 'http://example.com/cn/test-path', + assign: jest.fn(), + reload: jest.fn(), + }, + }); }); afterEach(() => { jest.clearAllMocks(); // Clear mocks after each test @@ -31,11 +40,12 @@ describe('Test rewrite links', () => { `; }); - test('should update prod links to cbc stage in non-prod, with resource query param and login path', () => { + test('should update prod links to cbc stage in non-prod, with resource query param and login path,' + + 'it should update locale if exist for cbc connection', () => { rewriteLinks(); const links = document.querySelectorAll('a'); expect(links[0].href).toBe('https://cbconnection-stage.adobe.com/bin/fusion/modalImsLogin?resource=%2Fhome%2Fsearch'); - expect(links[3].href).toBe('https://cbconnection-stage.adobe.com/bin/fusion/modalImsLogin?resource=%2Fen%2Fnews%2Fenablement-news-partner-lock'); + expect(links[3].href).toBe('https://cbconnection-stage.adobe.com/bin/fusion/modalImsLogin?resource=%2Fzh_cn%2Fnews%2Fenablement-news-partner-lock'); }); test('should update only domain when login path is already there', () => { @@ -50,20 +60,129 @@ describe('Test rewrite links', () => { expect(links[1].href).toBe('https://partners.stage.adobe.com/'); }); - test('should not update partners prod domain and cbc prod domain when on prod', () => { + test('should not update partners prod domain and cbc prod domain when on prod.' + + ' Should update locale if exist for cbcconnection', () => { getConfig.mockReturnValue({ env: { name: 'prod' } }); rewriteLinks(); const links = document.querySelectorAll('a'); expect(links[1].href).toBe('https://partners.adobe.com/'); - expect(links[3].href).toBe('https://cbconnection.adobe.com/bin/fusion/modalImsLogin?resource=%2Fen%2Fnews%2Fenablement-news-partner-lock'); + expect(links[3].href).toBe('https://cbconnection.adobe.com/bin/fusion/modalImsLogin?resource=%2Fzh_cn%2Fnews%2Fenablement-news-partner-lock'); }); - test('should update partners prod domain and cbc prod domain but not login path when not logged in when on stage', () => { + test('should update partners prod domain and cbc prod domain but not login path when not logged in when on stage,' + + 'it should update locale, if exist, for cbconnection', () => { partnerIsSignedIn.mockReturnValue(null); rewriteLinks(); const links = document.querySelectorAll('a'); expect(links[0].href).toBe('https://cbconnection-stage.adobe.com/home/search'); expect(links[1].href).toBe('https://partners.stage.adobe.com/'); - expect(links[3].href).toBe('https://cbconnection-stage.adobe.com/en/news/enablement-news-partner-lock'); + expect(links[3].href).toBe('https://cbconnection-stage.adobe.com/zh_cn/news/enablement-news-partner-lock'); + }); + + test('should update locales only for domains that are in the map', () => { + partnerIsSignedIn.mockReturnValue(null); + document.body.innerHTML = ` + cbc prod Link + Partner prod Link + adobe + helpx + business + not in list of locales + not in list of locales + +`; + rewriteLinks(); + const links = document.querySelectorAll('a'); + expect(links[0].href).toBe('https://cbconnection-stage.adobe.com/zh_cn/home/search'); + expect(links[1].href).toBe('https://partners.stage.adobe.com/'); + expect(links[2].href).toBe('https://www.adobe.com/cn'); + expect(links[3].href).toBe('https://www.helpx.adobe.com/cn'); + expect(links[4].href).toBe('https://www.business.adobe.com/cn'); + expect(links[5].href).toBe('https://www.business.adobe.com/cn'); + expect(links[6].href).toBe('https://www.business.adobe.com/cn'); + }); + test('should not update cbc link locale when locale mapping dont exist for current locale ', () => { + document.body.innerHTML = ` + cbc prod Link + cbc prod Link +`; + Object.defineProperty(window, 'location', { + writable: true, + value: { + pathname: '/pr/test-path', + href: 'http://example.com/pr/test-path', + assign: jest.fn(), + reload: jest.fn(), + }, + }); + partnerIsSignedIn.mockReturnValue(null); + rewriteLinks(); + const links = document.querySelectorAll('a'); + expect(links[0].href).toBe('https://cbconnection-stage.adobe.com/en/home/search/'); + expect(links[1].href).toBe('https://www.business.adobe.com/'); + }); + test('should not update link locale when current locale is na or international sites ', () => { + document.body.innerHTML = ` + cbc prod Link + cbc prod Link +`; + Object.defineProperty(window, 'location', { + writable: true, + value: { + pathname: '/latam/test-path', + href: 'http://example.com/latam/test-path', + assign: jest.fn(), + reload: jest.fn(), + }, + }); + partnerIsSignedIn.mockReturnValue(null); + rewriteLinks(); + const links = document.querySelectorAll('a'); + expect(links[0].href).toBe('https://cbconnection-stage.adobe.com/en/home/search/'); + expect(links[1].href).toBe('https://www.business.adobe.com/emea'); + }); + + test('should not update cbc link locale when it have different locale than en ', () => { + document.body.innerHTML = ` + cbc prod Link +`; + Object.defineProperty(window, 'location', { + writable: true, + value: { + pathname: '/emea/test-path', + href: 'http://example.com/emea/test-path', + assign: jest.fn(), + reload: jest.fn(), + }, + }); + partnerIsSignedIn.mockReturnValue(null); + rewriteLinks(); + const links = document.querySelectorAll('a'); + expect(links[0].href).toBe('https://cbconnection-stage.adobe.com/fr/home/search/'); + }); + test('should update adobe,helpx and business.adobe link locale when current page locale is emea, and for cbc ' + + 'it shouldnt be transformed ', () => { + document.body.innerHTML = ` + cbc prod Link + cbc prod Link + cbc prod Link + cbc prod Link +`; + Object.defineProperty(window, 'location', { + writable: true, + value: { + pathname: '/emea/test-path', + href: 'http://example.com/emea/test-path', + assign: jest.fn(), + reload: jest.fn(), + }, + }); + partnerIsSignedIn.mockReturnValue(null); + rewriteLinks(); + const links = document.querySelectorAll('a'); + expect(links[0].href).toBe('https://www.business.adobe.com/uk'); + expect(links[1].href).toBe('https://www.helpx.adobe.com/uk'); + expect(links[2].href).toBe('https://www.adobe.com/uk'); + expect(links[3].href).toBe('https://cbconnection-stage.adobe.com/en/home/search/'); }); });