From cd095b1ed6a31d287aa54e4942f7bfb71154547c Mon Sep 17 00:00:00 2001 From: vgoodric Date: Mon, 14 Oct 2024 21:00:02 -0600 Subject: [PATCH 01/12] create mepxlg branch --- libs/features/personalization/entitlements.js | 62 ------------------- .../personalization/personalization.js | 39 +++++++++++- libs/martech/martech.js | 6 +- 3 files changed, 41 insertions(+), 66 deletions(-) delete mode 100644 libs/features/personalization/entitlements.js diff --git a/libs/features/personalization/entitlements.js b/libs/features/personalization/entitlements.js deleted file mode 100644 index b329c8b338..0000000000 --- a/libs/features/personalization/entitlements.js +++ /dev/null @@ -1,62 +0,0 @@ -import { getConfig } from '../../utils/utils.js'; - -const ENTITLEMENT_MAP = { - '31943c06-06de-4f5f-8689-18973c13207a': 'photoshop-any', - '8ba78b22-90fb-4b97-a1c4-f8c03a45cbc2': 'indesign-any', - '8d3c8ac2-2937-486b-b6ff-37f02271b09b': 'illustrator-any', - 'fd30e9c7-9ae9-44db-8e70-5c652a5bb1d2': 'cc-all-apps-any', - '4e2f2a6e-48c4-49eb-9dd5-c44070abb3f0': 'after-effects-any', - 'e7650448-268b-4a0d-9795-05f604d7e42f': 'lightroom-any', - '619130fc-c7b5-4b39-a687-b32061326869': 'premiere-pro-any', - 'cec4d899-4b41-469e-9f2d-4658689abf29': 'phsp-ltr-bundle', - '8da44606-9841-43d0-af72-86d5a9d3bba0': 'cc-photo', - 'ab713720-91a2-4e8e-b6d7-6f613e049566': 'any-cc-product-no-stock', - 'b0f65e1c-7737-4788-b3ae-0011c80bcbe1': 'any-cc-product-with-stock', - '934fdc1d-7ba6-4644-908b-53e01e550086': 'any-dc-product', - '6dfcb769-324f-42e0-9e12-1fc4dc0ee85b': 'always-on-promo', - '015c52cb-30b0-4ac9-b02e-f8716b39bfb6': 'not-q-always-on-promo', - '42e06851-64cd-4684-a54a-13777403487a': '3d-substance-collection', - 'eda8c774-420b-44c2-9006-f9a8d0fb5168': '3d-substance-texturing', - '76e408f6-ab08-49f0-adb6-f9b4efcc205d': 'cc-free', - '08216aa4-4a0f-4136-8b27-182212764a7c': 'dc-free', - 'fc2d5b34-fa75-4e80-9f23-7d4b40bcfc9b': 'cc-paid', - 'c6927505-97b3-4655-995a-6452630fa9cb': 'fresco-any', - 'e82be3ab-1fbc-4410-a099-af6ac6d5dffe': 'cc-paid-no-stock', - '08691170-f6d6-46c7-9f3c-543d7761b64a': 'free-no-trial-loggedin-today', - - // PEP segments - '6cb0d58c-3a65-47e2-b459-c52bb158d5b6': 'lightroom-web-usage', - 'caa3de84-6336-4fa8-8db2-240fc88106cc': 'photoshop-signup-source', - 'ef82408e-1bab-4518-b655-a88981515d6b': 'photoshop-web-usage', - '5c6a4bb8-a2f3-4202-8cca-f5e918b969dc': 'firefly-signup-source', - '20106303-e88c-4b15-93e5-f6a1c3215a12': 'firefly-web-usage', - '3df0b0b0-d06e-4fcc-986e-cc97f54d04d8': 'acrobat-web-usage', - - // Express segments - '2a537e84-b35f-4158-8935-170c22b8ae87': 'express-entitled', - 'eb0dcb78-3e56-4b10-89f9-51831f2cc37f': 'express-pep', -}; - -export const getEntitlementMap = async () => { - const { env, consumerEntitlements } = getConfig(); - if (env?.name === 'prod') return { ...consumerEntitlements, ...ENTITLEMENT_MAP }; - const { default: STAGE_ENTITLEMENTS } = await import('./stage-entitlements.js'); - return { ...consumerEntitlements, ...STAGE_ENTITLEMENTS }; -}; - -const getEntitlements = async (data) => { - const entitlementMap = await getEntitlementMap(); - - return data.flatMap((destination) => { - const ents = destination.segments?.flatMap((segment) => { - const entMatch = entitlementMap[segment.id]; - return entMatch ? [entMatch] : []; - }); - - return ents || []; - }); -}; - -export default function init(data) { - return getEntitlements(data); -} diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index df0744662b..c909648a39 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -2,7 +2,6 @@ /* eslint-disable no-console */ import { createTag, getConfig, loadLink, loadScript, localizeLink } from '../../utils/utils.js'; -import { getEntitlementMap } from './entitlements.js'; /* c8 ignore start */ const PHONE_SIZE = window.screen.width < 550 || window.screen.height < 550; @@ -66,6 +65,14 @@ export const normalizePath = (p, localize = true) => { return path; } + if (path.includes('main--federal--adobecom')) { + const { origin } = new URL(window.location); + if (origin.includes('.hlx.live')) path = path.replace('.hlx.live', '.hlx.page'); + else if (origin.includes('stage.adobe.com')) path = path.replace('main--federal--adobecom.hlx.page', 'www.stage.adobe.com'); + else if (origin.includes('adobe.com')) path = path.replace('main--federal--adobecom.hlx.page', 'www.adobe.com'); + return path; + } + const config = getConfig(); if (path.startsWith(config.codeRoot) @@ -702,6 +709,36 @@ export function buildVariantInfo(variantNames) { }, { allNames: [] }); } +export const getEntitlementMap = async () => { + const config = getConfig(); + if (config.mep?.entitlementMap) return config.mep.entitlementMap; + const sheet = config.env?.name === 'prod' ? 'prod' : 'stage'; + const entitlementUrl = `https://main--federal--adobecom.hlx.page/federal/assets/data/mep-entitlement-tags.json?sheet=${sheet}`; + const fetchedData = await fetchData(entitlementUrl, DATA_TYPE.JSON); + if (!fetchedData) return config.consumerEntitlements || {}; + const entitlements = {}; + fetchedData?.data?.forEach((ent) => { + const { id, tagname } = ent; + entitlements[id] = tagname; + }); + config.mep ??= {}; + config.mep.entitlementMap = { ...config.consumerEntitlements, ...entitlements }; + return config.mep.entitlementMap; +}; + +export const getEntitlements = async (data) => { + const entitlementMap = await getEntitlementMap(); + + return data.flatMap((destination) => { + const ents = destination.segments?.flatMap((segment) => { + const entMatch = entitlementMap[segment.id]; + return entMatch ? [entMatch] : []; + }); + + return ents || []; + }); +}; + async function getPersonalizationVariant(manifestPath, variantNames = [], variantLabel = null) { const config = getConfig(); if (config.mep?.variantOverride?.[manifestPath]) { diff --git a/libs/martech/martech.js b/libs/martech/martech.js index 0aa10ac41f..74df28252c 100644 --- a/libs/martech/martech.js +++ b/libs/martech/martech.js @@ -152,8 +152,8 @@ export const getTargetPersonalization = async () => { const setupEntitlementCallback = () => { const setEntitlements = async (destinations) => { - const { default: parseEntitlements } = await import('../features/personalization/entitlements.js'); - return parseEntitlements(destinations); + const { getEntitlements } = await import('../features/personalization/personalization.js'); + return getEntitlements(destinations); }; const getEntitlements = (resolve) => { @@ -173,7 +173,7 @@ const setupEntitlementCallback = () => { getEntitlements(resolveEnt); loadLink( - `${miloLibs || codeRoot}/features/personalization/entitlements.js`, + `${miloLibs || codeRoot}/features/personalization/personalization.js`, { as: 'script', rel: 'modulepreload' }, ); }; From 0a357381e5472632fdb1a818c7e988c5b59b8ae1 Mon Sep 17 00:00:00 2001 From: vgoodric Date: Tue, 15 Oct 2024 13:35:19 -0600 Subject: [PATCH 02/12] update library --- libs/blocks/library-config/library-config.js | 4 +-- .../library-config/lists/personalization.js | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/libs/blocks/library-config/library-config.js b/libs/blocks/library-config/library-config.js index 394ec5a9b7..7654d4cbbe 100644 --- a/libs/blocks/library-config/library-config.js +++ b/libs/blocks/library-config/library-config.js @@ -103,7 +103,7 @@ async function loadList(type, content, list) { case 'assets': loadAssets(content, list); break; - case 'personalization_tags': + case 'MEP_personalization': loadPersonalization(content, list); break; default: @@ -153,7 +153,7 @@ async function combineLibraries(base, supplied) { blocks: base.blocks.data, templates: base.templates?.data, icons: base.icons?.data, - personalization_tags: base.personalization?.data, + MEP_personalization: base.personalization?.data, placeholders: base.placeholders?.data, }; diff --git a/libs/blocks/library-config/lists/personalization.js b/libs/blocks/library-config/lists/personalization.js index 1d6c12f824..b9768d580b 100644 --- a/libs/blocks/library-config/lists/personalization.js +++ b/libs/blocks/library-config/lists/personalization.js @@ -1,23 +1,24 @@ import { createTag } from '../../../utils/utils.js'; import createCopy from '../library-utils.js'; -const fetchTags = async (path) => { - const resp = await fetch(path); - if (!resp.ok) return []; - const json = await resp.json(); - return json.data || []; -}; - -const categorize = (tagData) => tagData +const categorize = (tagData, category) => tagData .reduce((tags, tag) => { - tags[tag.category] ??= []; - tags[tag.category].push({ + const tagCategory = tag.category || category; + tags[tagCategory] ??= []; + tags[tagCategory].push({ tagname: tag.tagname, description: tag.description, }); return tags; }, {}); +const fetchTags = async (path, category) => { + const resp = await fetch(path); + if (!resp.ok) return []; + const json = await resp.json(); + return categorize(json.data, category); +}; + const getCopyBtn = (tagName) => { const copy = createTag('button', { class: 'copy' }); copy.id = `${tagName}-tag-copy`; @@ -32,8 +33,15 @@ const getCopyBtn = (tagName) => { }; export default async function loadPersonalization(content, list) { - const tagData = await fetchTags(content[0].path); - const tagsObj = categorize(tagData); + let tagsObj = {}; + for (const item of content) { + const { category, path } = item; + tagsObj = { + ...tagsObj, + ...await fetchTags(path, category), + }; + } + list.textContent = ''; Object.entries(tagsObj).forEach(([category, tags]) => { From a335fcb3df856784c08bfd8fb6edd439203bbf30 Mon Sep 17 00:00:00 2001 From: vgoodric Date: Tue, 15 Oct 2024 17:04:13 -0600 Subject: [PATCH 03/12] require full hostname match --- libs/features/personalization/personalization.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index c909648a39..b578f32c89 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -66,10 +66,12 @@ export const normalizePath = (p, localize = true) => { } if (path.includes('main--federal--adobecom')) { - const { origin } = new URL(window.location); - if (origin.includes('.hlx.live')) path = path.replace('.hlx.live', '.hlx.page'); - else if (origin.includes('stage.adobe.com')) path = path.replace('main--federal--adobecom.hlx.page', 'www.stage.adobe.com'); - else if (origin.includes('adobe.com')) path = path.replace('main--federal--adobecom.hlx.page', 'www.adobe.com'); + const subDomains = ['www', 'milo', 'blog', 'business']; + const prodDomains = subDomains.map((sub) => `${sub}.adobe.com`); + const stageDomains = subDomains.map((sub) => `${sub}.stage.adobe.com`); + const { hostname } = new URL(window.location); + if (prodDomains.includes(hostname)) path = path.replace('main--federal--adobecom.hlx.page', 'www.adobe.com'); + else if (stageDomains.includes(hostname)) path = path.replace('main--federal--adobecom.hlx.page', 'www.stage.adobe.com'); return path; } From 63bed0543d6f4aa949cb6ff4078019f26604d0a9 Mon Sep 17 00:00:00 2001 From: vgoodric Date: Tue, 15 Oct 2024 17:55:49 -0600 Subject: [PATCH 04/12] update reference for unit test --- test/features/personalization/entitlements.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/features/personalization/entitlements.test.js b/test/features/personalization/entitlements.test.js index 990a7f5fac..848752977b 100644 --- a/test/features/personalization/entitlements.test.js +++ b/test/features/personalization/entitlements.test.js @@ -1,6 +1,6 @@ import { expect } from '@esm-bundle/chai'; import { getConfig } from '../../../libs/utils/utils.js'; -import getEntitlements from '../../../libs/features/personalization/entitlements.js'; +import getEntitlements from '../../../libs/features/personalization/personalization.js'; describe('entitlements', () => { it('Should return any entitlements that match the id', async () => { From e30a2f0ed3fce3194938f24dbfb01fb60958d4f0 Mon Sep 17 00:00:00 2001 From: vgoodric Date: Wed, 16 Oct 2024 16:05:25 -0600 Subject: [PATCH 05/12] switch to use config instead of domain list and stub response in unit test --- .../personalization/personalization.js | 17 ++- .../personalization/entitlements.test.js | 102 +++++++++++------- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index b578f32c89..412a0b9000 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -65,18 +65,15 @@ export const normalizePath = (p, localize = true) => { return path; } - if (path.includes('main--federal--adobecom')) { - const subDomains = ['www', 'milo', 'blog', 'business']; - const prodDomains = subDomains.map((sub) => `${sub}.adobe.com`); - const stageDomains = subDomains.map((sub) => `${sub}.stage.adobe.com`); + const config = getConfig(); + if (path.startsWith('https://www.adobe.com/federal/')) { const { hostname } = new URL(window.location); - if (prodDomains.includes(hostname)) path = path.replace('main--federal--adobecom.hlx.page', 'www.adobe.com'); - else if (stageDomains.includes(hostname)) path = path.replace('main--federal--adobecom.hlx.page', 'www.stage.adobe.com'); - return path; + if (config.env?.name === 'prod') { + return path.replace('www.adobe.com', hostname); + } + return path.replace('www.adobe.com', 'www.stage.adobe.com'); } - const config = getConfig(); - if (path.startsWith(config.codeRoot) || path.includes('.hlx.') || path.includes('.adobe.')) { @@ -715,7 +712,7 @@ export const getEntitlementMap = async () => { const config = getConfig(); if (config.mep?.entitlementMap) return config.mep.entitlementMap; const sheet = config.env?.name === 'prod' ? 'prod' : 'stage'; - const entitlementUrl = `https://main--federal--adobecom.hlx.page/federal/assets/data/mep-entitlement-tags.json?sheet=${sheet}`; + const entitlementUrl = `https://www.adobe.com/federal/assets/data/mep-entitlement-tags.json?sheet=${sheet}`; const fetchedData = await fetchData(entitlementUrl, DATA_TYPE.JSON); if (!fetchedData) return config.consumerEntitlements || {}; const entitlements = {}; diff --git a/test/features/personalization/entitlements.test.js b/test/features/personalization/entitlements.test.js index 848752977b..de6184c944 100644 --- a/test/features/personalization/entitlements.test.js +++ b/test/features/personalization/entitlements.test.js @@ -1,12 +1,49 @@ import { expect } from '@esm-bundle/chai'; +import { stub } from 'sinon'; import { getConfig } from '../../../libs/utils/utils.js'; -import getEntitlements from '../../../libs/features/personalization/personalization.js'; +import { getEntitlements } from '../../../libs/features/personalization/personalization.js'; + +const config = getConfig(); +config.env = { name: 'prod' }; +config.mep = {}; + +const getFetchPromise = (data, type = 'json') => new Promise((resolve) => { + resolve({ + ok: true, + [type]: () => data, + }); +}); + +const setFetchResponse = () => { + const response = { + data: [ + { + tagname: 'photoshop-any', + id: 'photoshop-guid-id', + }, + { + tagname: 'illustrator-any', + id: 'illustrator-guid-id', + }, + { + tagname: 'indesign-any', + id: 'indesign-guid-id', + }, + { + tagname: 'after-effects-any', + id: 'after-effects-guid-id', + }, + ], + }; + window.fetch = stub().returns(getFetchPromise(response, 'json')); +}; +setFetchResponse(); describe('entitlements', () => { + beforeEach(() => { + config.mep.entitlementMap = undefined; + }); it('Should return any entitlements that match the id', async () => { - const config = getConfig(); - config.env = { name: 'prod' }; - const destinations = [ { segments: [ @@ -15,99 +52,90 @@ describe('entitlements', () => { namespace: 'ups', }, { - id: 'e7650448-268b-4a0d-9795-05f604d7e42f', + id: 'photoshop-guid-id', namespace: 'ups', }, { - id: '8da44606-9841-43d0-af72-86d5a9d3bba0', + id: 'illustrator-guid-id', namespace: 'ups', }, ], }, ]; - const expectedEntitlements = ['lightroom-any', 'cc-photo']; + const expectedEntitlements = ['photoshop-any', 'illustrator-any']; const entitlements = await getEntitlements(destinations); expect(entitlements).to.deep.equal(expectedEntitlements); }); - it('Should return any stage entitlements that match the id', async () => { - const config = getConfig(); - config.env = { name: 'stage' }; - + it('Should not return any entitlements if there is no match', async () => { const destinations = [ { segments: [ { - id: '09bc4ba3-ebed-4d05-812d-a1fb1a7e82ae', - namespace: 'ups', - }, - { - id: '11111111-aaaa-bbbb-6666-cccccccccccc', + id: 'x1111111-aaaa-bbbb-6666-cccccccccccc', namespace: 'ups', }, { - id: '73c3406b-32a2-4465-abf3-2d415b9b1f4f', + id: 'y2222222-xxxx-bbbb-7777-cccccccccccc', namespace: 'ups', }, ], }, ]; - const expectedEntitlements = ['indesign-any', 'after-effects-any']; + const expectedEntitlements = []; const entitlements = await getEntitlements(destinations); expect(entitlements).to.deep.equal(expectedEntitlements); }); - it('Should not return any entitlements if there is no match', async () => { - const config = getConfig(); - config.env = { name: 'prod' }; - + it('Should be able to use consumer defined entitlements in the config', async () => { + config.consumerEntitlements = { 'consumer-defined-entitlement': 'consumer-defined' }; const destinations = [ { segments: [ { - id: 'x1111111-aaaa-bbbb-6666-cccccccccccc', + id: 'photoshop-guid-id', namespace: 'ups', }, { - id: 'y2222222-xxxx-bbbb-7777-cccccccccccc', + id: '11111111-aaaa-bbbb-6666-cccccccccccc', + namespace: 'ups', + }, + { + id: 'consumer-defined-entitlement', namespace: 'ups', }, ], }, ]; - const expectedEntitlements = []; + const expectedEntitlements = ['photoshop-any', 'consumer-defined']; const entitlements = await getEntitlements(destinations); expect(entitlements).to.deep.equal(expectedEntitlements); }); - it('Should be able to use consumer defined entitlements in the config', async () => { - const config = getConfig(); - config.consumerEntitlements = { 'consumer-defined-entitlement': 'consumer-defined' }; - config.env = { name: 'prod' }; - + it('Should return previously retrieved entitlements map if available', async () => { + config.mep.entitlementMap = { + 'photoshop-guid-id2': 'photoshop-any', + 'illustrator-guid-id2': 'illustrator-any', + }; const destinations = [ { segments: [ { - id: 'e7650448-268b-4a0d-9795-05f604d7e42f', + id: 'photoshop-guid-id2', namespace: 'ups', }, { - id: '11111111-aaaa-bbbb-6666-cccccccccccc', - namespace: 'ups', - }, - { - id: 'consumer-defined-entitlement', + id: 'illustrator-guid-id2', namespace: 'ups', }, ], }, ]; - const expectedEntitlements = ['lightroom-any', 'consumer-defined']; + const expectedEntitlements = ['photoshop-any', 'illustrator-any']; const entitlements = await getEntitlements(destinations); expect(entitlements).to.deep.equal(expectedEntitlements); }); From eefbe756ba2b68c70c92258d04c4320a178be5cc Mon Sep 17 00:00:00 2001 From: vgoodric Date: Wed, 16 Oct 2024 16:39:47 -0600 Subject: [PATCH 06/12] update fetch to 2 --- test/features/personalization/pageFilter.test.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/features/personalization/pageFilter.test.js b/test/features/personalization/pageFilter.test.js index 0a08e45481..150e20e33d 100644 --- a/test/features/personalization/pageFilter.test.js +++ b/test/features/personalization/pageFilter.test.js @@ -6,11 +6,10 @@ import { init } from '../../../libs/features/personalization/personalization.js' import mepSettings from './mepSettings.js'; document.body.innerHTML = await readFile({ path: './mocks/personalization.html' }); +const config = getConfig(); +config.env = { name: 'prod' }; it('pageFilter should exclude page if it is not a match', async () => { - const config = getConfig(); - config.env = { name: 'prod' }; - let manifestJson = await readFile({ path: './mocks/manifestPageFilterExclude.json' }); manifestJson = JSON.parse(manifestJson); const replacePageHtml = await readFile({ path: './mocks/fragments/replacePage.plain.html' }); @@ -24,7 +23,7 @@ it('pageFilter should exclude page if it is not a match', async () => { }); }), ); - window.fetch.onCall(1).returns( + window.fetch.onCall(2).returns( new Promise((resolve) => { resolve({ ok: true, @@ -44,9 +43,6 @@ it('pageFilter should exclude page if it is not a match', async () => { }); it('pageFilter should include page if it is a match', async () => { - const config = getConfig(); - config.env = { name: 'prod' }; - let manifestJson = await readFile({ path: './mocks/manifestPageFilterInclude.json' }); manifestJson = JSON.parse(manifestJson); const replacePageHtml = await readFile({ path: './mocks/fragments/replacePage.plain.html' }); @@ -60,7 +56,7 @@ it('pageFilter should include page if it is a match', async () => { }); }), ); - window.fetch.onCall(1).returns( + window.fetch.onCall(2).returns( new Promise((resolve) => { resolve({ ok: true, From 7508167a1a07fa52bc79ba1edab44231e1937963 Mon Sep 17 00:00:00 2001 From: vgoodric Date: Wed, 16 Oct 2024 16:43:27 -0600 Subject: [PATCH 07/12] updating another fetch to 2 --- test/features/personalization/replacePage.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/features/personalization/replacePage.test.js b/test/features/personalization/replacePage.test.js index 3ea70387f5..d05a09f615 100644 --- a/test/features/personalization/replacePage.test.js +++ b/test/features/personalization/replacePage.test.js @@ -24,7 +24,7 @@ it('replacePage should replace all of the main block', async () => { }); }), ); - window.fetch.onCall(1).returns( + window.fetch.onCall(2).returns( new Promise((resolve) => { resolve({ ok: true, From 76975b6079c719d7cb9610d18ba3d70609f175fa Mon Sep 17 00:00:00 2001 From: vgoodric Date: Thu, 17 Oct 2024 13:11:32 -0600 Subject: [PATCH 08/12] restore normalizePath to use preview domains on preview links --- libs/features/personalization/personalization.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index 412a0b9000..d4a017665e 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -67,11 +67,13 @@ export const normalizePath = (p, localize = true) => { const config = getConfig(); if (path.startsWith('https://www.adobe.com/federal/')) { + const subDomains = ['www', 'milo', 'business', 'blog']; + const stageDomains = subDomains.map((sub) => `${sub}.stage.adobe.com`); const { hostname } = new URL(window.location); - if (config.env?.name === 'prod') { + if (config.env?.name === 'prod' || stageDomains.includes(hostname)) { return path.replace('www.adobe.com', hostname); } - return path.replace('www.adobe.com', 'www.stage.adobe.com'); + return path.replace('www.adobe.com', 'main--federal--adobecom.hlx.page'); } if (path.startsWith(config.codeRoot) From e571daa017c1e98d7fd5bdb22ef8b8c494d0dcbc Mon Sep 17 00:00:00 2001 From: vgoodric Date: Thu, 17 Oct 2024 13:29:01 -0600 Subject: [PATCH 09/12] preload segment list json --- libs/features/personalization/personalization.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index d4a017665e..baa92afb09 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -710,11 +710,15 @@ export function buildVariantInfo(variantNames) { }, { allNames: [] }); } +const getXLGListURL = (config) => { + const sheet = config.env?.name === 'prod' ? 'prod' : 'stage'; + return `https://www.adobe.com/federal/assets/data/mep-entitlement-tags.json?sheet=${sheet}`; +}; + export const getEntitlementMap = async () => { const config = getConfig(); if (config.mep?.entitlementMap) return config.mep.entitlementMap; - const sheet = config.env?.name === 'prod' ? 'prod' : 'stage'; - const entitlementUrl = `https://www.adobe.com/federal/assets/data/mep-entitlement-tags.json?sheet=${sheet}`; + const entitlementUrl = getXLGListURL(config); const fetchedData = await fetchData(entitlementUrl, DATA_TYPE.JSON); if (!fetchedData) return config.consumerEntitlements || {}; const entitlements = {}; @@ -1140,6 +1144,7 @@ export async function init(enablements = {}) { const normalizedURL = normalizePath(manifest.manifestPath); loadLink(normalizedURL, { as: 'fetch', crossorigin: 'anonymous', rel: 'preload' }); }); + if (pzn) loadLink(getXLGListURL(config), { as: 'fetch', crossorigin: 'anonymous', rel: 'preload' }); } if (target === true) manifests = manifests.concat(await callMartech(config)); From 91124465faef336e2c9233f0848bf814a630dcd6 Mon Sep 17 00:00:00 2001 From: vgoodric Date: Thu, 17 Oct 2024 14:02:00 -0600 Subject: [PATCH 10/12] use getFederatedUrl instead --- libs/features/personalization/personalization.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index baa92afb09..ff2d0e25c8 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -67,13 +67,10 @@ export const normalizePath = (p, localize = true) => { const config = getConfig(); if (path.startsWith('https://www.adobe.com/federal/')) { - const subDomains = ['www', 'milo', 'business', 'blog']; - const stageDomains = subDomains.map((sub) => `${sub}.stage.adobe.com`); - const { hostname } = new URL(window.location); - if (config.env?.name === 'prod' || stageDomains.includes(hostname)) { - return path.replace('www.adobe.com', hostname); - } - return path.replace('www.adobe.com', 'main--federal--adobecom.hlx.page'); + import('../../utils/federated.js').then(({ getFederatedUrl }) => { + path = getFederatedUrl(path); + }); + return path; } if (path.startsWith(config.codeRoot) From 0107cc7272d905d7d9f29fb2cf9e01a6a05417b9 Mon Sep 17 00:00:00 2001 From: vgoodric Date: Thu, 17 Oct 2024 14:09:39 -0600 Subject: [PATCH 11/12] import at top so we don't have to make normalizePath async --- libs/features/personalization/personalization.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index ff2d0e25c8..953d467019 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -2,6 +2,7 @@ /* eslint-disable no-console */ import { createTag, getConfig, loadLink, loadScript, localizeLink } from '../../utils/utils.js'; +import { getFederatedUrl } from '../../utils/federated.js'; /* c8 ignore start */ const PHONE_SIZE = window.screen.width < 550 || window.screen.height < 550; @@ -67,10 +68,7 @@ export const normalizePath = (p, localize = true) => { const config = getConfig(); if (path.startsWith('https://www.adobe.com/federal/')) { - import('../../utils/federated.js').then(({ getFederatedUrl }) => { - path = getFederatedUrl(path); - }); - return path; + return getFederatedUrl(path); } if (path.startsWith(config.codeRoot) From 672da4c9a1ab68c41afa9279518c76a94bb71455 Mon Sep 17 00:00:00 2001 From: Vivian A Goodrich <101133187+vgoodric@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:22:44 -0600 Subject: [PATCH 12/12] MWPW-148129 [MILO][MEP][GNAV] Able to use select by url feature with federated link (#3064) * add federated link function to registerInBlockActions * add to unit test * add unit test coverage --- .../personalization/personalization.js | 4 +- test/features/personalization/actions.test.js | 58 ++++++++++++++----- .../mocks/actions/manifestCustomAction.json | 14 ++++- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/libs/features/personalization/personalization.js b/libs/features/personalization/personalization.js index 953d467019..d32df9632c 100644 --- a/libs/features/personalization/personalization.js +++ b/libs/features/personalization/personalization.js @@ -343,6 +343,8 @@ function registerInBlockActions(command) { blockSelector = blockAndSelector.slice(1).join(' '); command.selector = blockSelector; if (getSelectorType(blockSelector) === 'fragment') { + if (blockSelector.includes('/federal/')) blockSelector = getFederatedUrl(blockSelector); + if (command.content.includes('/federal/')) command.content = getFederatedUrl(command.content); config.mep.inBlock[blockName].fragments ??= {}; const { fragments } = config.mep.inBlock[blockName]; delete command.selector; @@ -450,7 +452,7 @@ function getSelectedElements(sel, rootEl, forceRootEl) { ); return { els: fragments, modifiers: [FLAGS.all, FLAGS.includeFragments] }; } catch (e) { - /* c8 ignore next */ + /* c8 ignore next 2 */ return { els: [], modifiers: [] }; } } diff --git a/test/features/personalization/actions.test.js b/test/features/personalization/actions.test.js index d0a7d0dc83..fad860915b 100644 --- a/test/features/personalization/actions.test.js +++ b/test/features/personalization/actions.test.js @@ -3,7 +3,7 @@ import { readFile } from '@web/test-runner-commands'; import { stub } from 'sinon'; import { getConfig, loadBlock } from '../../../libs/utils/utils.js'; import initFragments from '../../../libs/blocks/fragment/fragment.js'; -import { init, handleFragmentCommand } from '../../../libs/features/personalization/personalization.js'; +import { init, handleCommands } from '../../../libs/features/personalization/personalization.js'; import mepSettings from './mepSettings.js'; document.head.innerHTML = await readFile({ path: './mocks/metadata.html' }); @@ -151,7 +151,6 @@ describe('prependToSection action', async () => { describe('appendToSection action', async () => { it('appendToSection should add fragment to end of section', async () => { - config.mep = { handleFragmentCommand }; let manifestJson = await readFile({ path: './mocks/actions/manifestAppendToSection.json' }); manifestJson = JSON.parse(manifestJson); @@ -167,6 +166,24 @@ describe('appendToSection action', async () => { }); }); +describe('addHash', async () => { + it('if forceInline is true, addHash is called', async () => { + config.mep.commands = [{ + action: 'replace', + content: '/new-fragment', + selector: 'h1', + }]; + const rootEl = document.createElement('div'); + handleCommands(config.mep.commands, rootEl, true, true); + console.log(config.mep.commands[0].content); + expect(config.mep.commands[0].content).to.equal('/new-fragment#_inline'); + config.mep.commands[0].content = 'https://main--cc--adobecom.hlx.page/cc/fragments/new-fragment'; + handleCommands(config.mep.commands, rootEl, true, true); + console.log(config.mep.commands[0].content); + expect(config.mep.commands[0].content).to.equal('https://main--cc--adobecom.hlx.page/cc/fragments/new-fragment#_inline'); + }); +}); + describe('replace action with html/text instead of fragment', () => { it('should replace marquee content', async () => { document.body.innerHTML = await readFile({ path: './mocks/personalization.html' }); @@ -219,20 +236,25 @@ describe('remove action', () => { let manifestJson = await readFile({ path: './mocks/actions/manifestRemove.json' }); manifestJson = JSON.parse(manifestJson); setFetchResponse(manifestJson); + delete config.mep; + + expect(document.querySelector('.z-pattern')).to.not.be.null; + await init({ + mepParam: '', + mepHighlight: false, + mepButton: false, + pzn: '/path/to/manifest.json', + promo: false, + target: false, + }); - setTimeout(async () => { - expect(document.querySelector('.z-pattern')).to.not.be.null; - mepSettings.mepButton = false; - await init(mepSettings); - - expect(document.querySelector('.z-pattern')).to.not.be.null; - expect(document.querySelector('.z-pattern').dataset.removedManifestId).to.not.be.null; + expect(document.querySelector('.z-pattern')).to.not.be.null; + expect(document.querySelector('.z-pattern').dataset.removedManifestId).to.equal('manifest.json'); - const removeMeFrag = document.querySelector('a[href="/fragments/removeme"]'); - await initFragments(removeMeFrag); - expect(document.querySelector('a[href="/fragments/removeme"]')).to.not.be.null; - expect(document.querySelector('a[href="/fragments/removeme"]').dataset.removedManifestId).to.not.be.null; - }, 50); + const removeMeFrag = document.querySelector('a[href="/fragments/removeme"]'); + await initFragments(removeMeFrag); + expect(document.querySelector('a[href="/fragments/removeme"]')).to.not.be.null; + expect(document.querySelector('a[href="/fragments/removeme"]').dataset.removedManifestId).to.not.be.null; }); }); @@ -322,6 +344,14 @@ describe('custom actions', async () => { pageFilter: '', selectorType: 'in-block:', }, + 'https://main--federal--adobecom.hlx.page/federal/fragments/new-sub-menu': { + action: 'replace', + pageFilter: '', + content: 'https://main--federal--adobecom.hlx.page/federal/fragments/even-more-new-sub-menu', + selectorType: 'in-block:', + manifestId: false, + targetManifestId: false, + }, }, }, }); diff --git a/test/features/personalization/mocks/actions/manifestCustomAction.json b/test/features/personalization/mocks/actions/manifestCustomAction.json index 1de7092bbb..ef510666fa 100644 --- a/test/features/personalization/mocks/actions/manifestCustomAction.json +++ b/test/features/personalization/mocks/actions/manifestCustomAction.json @@ -35,7 +35,8 @@ "firefox": "", "android": "", "ios": "" - }, { + }, + { "action": "replace", "selector": "in-block:my-block /fragments/new-sub-menu", "page filter (optional)": "", @@ -45,6 +46,17 @@ "firefox": "", "android": "", "ios": "" + }, + { + "action": "replace", + "selector": "in-block:my-block /federal/fragments/new-sub-menu", + "page filter (optional)": "", + "param-newoffer=123": "", + "chrome": "/federal/fragments/even-more-new-sub-menu", + "target-var1": "/federal/fragments/even-more-new-sub-menu", + "firefox": "", + "android": "", + "ios": "" } ], ":type": "sheet"