From 1b25687f756cc411fb9c80b5f6052a595d07e7e7 Mon Sep 17 00:00:00 2001 From: Shamiul Mowla Date: Mon, 11 Nov 2024 14:05:27 -0500 Subject: [PATCH 1/2] Click Collection Configuration Validation. --- .../ActivityCollector/configValidators.js | 13 +- src/components/ActivityCollector/index.js | 7 + .../validateClickCollectionConfig.js | 36 +++++ .../functional/specs/Data Collector/C81184.js | 135 ++++++++++++++++++ .../validateClickCollectionConfig.spec.js | 93 ++++++++++++ 5 files changed, 280 insertions(+), 4 deletions(-) create mode 100644 src/components/ActivityCollector/validateClickCollectionConfig.js create mode 100644 test/functional/specs/Data Collector/C81184.js create mode 100644 test/unit/specs/components/ActivityCollector/validateClickCollectionConfig.spec.js diff --git a/src/components/ActivityCollector/configValidators.js b/src/components/ActivityCollector/configValidators.js index 7f584d89b..dba99411e 100644 --- a/src/components/ActivityCollector/configValidators.js +++ b/src/components/ActivityCollector/configValidators.js @@ -17,13 +17,14 @@ import { string, } from "../../utils/validation/index.js"; +const DEFAULT_DOWNLOAD_QUALIFIER = + "\\.(exe|zip|wav|mp3|mov|mpg|avi|wmv|pdf|doc|docx|xls|xlsx|ppt|pptx)$"; + export const downloadLinkQualifier = string() .regexp() - .default( - "\\.(exe|zip|wav|mp3|mov|mpg|avi|wmv|pdf|doc|docx|xls|xlsx|ppt|pptx)$", - ); + .default(DEFAULT_DOWNLOAD_QUALIFIER); -export default objectOf({ +const validators = objectOf({ clickCollectionEnabled: boolean().default(true), clickCollection: objectOf({ internalLinkEnabled: boolean().default(true), @@ -45,3 +46,7 @@ export default objectOf({ 'The field "onBeforeLinkClickSend" has been deprecated. Use "clickCollection.filterClickDetails" instead.', ), }); + +// Export both the validators and the default qualifier +export { DEFAULT_DOWNLOAD_QUALIFIER }; +export default validators; diff --git a/src/components/ActivityCollector/index.js b/src/components/ActivityCollector/index.js index 852f1759c..a2133681a 100644 --- a/src/components/ActivityCollector/index.js +++ b/src/components/ActivityCollector/index.js @@ -17,6 +17,7 @@ import createRecallAndInjectClickedElementProperties from "./createRecallAndInje import createGetClickedElementProperties from "./createGetClickedElementProperties.js"; import createClickActivityStorage from "./createClickActivityStorage.js"; import createStorePageViewProperties from "./createStorePageViewProperties.js"; +import validateClickCollectionConfig from "./validateClickCollectionConfig.js"; import getLinkName from "./getLinkName.js"; import getLinkRegion from "./getLinkRegion.js"; import getAbsoluteUrlFromAnchorElement from "./utils/dom/getAbsoluteUrlFromAnchorElement.js"; @@ -55,23 +56,29 @@ const createActivityCollector = ({ handleError, logger, }) => { + validateClickCollectionConfig(config, logger); + const clickCollection = config.clickCollection; if (!clickActivityStorage) { initClickActivityStorage(config); } + const injectClickedElementProperties = createInjectClickedElementProperties({ config, logger, clickActivityStorage, getClickedElementProperties, }); + const recallAndInjectClickedElementProperties = createRecallAndInjectClickedElementProperties({ clickActivityStorage, }); + const storePageViewProperties = createStorePageViewProperties({ clickActivityStorage, }); + return { lifecycle: { onComponentsRegistered(tools) { diff --git a/src/components/ActivityCollector/validateClickCollectionConfig.js b/src/components/ActivityCollector/validateClickCollectionConfig.js new file mode 100644 index 000000000..e8b153207 --- /dev/null +++ b/src/components/ActivityCollector/validateClickCollectionConfig.js @@ -0,0 +1,36 @@ +// src/components/ActivityCollector/validateClickCollectionConfig.js +/* +Copyright 2024 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +import { DEFAULT_DOWNLOAD_QUALIFIER } from "./configValidators.js"; + +export default (config, logger) => { + const { + clickCollectionEnabled, + onBeforeLinkClickSend, + downloadLinkQualifier: dlq, + } = config; + + if (clickCollectionEnabled === false) { + if (onBeforeLinkClickSend) { + logger.warn( + "The 'onBeforeLinkClickSend' configuration was provided but will be ignored because clickCollectionEnabled is false.", + ); + } + + if (dlq && dlq !== DEFAULT_DOWNLOAD_QUALIFIER) { + logger.warn( + "The 'downloadLinkQualifier' configuration was provided but will be ignored because clickCollectionEnabled is false.", + ); + } + } +}; diff --git a/test/functional/specs/Data Collector/C81184.js b/test/functional/specs/Data Collector/C81184.js new file mode 100644 index 000000000..574fb568f --- /dev/null +++ b/test/functional/specs/Data Collector/C81184.js @@ -0,0 +1,135 @@ +// test/functional/specs/Data Collector/C81184.js +/* +Copyright 2023 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { t, ClientFunction } from "testcafe"; +import createFixture from "../../helpers/createFixture/index.js"; +import createConsoleLogger from "../../helpers/consoleLogger/index.js"; +import { + compose, + orgMainConfigMain, + debugEnabled, +} from "../../helpers/constants/configParts/index.js"; +import createAlloyProxy from "../../helpers/createAlloyProxy.js"; +import addHtmlToBody from "../../helpers/dom/addHtmlToBody.js"; + +const alloyMonitorScript = ` +window.__alloyMonitors = window.__alloyMonitors || []; +window.__alloyMonitors.push({ + onInstanceConfigured: function(data) { + window.___getLinkDetails = data.getLinkDetails; + } +});`; + +createFixture({ + title: "C81184: Validate click collection configuration warnings", + monitoringHooksScript: alloyMonitorScript, +}); + +test.meta({ + ID: "C81184", + SEVERITY: "P0", + TEST_RUN: "Regression", +}); + +test("Test C81184: Warns when click collection features configured but disabled", async () => { + const consoleLogger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + + await alloy.configure( + compose(orgMainConfigMain, debugEnabled, { + clickCollectionEnabled: false, + onBeforeLinkClickSend: () => {}, + downloadLinkQualifier: "\\.pdf$", + }), + ); + + await consoleLogger.warn.expectMessageMatching( + /The 'onBeforeLinkClickSend' configuration was provided but will be ignored because clickCollectionEnabled is false/, + ); + + await consoleLogger.warn.expectMessageMatching( + /The 'downloadLinkQualifier' configuration was provided but will be ignored because clickCollectionEnabled is false/, + ); +}); + +test("Test C81184: Does not warn for default downloadLinkQualifier when disabled", async () => { + const consoleLogger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + + await alloy.configure( + compose(orgMainConfigMain, debugEnabled, { + clickCollectionEnabled: false, + }), + ); + + await consoleLogger.warn.expectNoMessageMatching( + /The 'downloadLinkQualifier' configuration was provided/, + ); +}); + +test("Test C81184: Does not warn when clickCollectionEnabled is true", async () => { + const consoleLogger = await createConsoleLogger(); + const alloy = createAlloyProxy(); + + await alloy.configure( + compose(orgMainConfigMain, debugEnabled, { + clickCollectionEnabled: true, + onBeforeLinkClickSend: () => {}, + downloadLinkQualifier: "\\.pdf$", + }), + ); + + await consoleLogger.warn.expectNoMessageMatching( + /The 'onBeforeLinkClickSend' configuration was provided/, + ); + + await consoleLogger.warn.expectNoMessageMatching( + /The 'downloadLinkQualifier' configuration was provided/, + ); +}); + +const getLinkDetails = ClientFunction((selector) => { + const linkElement = document.getElementById(selector); + // eslint-disable-next-line no-underscore-dangle + const result = window.___getLinkDetails(linkElement); + if (!result) { + return result; + } + return { + pageName: result.pageName, + linkName: result.linkName, + linkRegion: result.linkRegion, + linkType: result.linkType, + linkUrl: result.linkUrl, + }; +}); + +test("Test C81184: getLinkDetails works regardless of clickCollectionEnabled", async () => { + const alloy = createAlloyProxy(); + + await alloy.configure( + compose(orgMainConfigMain, debugEnabled, { + clickCollectionEnabled: false, + }), + ); + + await addHtmlToBody( + 'Test Link', + ); + + const result = await getLinkDetails("test-link"); + + await t.expect(result).notEql(undefined); + await t.expect(result.linkName).eql("Test Link"); + await t.expect(result.linkUrl).contains("example.com"); + await t.expect(result.linkType).eql("exit"); +}); diff --git a/test/unit/specs/components/ActivityCollector/validateClickCollectionConfig.spec.js b/test/unit/specs/components/ActivityCollector/validateClickCollectionConfig.spec.js new file mode 100644 index 000000000..cbab9c565 --- /dev/null +++ b/test/unit/specs/components/ActivityCollector/validateClickCollectionConfig.spec.js @@ -0,0 +1,93 @@ +/* +Copyright 2024 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +import validateClickCollectionConfig from "../../../../../src/components/ActivityCollector/validateClickCollectionConfig.js"; +import { DEFAULT_DOWNLOAD_QUALIFIER } from "../../../../../src/components/ActivityCollector/configValidators.js"; + +describe("ActivityCollector::validateClickCollectionConfig", () => { + let logger; + + beforeEach(() => { + logger = jasmine.createSpyObj("logger", ["warn"]); + }); + + it("warns when onBeforeLinkClickSend provided with clickCollectionEnabled false", () => { + const config = { + clickCollectionEnabled: false, + onBeforeLinkClickSend: () => {}, + }; + + validateClickCollectionConfig(config, logger); + + expect(logger.warn).toHaveBeenCalledWith( + "The 'onBeforeLinkClickSend' configuration was provided but will be ignored because clickCollectionEnabled is false.", + ); + }); + + it("warns when custom downloadLinkQualifier provided with clickCollectionEnabled false", () => { + const config = { + clickCollectionEnabled: false, + downloadLinkQualifier: "\\.pdf$", + }; + + validateClickCollectionConfig(config, logger); + + expect(logger.warn).toHaveBeenCalledWith( + "The 'downloadLinkQualifier' configuration was provided but will be ignored because clickCollectionEnabled is false.", + ); + }); + + it("does not warn for default downloadLinkQualifier when disabled", () => { + const config = { + clickCollectionEnabled: false, + downloadLinkQualifier: DEFAULT_DOWNLOAD_QUALIFIER, + }; + + validateClickCollectionConfig(config, logger); + + expect(logger.warn).not.toHaveBeenCalled(); + }); + + it("does not warn when clickCollectionEnabled is true", () => { + const config = { + clickCollectionEnabled: true, + onBeforeLinkClickSend: () => {}, + downloadLinkQualifier: "\\.pdf$", + }; + + validateClickCollectionConfig(config, logger); + + expect(logger.warn).not.toHaveBeenCalled(); + }); + + it("does not warn when no click collection features configured", () => { + const config = { + clickCollectionEnabled: false, + }; + + validateClickCollectionConfig(config, logger); + + expect(logger.warn).not.toHaveBeenCalled(); + }); + + it("handles undefined config values", () => { + const config = { + clickCollectionEnabled: false, + onBeforeLinkClickSend: undefined, + downloadLinkQualifier: undefined, + }; + + validateClickCollectionConfig(config, logger); + + expect(logger.warn).not.toHaveBeenCalled(); + }); +}); From a3490194713f98678a7c33d7c27e55c416514588 Mon Sep 17 00:00:00 2001 From: Shamiul Mowla Date: Mon, 11 Nov 2024 14:06:03 -0500 Subject: [PATCH 2/2] Click Collection Configuration Validation. --- .../validateClickCollectionConfig.js | 11 +++++++++++ test/functional/specs/Data Collector/C81184.js | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/components/ActivityCollector/validateClickCollectionConfig.js b/src/components/ActivityCollector/validateClickCollectionConfig.js index e8b153207..8c7d29101 100644 --- a/src/components/ActivityCollector/validateClickCollectionConfig.js +++ b/src/components/ActivityCollector/validateClickCollectionConfig.js @@ -1,3 +1,14 @@ +/* +Copyright 2024 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ // src/components/ActivityCollector/validateClickCollectionConfig.js /* Copyright 2024 Adobe. All rights reserved. diff --git a/test/functional/specs/Data Collector/C81184.js b/test/functional/specs/Data Collector/C81184.js index 574fb568f..a45d3986f 100644 --- a/test/functional/specs/Data Collector/C81184.js +++ b/test/functional/specs/Data Collector/C81184.js @@ -1,3 +1,14 @@ +/* +Copyright 2024 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ // test/functional/specs/Data Collector/C81184.js /* Copyright 2023 Adobe. All rights reserved.